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