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 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 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_aray_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 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_position(self.current_table_position);
121 self.current_table.span = Some(span);
122 self.current_is_array = true;
123 self.current_table_path = path;
124
125 Ok(())
126 }
127
128 pub(crate) fn start_table(
129 &mut self,
130 path: Vec<Key>,
131 decor: Decor,
132 span: std::ops::Range<usize>,
133 ) -> Result<(), CustomError> {
134 debug_assert!(!path.is_empty());
135 debug_assert!(self.current_table.is_empty());
136 debug_assert!(self.current_table_path.is_empty());
137
138 let root = self.document.as_table_mut();
141 let parent_table = Self::descend_path(root, &path[..path.len() - 1], false)?;
142 let key = &path[path.len() - 1];
143 if let Some(entry) = parent_table.remove(key.get()) {
144 match entry {
145 Item::Table(t) if t.implicit && !t.is_dotted() => {
146 self.current_table = t;
147 }
148 _ => return Err(CustomError::duplicate_key(&path, path.len() - 1)),
150 }
151 }
152
153 self.current_table_position += 1;
154 self.current_table.decor = decor;
155 self.current_table.set_position(self.current_table_position);
156 self.current_table.span = Some(span);
157 self.current_is_array = false;
158 self.current_table_path = path;
159
160 Ok(())
161 }
162
163 pub(crate) fn finalize_table(&mut self) -> Result<(), CustomError> {
164 let mut table = std::mem::take(&mut self.current_table);
165 let path = std::mem::take(&mut self.current_table_path);
166
167 let root = self.document.as_table_mut();
168 if path.is_empty() {
169 assert!(root.is_empty());
170 std::mem::swap(&mut table, root);
171 } else if self.current_is_array {
172 let parent_table = Self::descend_path(root, &path[..path.len() - 1], false)?;
173 let key = &path[path.len() - 1];
174
175 let entry = parent_table
176 .entry_format(key)
177 .or_insert(Item::ArrayOfTables(ArrayOfTables::new()));
178 let array = entry
179 .as_array_of_tables_mut()
180 .ok_or_else(|| CustomError::duplicate_key(&path, path.len() - 1))?;
181 array.push(table);
182 let span = if let (Some(first), Some(last)) = (
183 array.values.first().and_then(|t| t.span()),
184 array.values.last().and_then(|t| t.span()),
185 ) {
186 Some((first.start)..(last.end))
187 } else {
188 None
189 };
190 array.span = span;
191 } else {
192 let parent_table = Self::descend_path(root, &path[..path.len() - 1], false)?;
193 let key = &path[path.len() - 1];
194
195 let entry = parent_table.entry_format(key);
196 match entry {
197 crate::Entry::Occupied(entry) => {
198 match entry.into_mut() {
199 Item::Table(ref mut t) if t.implicit => {
201 std::mem::swap(t, &mut table);
202 }
203 _ => return Err(CustomError::duplicate_key(&path, path.len() - 1)),
204 }
205 }
206 crate::Entry::Vacant(entry) => {
207 let item = Item::Table(table);
208 entry.insert(item);
209 }
210 }
211 }
212
213 Ok(())
214 }
215
216 pub(crate) fn descend_path<'t, 'k>(
217 mut table: &'t mut Table,
218 path: &'k [Key],
219 dotted: bool,
220 ) -> Result<&'t mut Table, CustomError> {
221 for (i, key) in path.iter().enumerate() {
222 let entry = table.entry_format(key).or_insert_with(|| {
223 let mut new_table = Table::new();
224 new_table.set_implicit(true);
225 new_table.set_dotted(dotted);
226
227 Item::Table(new_table)
228 });
229 match *entry {
230 Item::Value(ref v) => {
231 return Err(CustomError::extend_wrong_type(path, i, v.type_name()));
232 }
233 Item::ArrayOfTables(ref mut array) => {
234 debug_assert!(!array.is_empty());
235
236 let index = array.len() - 1;
237 let last_child = array.get_mut(index).unwrap();
238
239 table = last_child;
240 }
241 Item::Table(ref mut sweet_child_of_mine) => {
242 if dotted && !sweet_child_of_mine.is_implicit() {
246 return Err(CustomError::DuplicateKey {
247 key: key.get().into(),
248 table: None,
249 });
250 }
251 table = sweet_child_of_mine;
252 }
253 _ => unreachable!(),
254 }
255 }
256 Ok(table)
257 }
258
259 pub(crate) fn on_std_header(
260 &mut self,
261 path: Vec<Key>,
262 trailing: std::ops::Range<usize>,
263 span: std::ops::Range<usize>,
264 ) -> Result<(), CustomError> {
265 debug_assert!(!path.is_empty());
266
267 self.finalize_table()?;
268 let leading = self
269 .trailing
270 .take()
271 .map(RawString::with_span)
272 .unwrap_or_default();
273 self.start_table(
274 path,
275 Decor::new(leading, RawString::with_span(trailing)),
276 span,
277 )?;
278
279 Ok(())
280 }
281
282 pub(crate) fn on_array_header(
283 &mut self,
284 path: Vec<Key>,
285 trailing: std::ops::Range<usize>,
286 span: std::ops::Range<usize>,
287 ) -> Result<(), CustomError> {
288 debug_assert!(!path.is_empty());
289
290 self.finalize_table()?;
291 let leading = self
292 .trailing
293 .take()
294 .map(RawString::with_span)
295 .unwrap_or_default();
296 self.start_aray_table(
297 path,
298 Decor::new(leading, RawString::with_span(trailing)),
299 span,
300 )?;
301
302 Ok(())
303 }
304}
305
306impl Default for ParseState {
307 fn default() -> Self {
308 let mut root = Table::new();
309 root.span = Some(0..0);
310 Self {
311 document: Document::new(),
312 trailing: None,
313 current_table_position: 0,
314 current_table: root,
315 current_is_array: false,
316 current_table_path: Vec::new(),
317 }
318 }
319}