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