1use serde_spanned::Spanned;
2
3use crate::alloc_prelude::*;
4use crate::de::DeString;
5use crate::de::DeValue;
6use crate::de::parser::key::on_key;
7use crate::de::parser::prelude::*;
8use crate::de::parser::value::value;
9use crate::de::{DeArray, DeTable};
10use crate::map::Entry;
11
12pub(crate) fn document<'i>(
23 input: &mut Input<'_>,
24 source: toml_parser::Source<'i>,
25 errors: &mut dyn ErrorSink,
26) -> Spanned<DeTable<'i>> {
27 #[cfg(feature = "debug")]
28 let _scope = TraceScope::new("document::document");
29 let mut state = State::default();
30 while let Some(event) = input.next_token() {
31 match event.kind() {
32 EventKind::InlineTableOpen
33 | EventKind::InlineTableClose
34 | EventKind::ArrayOpen
35 | EventKind::ArrayClose
36 | EventKind::Scalar
37 | EventKind::ValueSep
38 | EventKind::Error
39 | EventKind::KeySep
40 | EventKind::KeyValSep
41 | EventKind::StdTableClose
42 | EventKind::ArrayTableClose => {
43 #[cfg(feature = "debug")]
44 trace(
45 &format!("unexpected {event:?}"),
46 anstyle::AnsiColor::Red.on_default(),
47 );
48 continue;
49 }
50 EventKind::StdTableOpen | EventKind::ArrayTableOpen => {
51 state.finish_table(errors);
52
53 let header = on_table(event, input, source, errors);
54
55 state.start_table(header, errors);
56 }
57 EventKind::SimpleKey => {
58 let (path, key) = on_key(event, input, source, errors);
59 let Some(key) = key else {
60 break;
61 };
62 let Some(next_event) = input.next_token() else {
63 break;
64 };
65 let keyval_event = if next_event.kind() == EventKind::Whitespace {
66 let Some(next_event) = input.next_token() else {
67 break;
68 };
69 next_event
70 } else {
71 next_event
72 };
73 if keyval_event.kind() != EventKind::KeyValSep {
74 break;
75 }
76
77 if input
78 .first()
79 .map(|e| e.kind() == EventKind::Whitespace)
80 .unwrap_or(false)
81 {
82 let _ = input.next_token();
83 }
84 let value = value(input, source, errors);
85
86 state.capture_key_value(path, key, value, errors);
87 }
88 EventKind::Whitespace | EventKind::Comment | EventKind::Newline => {
89 state.capture_trailing(event);
90 }
91 }
92 }
93
94 state.finish_table(errors);
95
96 let span = Default::default();
97 Spanned::new(span, state.root)
98}
99
100fn on_table<'i>(
110 open_event: &toml_parser::parser::Event,
111 input: &mut Input<'_>,
112 source: toml_parser::Source<'i>,
113 errors: &mut dyn ErrorSink,
114) -> TableHeader<'i> {
115 #[cfg(feature = "debug")]
116 let _scope = TraceScope::new("document::on_table");
117 let is_array = open_event.kind() == EventKind::ArrayTableOpen;
118 let mut current_path = None;
119 let mut current_key = None;
120 let mut current_span = open_event.span();
121 let mut current_prefix = None;
122 let mut current_suffix = None;
123
124 while let Some(event) = input.next_token() {
125 match event.kind() {
126 EventKind::InlineTableOpen
127 | EventKind::InlineTableClose
128 | EventKind::ArrayOpen
129 | EventKind::ArrayClose
130 | EventKind::Scalar
131 | EventKind::ValueSep
132 | EventKind::Error
133 | EventKind::KeySep
134 | EventKind::KeyValSep
135 | EventKind::StdTableOpen
136 | EventKind::ArrayTableOpen
137 | EventKind::Comment
138 | EventKind::Newline => {
139 #[cfg(feature = "debug")]
140 trace(
141 &format!("unexpected {event:?}"),
142 anstyle::AnsiColor::Red.on_default(),
143 );
144 continue;
145 }
146 EventKind::ArrayTableClose | EventKind::StdTableClose => {
147 current_span = current_span.append(event.span());
148 break;
149 }
150 EventKind::SimpleKey => {
151 current_prefix.get_or_insert_with(|| event.span().before());
152 let (path, key) = on_key(event, input, source, errors);
153 current_path = Some(path);
154 current_key = key;
155 current_suffix.get_or_insert_with(|| event.span().after());
156 }
157 EventKind::Whitespace => {
158 if current_key.is_some() {
159 current_suffix = Some(event.span());
160 } else {
161 current_prefix = Some(event.span());
162 }
163 }
164 }
165 }
166
167 TableHeader {
168 path: current_path.unwrap_or_default(),
169 key: current_key,
170 span: current_span,
171 is_array,
172 }
173}
174
175struct TableHeader<'i> {
176 path: Vec<Spanned<DeString<'i>>>,
177 key: Option<Spanned<DeString<'i>>>,
178 span: toml_parser::Span,
179 is_array: bool,
180}
181
182#[derive(Default)]
183struct State<'i> {
184 root: DeTable<'i>,
185 current_table: DeTable<'i>,
186 current_header: Option<TableHeader<'i>>,
187 current_position: usize,
188}
189
190impl<'i> State<'i> {
191 fn capture_trailing(&mut self, _event: &toml_parser::parser::Event) {}
192
193 fn capture_key_value(
194 &mut self,
195 path: Vec<Spanned<DeString<'i>>>,
196 key: Spanned<DeString<'i>>,
197 value: Spanned<DeValue<'i>>,
198 errors: &mut dyn ErrorSink,
199 ) {
200 #[cfg(feature = "debug")]
201 let _scope = TraceScope::new("document::capture_key_value");
202 #[cfg(feature = "debug")]
203 trace(
204 &format!(
205 "path={:?}",
206 path.iter().map(|k| k.get_ref()).collect::<Vec<_>>()
207 ),
208 anstyle::AnsiColor::Blue.on_default(),
209 );
210 #[cfg(feature = "debug")]
211 trace(
212 &format!("key={key}",),
213 anstyle::AnsiColor::Blue.on_default(),
214 );
215 #[cfg(feature = "debug")]
216 trace(
217 &format!("value={value:?}",),
218 anstyle::AnsiColor::Blue.on_default(),
219 );
220
221 let dotted = !path.is_empty();
222 let Some(parent_table) = descend_path(&mut self.current_table, &path, dotted, errors)
223 else {
224 return;
225 };
226 let mixed_table_types = dotted && !parent_table.is_implicit();
228 if mixed_table_types {
229 #[cfg(feature = "debug")]
230 trace(
231 &format!("dotted={dotted}"),
232 anstyle::AnsiColor::Red.on_default(),
233 );
234 #[cfg(feature = "debug")]
235 trace(
236 &format!("parent_table.is_implicit={}", parent_table.is_implicit()),
237 anstyle::AnsiColor::Red.on_default(),
238 );
239 let key_span = get_key_span(&key);
240 errors.report_error(ParseError::new("duplicate key").with_unexpected(key_span));
241 return;
242 }
243 let key_span = get_key_span(&key);
244 match parent_table.entry(key) {
245 Entry::Vacant(o) => {
246 o.insert(value);
247 }
248 Entry::Occupied(existing) => {
249 let old_span = get_key_span(existing.key());
251 errors.report_error(
252 ParseError::new("duplicate key")
253 .with_unexpected(key_span)
254 .with_context(old_span),
255 );
256 }
257 }
258 }
259
260 fn finish_table(&mut self, errors: &mut dyn ErrorSink) {
261 #[cfg(feature = "debug")]
262 let _scope = TraceScope::new("document::finish_table");
263 let prev_table = core::mem::take(&mut self.current_table);
264 if let Some(header) = self.current_header.take() {
265 let Some(key) = &header.key else {
266 return;
267 };
268 let header_span = header.span.start()..header.span.end();
269 let prev_table = Spanned::new(header_span.clone(), DeValue::Table(prev_table));
270
271 let parent_key = &header.path;
272 let dotted = false;
273 let Some(parent_table) = descend_path(&mut self.root, parent_key, dotted, errors)
274 else {
275 return;
276 };
277 #[cfg(feature = "debug")]
278 trace(
279 &format!("key={key}",),
280 anstyle::AnsiColor::Blue.on_default(),
281 );
282 if header.is_array {
283 let entry = parent_table.entry(key.clone()).or_insert_with(|| {
284 let mut array = DeArray::new();
285 array.set_array_of_tables(true);
286 Spanned::new(header_span, DeValue::Array(array))
287 });
288 let Some(array) = entry
289 .as_mut()
290 .as_array_mut()
291 .filter(|a| a.is_array_of_tables())
292 else {
293 #[cfg(feature = "debug")]
294 trace(
295 "is_array_of_tables=false",
296 anstyle::AnsiColor::Red.on_default(),
297 );
298 let key_span = get_key_span(key);
299 let old_span = entry.span();
300 let old_span = toml_parser::Span::new_unchecked(old_span.start, old_span.end);
301 errors.report_error(
302 ParseError::new("duplicate key")
303 .with_unexpected(key_span)
304 .with_context(old_span),
305 );
306 return;
307 };
308 array.push(prev_table);
309 } else {
310 let existing = parent_table.insert(key.clone(), prev_table);
311 debug_assert!(existing.is_none());
312 }
313 } else {
314 self.root = prev_table;
315 }
316 }
317
318 fn start_table(&mut self, header: TableHeader<'i>, errors: &mut dyn ErrorSink) {
319 if !header.is_array {
320 let root = &mut self.root;
323 if let (Some(parent_table), Some(key)) =
324 (descend_path(root, &header.path, false, errors), &header.key)
325 {
326 if let Some((old_key, old_value)) = parent_table.remove_entry(key) {
327 match old_value.into_inner() {
328 DeValue::Table(t) if t.is_implicit() && !t.is_dotted() => {
329 self.current_table = t;
330 }
331 old_value => {
333 #[cfg(feature = "debug")]
334 if let DeValue::Table(t) = &old_value {
335 trace(
336 &format!("t.dotted={}", t.is_dotted()),
337 anstyle::AnsiColor::Red.on_default(),
338 );
339 trace(
340 &format!("t.is_implicit={}", t.is_implicit()),
341 anstyle::AnsiColor::Red.on_default(),
342 );
343 } else {
344 trace(
345 &format!("old_value.type_str={}", old_value.type_str()),
346 anstyle::AnsiColor::Red.on_default(),
347 );
348 }
349 let old_span = get_key_span(&old_key);
350 let key_span = get_key_span(key);
351 errors.report_error(
352 ParseError::new("duplicate key")
353 .with_unexpected(key_span)
354 .with_context(old_span),
355 );
356
357 if let DeValue::Table(t) = old_value {
358 self.current_table = t;
359 }
360 }
361 }
362 }
363 }
364 }
365
366 self.current_position += 1;
367 self.current_table.set_implicit(false);
368 self.current_table.set_dotted(false);
369 self.current_header = Some(header);
370 }
371}
372
373fn descend_path<'t, 'i>(
374 mut table: &'t mut DeTable<'i>,
375 path: &[Spanned<DeString<'i>>],
376 dotted: bool,
377 errors: &mut dyn ErrorSink,
378) -> Option<&'t mut DeTable<'i>> {
379 #[cfg(feature = "debug")]
380 let _scope = TraceScope::new("document::descend_path");
381 #[cfg(feature = "debug")]
382 trace(
383 &format!(
384 "path={:?}",
385 path.iter().map(|k| k.get_ref()).collect::<Vec<_>>()
386 ),
387 anstyle::AnsiColor::Blue.on_default(),
388 );
389 for key in path.iter() {
390 #[cfg(feature = "debug")]
391 trace(
392 &format!("path[_]={:?}", key.get_ref()),
393 anstyle::AnsiColor::Blue.on_default(),
394 );
395 table = match table.entry(key.clone()) {
396 Entry::Vacant(entry) => {
397 let mut new_table = DeTable::new();
398 new_table.set_implicit(true);
399 new_table.set_dotted(dotted);
400
401 let value = DeValue::Table(new_table);
402 let value = Spanned::new(key.span(), value);
403 let value = entry.insert(value);
404 value.as_mut().as_table_mut().unwrap()
405 }
406 Entry::Occupied(entry) => {
407 let spanned = entry.into_mut();
408 let old_span = spanned.span();
409 match spanned.as_mut() {
410 DeValue::Array(array) => {
411 if !array.is_array_of_tables() {
412 let old_span =
413 toml_parser::Span::new_unchecked(old_span.start, old_span.end);
414 let key_span = get_key_span(key);
415 errors.report_error(
416 ParseError::new(
417 "cannot extend value of type array with a dotted key",
418 )
419 .with_unexpected(key_span)
420 .with_context(old_span),
421 );
422 return None;
423 }
424
425 debug_assert!(!array.is_empty());
426
427 let index = array.len() - 1;
428 let last_child = array.get_mut(index).unwrap();
429
430 match last_child.as_mut() {
431 DeValue::Table(table) => table,
432 existing => {
433 let old_span =
434 toml_parser::Span::new_unchecked(old_span.start, old_span.end);
435 let key_span = get_key_span(key);
436 errors.report_error(
437 ParseError::new(format!(
438 "cannot extend value of type {} with a dotted key",
439 existing.type_str()
440 ))
441 .with_unexpected(key_span)
442 .with_context(old_span),
443 );
444 return None;
445 }
446 }
447 }
448 DeValue::Table(sweet_child_of_mine) => {
449 if sweet_child_of_mine.is_inline() {
450 let key_span = get_key_span(key);
451 errors.report_error(
452 ParseError::new(
453 "cannot extend value of type inline table with a dotted key",
454 )
455 .with_unexpected(key_span),
456 );
457 return None;
458 }
459 if dotted && sweet_child_of_mine.is_implicit() {
460 sweet_child_of_mine.set_dotted(true);
464 }
465 let mixed_table_types = dotted && !sweet_child_of_mine.is_implicit();
469 if mixed_table_types {
470 #[cfg(feature = "debug")]
471 trace(
472 &format!("dotted={dotted}"),
473 anstyle::AnsiColor::Red.on_default(),
474 );
475 #[cfg(feature = "debug")]
476 trace(
477 &format!(
478 "sweet_child_of_mine.is_implicit={}",
479 sweet_child_of_mine.is_implicit()
480 ),
481 anstyle::AnsiColor::Red.on_default(),
482 );
483 let key_span = get_key_span(key);
484 errors.report_error(
485 ParseError::new("duplicate key").with_unexpected(key_span),
486 );
487 return None;
488 }
489 sweet_child_of_mine
490 }
491 existing => {
492 let old_span =
493 toml_parser::Span::new_unchecked(old_span.start, old_span.end);
494 let key_span = get_key_span(key);
495 errors.report_error(
496 ParseError::new(format!(
497 "cannot extend value of type {} with a dotted key",
498 existing.type_str()
499 ))
500 .with_unexpected(key_span)
501 .with_context(old_span),
502 );
503 return None;
504 }
505 }
506 }
507 };
508 }
509 Some(table)
510}
511
512fn get_key_span(key: &Spanned<DeString<'_>>) -> toml_parser::Span {
513 let key_span = key.span();
514 toml_parser::Span::new_unchecked(key_span.start, key_span.end)
515}