toml_edit/parser/
state.rs

1use crate::key::Key;
2use crate::parser::error::CustomError;
3use crate::repr::Decor;
4use crate::{ArrayOfTables, ImDocument, Item, RawString, Table};
5
6pub(crate) struct ParseState {
7    root: Table,
8    trailing: Option<std::ops::Range<usize>>,
9    current_table_position: usize,
10    current_table: Table,
11    current_is_array: bool,
12    current_table_path: Vec<Key>,
13}
14
15impl ParseState {
16    pub(crate) fn new() -> Self {
17        let mut root = Table::new();
18        root.span = Some(0..0);
19        Self {
20            root: Table::new(),
21            trailing: None,
22            current_table_position: 0,
23            current_table: root,
24            current_is_array: false,
25            current_table_path: Vec::new(),
26        }
27    }
28
29    pub(crate) fn into_document<S>(mut self, raw: S) -> Result<ImDocument<S>, CustomError> {
30        self.finalize_table()?;
31        let trailing = self.trailing.map(RawString::with_span).unwrap_or_default();
32        Ok(ImDocument {
33            root: Item::Table(self.root),
34            trailing,
35            raw,
36        })
37    }
38
39    pub(crate) fn on_ws(&mut self, span: std::ops::Range<usize>) {
40        if let Some(old) = self.trailing.take() {
41            self.trailing = Some(old.start..span.end);
42        } else {
43            self.trailing = Some(span);
44        }
45    }
46
47    pub(crate) fn on_comment(&mut self, span: std::ops::Range<usize>) {
48        if let Some(old) = self.trailing.take() {
49            self.trailing = Some(old.start..span.end);
50        } else {
51            self.trailing = Some(span);
52        }
53    }
54
55    pub(crate) fn on_keyval(
56        &mut self,
57        path: Vec<Key>,
58        (mut key, value): (Key, Item),
59    ) -> Result<(), CustomError> {
60        {
61            let mut prefix = self.trailing.take();
62            let prefix = match (
63                prefix.take(),
64                key.leaf_decor.prefix().and_then(|d| d.span()),
65            ) {
66                (Some(p), Some(k)) => Some(p.start..k.end),
67                (Some(p), None) | (None, Some(p)) => Some(p),
68                (None, None) => None,
69            };
70            key.leaf_decor
71                .set_prefix(prefix.map(RawString::with_span).unwrap_or_default());
72        }
73
74        if let (Some(existing), Some(value)) = (self.current_table.span(), value.span()) {
75            self.current_table.span = Some((existing.start)..(value.end));
76        }
77        let table = &mut self.current_table;
78        let table = Self::descend_path(table, &path, true)?;
79
80        // "Likewise, using dotted keys to redefine tables already defined in [table] form is not allowed"
81        let mixed_table_types = table.is_dotted() == path.is_empty();
82        if mixed_table_types {
83            return Err(CustomError::DuplicateKey {
84                key: key.get().into(),
85                table: None,
86            });
87        }
88
89        match table.items.entry(key) {
90            indexmap::map::Entry::Vacant(o) => {
91                o.insert(value);
92            }
93            indexmap::map::Entry::Occupied(o) => {
94                // "Since tables cannot be defined more than once, redefining such tables using a [table] header is not allowed"
95                return Err(CustomError::DuplicateKey {
96                    key: o.key().get().into(),
97                    table: Some(self.current_table_path.clone()),
98                });
99            }
100        }
101
102        Ok(())
103    }
104
105    pub(crate) fn start_array_table(
106        &mut self,
107        path: Vec<Key>,
108        decor: Decor,
109        span: std::ops::Range<usize>,
110    ) -> Result<(), CustomError> {
111        debug_assert!(!path.is_empty());
112        debug_assert!(self.current_table.is_empty());
113        debug_assert!(self.current_table_path.is_empty());
114
115        // Look up the table on start to ensure the duplicate_key error points to the right line
116        let root = &mut self.root;
117        let parent_table = Self::descend_path(root, &path[..path.len() - 1], false)?;
118        let key = &path[path.len() - 1];
119        let entry = parent_table
120            .entry_format(key)
121            .or_insert(Item::ArrayOfTables(ArrayOfTables::new()));
122        entry
123            .as_array_of_tables()
124            .ok_or_else(|| CustomError::duplicate_key(&path, path.len() - 1))?;
125
126        self.current_table_position += 1;
127        self.current_table.decor = decor;
128        self.current_table.set_implicit(false);
129        self.current_table.set_dotted(false);
130        self.current_table.set_position(self.current_table_position);
131        self.current_table.span = Some(span);
132        self.current_is_array = true;
133        self.current_table_path = path;
134
135        Ok(())
136    }
137
138    pub(crate) fn start_table(
139        &mut self,
140        path: Vec<Key>,
141        decor: Decor,
142        span: std::ops::Range<usize>,
143    ) -> Result<(), CustomError> {
144        debug_assert!(!path.is_empty());
145        debug_assert!(self.current_table.is_empty());
146        debug_assert!(self.current_table_path.is_empty());
147
148        // 1. Look up the table on start to ensure the duplicate_key error points to the right line
149        // 2. Ensure any child tables from an implicit table are preserved
150        let root = &mut self.root;
151        let parent_table = Self::descend_path(root, &path[..path.len() - 1], false)?;
152        let key = &path[path.len() - 1];
153        if let Some(entry) = parent_table.remove(key.get()) {
154            match entry {
155                Item::Table(t) if t.implicit && !t.is_dotted() => {
156                    self.current_table = t;
157                }
158                // 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.
159                _ => return Err(CustomError::duplicate_key(&path, path.len() - 1)),
160            }
161        }
162
163        self.current_table_position += 1;
164        self.current_table.decor = decor;
165        self.current_table.set_implicit(false);
166        self.current_table.set_dotted(false);
167        self.current_table.set_position(self.current_table_position);
168        self.current_table.span = Some(span);
169        self.current_is_array = false;
170        self.current_table_path = path;
171
172        Ok(())
173    }
174
175    pub(crate) fn finalize_table(&mut self) -> Result<(), CustomError> {
176        let mut table = std::mem::take(&mut self.current_table);
177        let path = std::mem::take(&mut self.current_table_path);
178
179        let root = &mut self.root;
180        if path.is_empty() {
181            assert!(root.is_empty());
182            std::mem::swap(&mut table, root);
183        } else if self.current_is_array {
184            let parent_table = Self::descend_path(root, &path[..path.len() - 1], false)?;
185            let key = &path[path.len() - 1];
186
187            let entry = parent_table
188                .entry_format(key)
189                .or_insert(Item::ArrayOfTables(ArrayOfTables::new()));
190            let array = entry
191                .as_array_of_tables_mut()
192                .ok_or_else(|| CustomError::duplicate_key(&path, path.len() - 1))?;
193            array.push(table);
194            let span = if let (Some(first), Some(last)) = (
195                array.values.first().and_then(|t| t.span()),
196                array.values.last().and_then(|t| t.span()),
197            ) {
198                Some((first.start)..(last.end))
199            } else {
200                None
201            };
202            array.span = span;
203        } else {
204            let parent_table = Self::descend_path(root, &path[..path.len() - 1], false)?;
205            let key = &path[path.len() - 1];
206
207            let entry = parent_table.entry_format(key);
208            match entry {
209                crate::Entry::Occupied(entry) => {
210                    match entry.into_mut() {
211                        // if [a.b.c] header preceded [a.b]
212                        Item::Table(ref mut t) if t.implicit => {
213                            std::mem::swap(t, &mut table);
214                        }
215                        _ => return Err(CustomError::duplicate_key(&path, path.len() - 1)),
216                    }
217                }
218                crate::Entry::Vacant(entry) => {
219                    let item = Item::Table(table);
220                    entry.insert(item);
221                }
222            }
223        }
224
225        Ok(())
226    }
227
228    pub(crate) fn descend_path<'t>(
229        mut table: &'t mut Table,
230        path: &[Key],
231        dotted: bool,
232    ) -> Result<&'t mut Table, CustomError> {
233        for (i, key) in path.iter().enumerate() {
234            table = match table.entry_format(key) {
235                crate::Entry::Vacant(entry) => {
236                    let mut new_table = Table::new();
237                    new_table.set_implicit(true);
238                    new_table.set_dotted(dotted);
239
240                    entry.insert(Item::Table(new_table)).as_table_mut().unwrap()
241                }
242                crate::Entry::Occupied(entry) => {
243                    match entry.into_mut() {
244                        Item::Value(ref v) => {
245                            return Err(CustomError::extend_wrong_type(path, i, v.type_name()));
246                        }
247                        Item::ArrayOfTables(ref mut array) => {
248                            debug_assert!(!array.is_empty());
249
250                            let index = array.len() - 1;
251                            let last_child = array.get_mut(index).unwrap();
252
253                            last_child
254                        }
255                        Item::Table(ref mut sweet_child_of_mine) => {
256                            // Since tables cannot be defined more than once, redefining such tables using a
257                            // [table] header is not allowed. Likewise, using dotted keys to redefine tables
258                            // already defined in [table] form is not allowed.
259                            if dotted && !sweet_child_of_mine.is_implicit() {
260                                return Err(CustomError::DuplicateKey {
261                                    key: key.get().into(),
262                                    table: None,
263                                });
264                            }
265                            sweet_child_of_mine
266                        }
267                        Item::None => unreachable!(),
268                    }
269                }
270            };
271        }
272        Ok(table)
273    }
274
275    pub(crate) fn on_std_header(
276        &mut self,
277        path: Vec<Key>,
278        trailing: std::ops::Range<usize>,
279        span: std::ops::Range<usize>,
280    ) -> Result<(), CustomError> {
281        debug_assert!(!path.is_empty());
282
283        self.finalize_table()?;
284        let leading = self
285            .trailing
286            .take()
287            .map(RawString::with_span)
288            .unwrap_or_default();
289        self.start_table(
290            path,
291            Decor::new(leading, RawString::with_span(trailing)),
292            span,
293        )?;
294
295        Ok(())
296    }
297
298    pub(crate) fn on_array_header(
299        &mut self,
300        path: Vec<Key>,
301        trailing: std::ops::Range<usize>,
302        span: std::ops::Range<usize>,
303    ) -> Result<(), CustomError> {
304        debug_assert!(!path.is_empty());
305
306        self.finalize_table()?;
307        let leading = self
308            .trailing
309            .take()
310            .map(RawString::with_span)
311            .unwrap_or_default();
312        self.start_array_table(
313            path,
314            Decor::new(leading, RawString::with_span(trailing)),
315            span,
316        )?;
317
318        Ok(())
319    }
320}