1 | use crate::key::Key; |
2 | use crate::parser::error::CustomError; |
3 | use crate::repr::Decor; |
4 | use crate::{ArrayOfTables, ImDocument, Item, RawString, Table}; |
5 | |
6 | pub(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 | |
15 | impl 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 | } |
317 | |