1 | use crate::key::Key; |
2 | use crate::parser::errors::CustomError; |
3 | use crate::repr::Decor; |
4 | use crate::table::TableKeyValue; |
5 | use crate::{ArrayOfTables, Document, InternalString, Item, RawString, Table}; |
6 | |
7 | pub(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 | |
16 | impl 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 | |
310 | impl Default for ParseState { |
311 | fn default() -> Self { |
312 | let mut root: Table = 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 | } |
324 | |