Skip to main content

toml/de/parser/
inline_table.rs

1use serde_spanned::Spanned;
2
3use crate::alloc_prelude::*;
4use crate::de::DeString;
5use crate::de::DeTable;
6use crate::de::DeValue;
7use crate::de::parser::array::on_array;
8use crate::de::parser::key::on_key;
9use crate::de::parser::prelude::*;
10use crate::de::parser::value::on_scalar;
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                #[cfg(feature = "debug")]
148                trace(
149                    &format!("table.dotted={}", table.is_dotted()),
150                    anstyle::AnsiColor::Red.on_default(),
151                );
152                #[cfg(feature = "debug")]
153                trace(
154                    &format!("path.is_empty={}", path.is_empty()),
155                    anstyle::AnsiColor::Red.on_default(),
156                );
157                let key_span = get_key_span(&key);
158                errors.report_error(ParseError::new("duplicate key").with_unexpected(key_span));
159            } else {
160                let key_span = get_key_span(&key);
161                match table.entry(key) {
162                    Entry::Vacant(o) => {
163                        o.insert(value);
164                    }
165                    Entry::Occupied(o) => {
166                        let old_span = get_key_span(o.key());
167                        errors.report_error(
168                            ParseError::new("duplicate key")
169                                .with_unexpected(key_span)
170                                .with_context(old_span),
171                        );
172                    }
173                }
174            }
175        }
176    }
177
178    fn close(
179        &mut self,
180        _open_event: &toml_parser::parser::Event,
181        _close_event: &toml_parser::parser::Event,
182        _result: &mut DeTable<'i>,
183    ) {
184        #[cfg(feature = "debug")]
185        let _scope = TraceScope::new("inline_table::close");
186    }
187}
188
189fn descend_path<'a, 'i>(
190    mut table: &'a mut DeTable<'i>,
191    path: &'a [Spanned<DeString<'i>>],
192    dotted: bool,
193    errors: &mut dyn ErrorSink,
194) -> Option<&'a mut DeTable<'i>> {
195    #[cfg(feature = "debug")]
196    let _scope = TraceScope::new("inline_table::descend_path");
197    #[cfg(feature = "debug")]
198    trace(
199        &format!(
200            "path={:?}",
201            path.iter().map(|k| k.get_ref()).collect::<Vec<_>>()
202        ),
203        anstyle::AnsiColor::Blue.on_default(),
204    );
205    for key in path.iter() {
206        #[cfg(feature = "debug")]
207        trace(
208            &format!("path[_]={:?}", key.get_ref()),
209            anstyle::AnsiColor::Blue.on_default(),
210        );
211        table = match table.entry(key.clone()) {
212            Entry::Vacant(entry) => {
213                let mut new_table = DeTable::new();
214                new_table.set_implicit(true);
215                new_table.set_dotted(dotted);
216                new_table.set_inline(true);
217                let value = DeValue::Table(new_table);
218                let value = Spanned::new(key.span(), value);
219                let value = entry.insert(value);
220                value.as_mut().as_table_mut().unwrap()
221            }
222            Entry::Occupied(entry) => {
223                let spanned = entry.into_mut();
224                let old_span = spanned.span();
225                match spanned.as_mut() {
226                    DeValue::Table(sweet_child_of_mine) => {
227                        // Since tables cannot be defined more than once, redefining such tables using a
228                        // [table] header is not allowed. Likewise, using dotted keys to redefine tables
229                        // already defined in [table] form is not allowed.
230                        let mixed_table_types = dotted && !sweet_child_of_mine.is_implicit();
231                        if mixed_table_types {
232                            #[cfg(feature = "debug")]
233                            trace(
234                                &format!("dotted={dotted}"),
235                                anstyle::AnsiColor::Red.on_default(),
236                            );
237                            #[cfg(feature = "debug")]
238                            trace(
239                                &format!(
240                                    "sweet_child_of_mine.is_implicit={}",
241                                    sweet_child_of_mine.is_implicit()
242                                ),
243                                anstyle::AnsiColor::Red.on_default(),
244                            );
245                            let key_span = get_key_span(key);
246                            errors.report_error(
247                                ParseError::new("duplicate key").with_unexpected(key_span),
248                            );
249                            return None;
250                        }
251                        sweet_child_of_mine
252                    }
253                    existing => {
254                        let old_span =
255                            toml_parser::Span::new_unchecked(old_span.start, old_span.end);
256                        let key_span = get_key_span(key);
257                        errors.report_error(
258                            ParseError::new(format!(
259                                "cannot extend value of type {} with a dotted key",
260                                existing.type_str()
261                            ))
262                            .with_unexpected(key_span)
263                            .with_context(old_span),
264                        );
265                        return None;
266                    }
267                }
268            }
269        };
270    }
271    Some(table)
272}
273
274fn get_key_span(key: &Spanned<DeString<'_>>) -> toml_parser::Span {
275    let key_span = key.span();
276    toml_parser::Span::new_unchecked(key_span.start, key_span.end)
277}