| 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 | |