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 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 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 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 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 _ => 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 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 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}