toml_edit/parser/
inline_table.rs

1use crate::key::Key;
2use crate::parser::array::on_array;
3use crate::parser::key::on_key;
4use crate::parser::prelude::*;
5use crate::parser::value::on_scalar;
6use crate::repr::Decor;
7use crate::{InlineTable, Item, RawString, Value};
8
9use indexmap::map::Entry;
10
11/// ```bnf
12/// ;; Inline Table
13///
14/// inline-table = inline-table-open inline-table-keyvals inline-table-close
15/// ```
16pub(crate) fn on_inline_table(
17    open_event: &toml_parser::parser::Event,
18    input: &mut Input<'_>,
19    source: toml_parser::Source<'_>,
20    errors: &mut dyn ErrorSink,
21) -> Value {
22    #[cfg(feature = "debug")]
23    let _scope = TraceScope::new("inline_table::on_inline_table");
24    let mut result = InlineTable::new();
25
26    let mut state = State::default();
27    while let Some(event) = input.next_token() {
28        match event.kind() {
29            EventKind::StdTableOpen
30            | EventKind::ArrayTableOpen
31            | EventKind::StdTableClose
32            | EventKind::ArrayClose
33            | EventKind::ArrayTableClose
34            | EventKind::KeySep => {
35                #[cfg(feature = "debug")]
36                trace(
37                    &format!("unexpected {event:?}"),
38                    anstyle::AnsiColor::Red.on_default(),
39                );
40                break;
41            }
42            EventKind::Error => {
43                #[cfg(feature = "debug")]
44                trace(
45                    &format!("unexpected {event:?}"),
46                    anstyle::AnsiColor::Red.on_default(),
47                );
48                continue;
49            }
50            EventKind::SimpleKey => {
51                let (path, key) = on_key(event, input, source, errors);
52                state.capture_key(event, path, key);
53            }
54            EventKind::KeyValSep => {
55                state.finish_key(event);
56            }
57            EventKind::InlineTableOpen => {
58                let value = on_inline_table(event, input, source, errors);
59                state.capture_value(event, value);
60            }
61            EventKind::ArrayOpen => {
62                let value = on_array(event, input, source, errors);
63                state.capture_value(event, value);
64            }
65            EventKind::Scalar => {
66                let value = on_scalar(event, source, errors);
67                state.capture_value(event, value);
68            }
69            EventKind::ValueSep => {
70                state.finish_value(event, &mut result, errors);
71            }
72            EventKind::Whitespace | EventKind::Comment | EventKind::Newline => {
73                state.whitespace(event);
74            }
75            EventKind::InlineTableClose => {
76                state.finish_value(event, &mut result, errors);
77                state.close(open_event, event, &mut result);
78                break;
79            }
80        }
81    }
82
83    Value::InlineTable(result)
84}
85
86#[derive(Default)]
87struct State {
88    current_prefix: Option<toml_parser::Span>,
89    current_key: Option<(Vec<Key>, Key)>,
90    seen_keyval_sep: bool,
91    current_value: Option<Value>,
92    current_suffix: Option<toml_parser::Span>,
93}
94
95impl State {
96    fn whitespace(&mut self, event: &toml_parser::parser::Event) {
97        let decor = if self.is_prefix() {
98            self.current_prefix.get_or_insert(event.span())
99        } else {
100            self.current_suffix.get_or_insert(event.span())
101        };
102        *decor = decor.append(event.span());
103    }
104
105    fn is_prefix(&self) -> bool {
106        if self.seen_keyval_sep {
107            self.current_value.is_none()
108        } else {
109            self.current_key.is_none()
110        }
111    }
112
113    fn capture_key(
114        &mut self,
115        event: &toml_parser::parser::Event,
116        path: Vec<Key>,
117        key: Option<Key>,
118    ) {
119        self.current_prefix
120            .get_or_insert_with(|| event.span().before());
121        if let Some(key) = key {
122            self.current_key = Some((path, key));
123        }
124    }
125
126    fn finish_key(&mut self, event: &toml_parser::parser::Event) {
127        self.seen_keyval_sep = true;
128        if let Some(last_key) = self.current_key.as_mut().map(|(_, k)| k) {
129            let prefix = self
130                .current_prefix
131                .take()
132                .expect("setting a key should set a prefix");
133            let suffix = self
134                .current_suffix
135                .take()
136                .unwrap_or_else(|| event.span().before());
137            let prefix = RawString::with_span(prefix.start()..prefix.end());
138            let suffix = RawString::with_span(suffix.start()..suffix.end());
139            let leaf_decor = Decor::new(prefix, suffix);
140            *last_key.leaf_decor_mut() = leaf_decor;
141        }
142    }
143
144    fn capture_value(&mut self, event: &toml_parser::parser::Event, value: Value) {
145        self.current_prefix
146            .get_or_insert_with(|| event.span().before());
147        self.current_value = Some(value);
148    }
149
150    fn finish_value(
151        &mut self,
152        event: &toml_parser::parser::Event,
153        result: &mut InlineTable,
154        errors: &mut dyn ErrorSink,
155    ) {
156        #[cfg(feature = "debug")]
157        let _scope = TraceScope::new("inline_table::finish_value");
158        self.seen_keyval_sep = false;
159        if let (Some((path, key)), Some(mut value)) =
160            (self.current_key.take(), self.current_value.take())
161        {
162            let prefix = self
163                .current_prefix
164                .take()
165                .expect("setting a value should set a prefix");
166            let suffix = self
167                .current_suffix
168                .take()
169                .unwrap_or_else(|| event.span().before());
170            let Some(table) = descend_path(result, &path, true, errors) else {
171                return;
172            };
173
174            let decor = value.decor_mut();
175            decor.set_prefix(RawString::with_span(prefix.start()..prefix.end()));
176            decor.set_suffix(RawString::with_span(suffix.start()..suffix.end()));
177
178            // "Likewise, using dotted keys to redefine tables already defined in [table] form is not allowed"
179            let mixed_table_types = table.is_dotted() == path.is_empty();
180            if mixed_table_types {
181                let key_span = get_key_span(&key).unwrap_or_else(|| event.span());
182                errors.report_error(ParseError::new("duplicate key").with_unexpected(key_span));
183            } else {
184                let key_span = get_key_span(&key).unwrap_or_else(|| event.span());
185                match table.items.entry(key) {
186                    Entry::Vacant(o) => {
187                        o.insert(Item::Value(value));
188                    }
189                    Entry::Occupied(o) => {
190                        let old_span = get_key_span(o.key()).unwrap_or_else(|| event.span());
191                        errors.report_error(
192                            ParseError::new("duplicate key")
193                                .with_unexpected(key_span)
194                                .with_context(old_span),
195                        );
196                    }
197                }
198            }
199        }
200    }
201
202    fn close(
203        &mut self,
204        open_event: &toml_parser::parser::Event,
205        close_event: &toml_parser::parser::Event,
206        result: &mut InlineTable,
207    ) {
208        #[cfg(feature = "debug")]
209        let _scope = TraceScope::new("inline_table::close");
210        let span = open_event.span().append(close_event.span());
211        let preamble = self
212            .current_prefix
213            .take()
214            .map(|prefix| RawString::with_span(prefix.start()..prefix.end()));
215
216        result.span = Some(span.start()..span.end());
217        if let Some(preamble) = preamble {
218            result.set_preamble(preamble);
219        }
220    }
221}
222
223fn descend_path<'a>(
224    mut table: &'a mut InlineTable,
225    path: &'a [Key],
226    dotted: bool,
227    errors: &mut dyn ErrorSink,
228) -> Option<&'a mut InlineTable> {
229    #[cfg(feature = "debug")]
230    let _scope = TraceScope::new("inline_table::descend_path");
231    #[cfg(feature = "debug")]
232    trace(
233        &format!("key={:?}", path.iter().map(|k| k.get()).collect::<Vec<_>>()),
234        anstyle::AnsiColor::Blue.on_default(),
235    );
236    for key in path.iter() {
237        table = match table.entry_format(key) {
238            crate::InlineEntry::Vacant(entry) => {
239                let mut new_table = InlineTable::new();
240                new_table.span = key.span();
241                new_table.set_implicit(true);
242                new_table.set_dotted(dotted);
243                entry
244                    .insert(Value::InlineTable(new_table))
245                    .as_inline_table_mut()
246                    .unwrap()
247            }
248            crate::InlineEntry::Occupied(entry) => {
249                match entry.into_mut() {
250                    Value::InlineTable(ref mut sweet_child_of_mine) => {
251                        // Since tables cannot be defined more than once, redefining such tables using a
252                        // [table] header is not allowed. Likewise, using dotted keys to redefine tables
253                        // already defined in [table] form is not allowed.
254                        if dotted && !sweet_child_of_mine.is_implicit() {
255                            let key_span = get_key_span(key).expect("all keys have spans");
256                            errors.report_error(
257                                ParseError::new("duplicate key").with_unexpected(key_span),
258                            );
259                            return None;
260                        }
261                        sweet_child_of_mine
262                    }
263                    item => {
264                        let key_span = get_key_span(key).expect("all keys have spans");
265                        errors.report_error(
266                            ParseError::new(format!(
267                                "cannot extend value of type {} with a dotted key",
268                                item.type_name()
269                            ))
270                            .with_unexpected(key_span),
271                        );
272                        return None;
273                    }
274                }
275            }
276        };
277    }
278    Some(table)
279}
280
281fn get_key_span(key: &Key) -> Option<toml_parser::Span> {
282    key.as_repr()
283        .and_then(|r| r.span())
284        .map(|s| toml_parser::Span::new_unchecked(s.start, s.end))
285}