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            let entry = table.entry_format(key).or_insert_with(|| {
235                let mut new_table = Table::new();
236                new_table.set_implicit(true);
237                new_table.set_dotted(dotted);
238
239                Item::Table(new_table)
240            });
241            match *entry {
242                Item::Value(ref v) => {
243                    return Err(CustomError::extend_wrong_type(path, i, v.type_name()));
244                }
245                Item::ArrayOfTables(ref mut array) => {
246                    debug_assert!(!array.is_empty());
247
248                    let index = array.len() - 1;
249                    let last_child = array.get_mut(index).unwrap();
250
251                    table = last_child;
252                }
253                Item::Table(ref mut sweet_child_of_mine) => {
254                    // Since tables cannot be defined more than once, redefining such tables using a
255                    // [table] header is not allowed. Likewise, using dotted keys to redefine tables
256                    // already defined in [table] form is not allowed.
257                    if dotted && !sweet_child_of_mine.is_implicit() {
258                        return Err(CustomError::DuplicateKey {
259                            key: key.get().into(),
260                            table: None,
261                        });
262                    }
263                    table = sweet_child_of_mine;
264                }
265                Item::None => unreachable!(),
266            }
267        }
268        Ok(table)
269    }
270
271    pub(crate) fn on_std_header(
272        &mut self,
273        path: Vec<Key>,
274        trailing: std::ops::Range<usize>,
275        span: std::ops::Range<usize>,
276    ) -> Result<(), CustomError> {
277        debug_assert!(!path.is_empty());
278
279        self.finalize_table()?;
280        let leading = self
281            .trailing
282            .take()
283            .map(RawString::with_span)
284            .unwrap_or_default();
285        self.start_table(
286            path,
287            Decor::new(leading, RawString::with_span(trailing)),
288            span,
289        )?;
290
291        Ok(())
292    }
293
294    pub(crate) fn on_array_header(
295        &mut self,
296        path: Vec<Key>,
297        trailing: std::ops::Range<usize>,
298        span: std::ops::Range<usize>,
299    ) -> Result<(), CustomError> {
300        debug_assert!(!path.is_empty());
301
302        self.finalize_table()?;
303        let leading = self
304            .trailing
305            .take()
306            .map(RawString::with_span)
307            .unwrap_or_default();
308        self.start_array_table(
309            path,
310            Decor::new(leading, RawString::with_span(trailing)),
311            span,
312        )?;
313
314        Ok(())
315    }
316}