toml_edit/parser/
state.rs

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