1use crate::Item;
2use crate::RawString;
3use crate::Value;
4use crate::key::Key;
5use crate::parser::key::on_key;
6use crate::parser::prelude::*;
7use crate::parser::value::value;
8use crate::repr::Decor;
9use crate::{ArrayOfTables, Document, Table};
10
11pub(crate) fn document<'s>(
22 input: &mut Input<'_>,
23 source: toml_parser::Source<'s>,
24 errors: &mut dyn ErrorSink,
25) -> Document<&'s str> {
26 #[cfg(feature = "debug")]
27 let _scope = TraceScope::new("document::document");
28 let mut state = State::default();
29 while let Some(event) = input.next_token() {
30 match event.kind() {
31 EventKind::InlineTableOpen
32 | EventKind::InlineTableClose
33 | EventKind::ArrayOpen
34 | EventKind::ArrayClose
35 | EventKind::Scalar
36 | EventKind::ValueSep
37 | EventKind::Error
38 | EventKind::KeySep
39 | EventKind::KeyValSep
40 | EventKind::StdTableClose
41 | EventKind::ArrayTableClose => {
42 #[cfg(feature = "debug")]
43 trace(
44 &format!("unexpected {event:?}"),
45 anstyle::AnsiColor::Red.on_default(),
46 );
47 continue;
48 }
49 EventKind::StdTableOpen | EventKind::ArrayTableOpen => {
50 state.finish_table(errors);
51
52 let prefix = state.take_trailing();
53 let header = on_table(event, input, source, errors);
54 let suffix = ws_comment_newline(input)
55 .map(|s| RawString::with_span(s.start()..s.end()))
56 .unwrap_or_default();
57 let decor = Decor::new(prefix, suffix);
58
59 state.start_table(header, decor, errors);
60 }
61 EventKind::SimpleKey => {
62 let key_prefix = state.take_trailing();
63 let (path, key) = on_key(event, input, source, errors);
64 let Some(mut key) = key else {
65 break;
66 };
67 let Some(next_event) = input.next_token() else {
68 break;
69 };
70 let keyval_event;
71 let key_suffix;
72 if next_event.kind() == EventKind::Whitespace {
73 key_suffix = Some(next_event);
74 let Some(next_event) = input.next_token() else {
75 break;
76 };
77 keyval_event = next_event;
78 } else {
79 key_suffix = None;
80 keyval_event = next_event;
81 }
82 if keyval_event.kind() != EventKind::KeyValSep {
83 break;
84 }
85 let key_suffix = key_suffix
86 .map(|e| RawString::with_span(e.span().start()..e.span().end()))
87 .unwrap_or_default();
88 key.leaf_decor.set_prefix(key_prefix);
89 key.leaf_decor.set_suffix(key_suffix);
90
91 let value_prefix = if input
92 .first()
93 .map(|e| e.kind() == EventKind::Whitespace)
94 .unwrap_or(false)
95 {
96 input
97 .next_token()
98 .map(|e| RawString::with_span(e.span().start()..e.span().end()))
99 } else {
100 None
101 }
102 .unwrap_or_default();
103 let mut value = value(input, source, errors);
104 let value_suffix = ws_comment_newline(input)
105 .map(|s| RawString::with_span(s.start()..s.end()))
106 .unwrap_or_default();
107 let decor = value.decor_mut();
108 decor.set_prefix(value_prefix);
109 decor.set_suffix(value_suffix);
110
111 state.capture_key_value(path, key, value, errors);
112 }
113 EventKind::Whitespace | EventKind::Comment | EventKind::Newline => {
114 state.capture_trailing(event);
115 }
116 }
117 }
118
119 state.finish_table(errors);
120
121 let trailing = state.take_trailing();
122 Document {
123 root: Item::Table(state.root),
124 trailing,
125 raw: source.input(),
126 }
127}
128
129fn on_table(
139 open_event: &toml_parser::parser::Event,
140 input: &mut Input<'_>,
141 source: toml_parser::Source<'_>,
142 errors: &mut dyn ErrorSink,
143) -> TableHeader {
144 #[cfg(feature = "debug")]
145 let _scope = TraceScope::new("document::on_table");
146 let is_array = open_event.kind() == EventKind::ArrayTableOpen;
147 let mut current_path = None;
148 let mut current_key = None;
149 let mut current_span = open_event.span();
150 let mut current_prefix = None;
151 let mut current_suffix = None;
152
153 while let Some(event) = input.next_token() {
154 match event.kind() {
155 EventKind::InlineTableOpen
156 | EventKind::InlineTableClose
157 | EventKind::ArrayOpen
158 | EventKind::ArrayClose
159 | EventKind::Scalar
160 | EventKind::ValueSep
161 | EventKind::Error
162 | EventKind::KeySep
163 | EventKind::KeyValSep
164 | EventKind::StdTableOpen
165 | EventKind::ArrayTableOpen
166 | EventKind::Comment
167 | EventKind::Newline => {
168 #[cfg(feature = "debug")]
169 trace(
170 &format!("unexpected {event:?}"),
171 anstyle::AnsiColor::Red.on_default(),
172 );
173 continue;
174 }
175 EventKind::ArrayTableClose | EventKind::StdTableClose => {
176 current_span = current_span.append(event.span());
177 break;
178 }
179 EventKind::SimpleKey => {
180 current_prefix.get_or_insert_with(|| event.span().before());
181 let (path, key) = on_key(event, input, source, errors);
182 current_path = Some(path);
183 current_key = key;
184 current_suffix.get_or_insert_with(|| event.span().after());
185 }
186 EventKind::Whitespace => {
187 if current_key.is_some() {
188 current_suffix = Some(event.span());
189 } else {
190 current_prefix = Some(event.span());
191 }
192 }
193 }
194 }
195
196 let prefix = current_prefix
197 .take()
198 .expect("setting a key should set a prefix");
199 let suffix = current_suffix
200 .take()
201 .expect("setting a key should set a suffix");
202 if let Some(last_key) = current_key.as_mut() {
203 let prefix = RawString::with_span(prefix.start()..prefix.end());
204 let suffix = RawString::with_span(suffix.start()..suffix.end());
205 let leaf_decor = Decor::new(prefix, suffix);
206 *last_key.leaf_decor_mut() = leaf_decor;
207 }
208
209 TableHeader {
210 path: current_path.unwrap_or_default(),
211 key: current_key,
212 span: current_span,
213 is_array,
214 }
215}
216
217struct TableHeader {
218 path: Vec<Key>,
219 key: Option<Key>,
220 span: toml_parser::Span,
221 is_array: bool,
222}
223
224fn ws_comment_newline(input: &mut Input<'_>) -> Option<toml_parser::Span> {
225 let mut current_span = None;
226 while let Some(event) = input.next_token() {
227 match event.kind() {
228 EventKind::InlineTableOpen
229 | EventKind::InlineTableClose
230 | EventKind::ArrayOpen
231 | EventKind::ArrayClose
232 | EventKind::Scalar
233 | EventKind::ValueSep
234 | EventKind::Error
235 | EventKind::SimpleKey
236 | EventKind::KeySep
237 | EventKind::KeyValSep
238 | EventKind::StdTableOpen
239 | EventKind::ArrayTableOpen
240 | EventKind::StdTableClose
241 | EventKind::ArrayTableClose => {
242 #[cfg(feature = "debug")]
243 trace(
244 &format!("unexpected {event:?}"),
245 anstyle::AnsiColor::Red.on_default(),
246 );
247 }
248 EventKind::Whitespace | EventKind::Comment => {
249 let span = current_span.get_or_insert_with(|| event.span());
250 *span = span.append(event.span());
251 }
252 EventKind::Newline => {
253 break;
254 }
255 }
256 }
257
258 current_span
259}
260
261#[derive(Default)]
262struct State {
263 root: Table,
264 current_table: Table,
265 current_trailing: Option<toml_parser::Span>,
266 current_header: Option<TableHeader>,
267 current_position: isize,
268}
269
270impl State {
271 fn capture_trailing(&mut self, event: &toml_parser::parser::Event) {
272 let decor = self.current_trailing.get_or_insert(event.span());
273 *decor = decor.append(event.span());
274 }
275
276 fn capture_key_value(
277 &mut self,
278 path: Vec<Key>,
279 key: Key,
280 value: Value,
281 errors: &mut dyn ErrorSink,
282 ) {
283 #[cfg(feature = "debug")]
284 let _scope = TraceScope::new("document::capture_key_value");
285 #[cfg(feature = "debug")]
286 trace(
287 &format!(
288 "path={:?}",
289 path.iter().map(|k| k.get()).collect::<Vec<_>>()
290 ),
291 anstyle::AnsiColor::Blue.on_default(),
292 );
293 #[cfg(feature = "debug")]
294 trace(
295 &format!("key={key}",),
296 anstyle::AnsiColor::Blue.on_default(),
297 );
298 #[cfg(feature = "debug")]
299 trace(
300 &format!("value={value:?}",),
301 anstyle::AnsiColor::Blue.on_default(),
302 );
303
304 let dotted = !path.is_empty();
305 let Some(parent_table) = descend_path(&mut self.current_table, &path, dotted, errors)
306 else {
307 return;
308 };
309 let mixed_table_types = dotted && !parent_table.is_implicit();
311 if mixed_table_types {
312 #[cfg(feature = "debug")]
313 trace(
314 &format!("dotted={dotted}"),
315 anstyle::AnsiColor::Red.on_default(),
316 );
317 #[cfg(feature = "debug")]
318 trace(
319 &format!("parent_table.is_implicit={}", parent_table.is_implicit()),
320 anstyle::AnsiColor::Red.on_default(),
321 );
322 let key_span = get_key_span(&key).expect("all keys have spans");
323 errors.report_error(ParseError::new("duplicate key").with_unexpected(key_span));
324 return;
325 }
326 let key_span = get_key_span(&key).expect("all keys have spans");
327 match parent_table.items.entry(key) {
328 indexmap::map::Entry::Vacant(o) => {
329 o.insert(Item::Value(value));
330 }
331 indexmap::map::Entry::Occupied(existing) => {
332 let old_span = existing.key().span().expect("all items have spans");
334 let old_span = toml_parser::Span::new_unchecked(old_span.start, old_span.end);
335 errors.report_error(
336 ParseError::new("duplicate key")
337 .with_unexpected(key_span)
338 .with_context(old_span),
339 );
340 }
341 }
342 }
343
344 fn finish_table(&mut self, errors: &mut dyn ErrorSink) {
345 #[cfg(feature = "debug")]
346 let _scope = TraceScope::new("document::finish_table");
347 let mut prev_table = std::mem::take(&mut self.current_table);
348 if let Some(header) = self.current_header.take() {
349 let Some(key) = &header.key else {
350 return;
351 };
352 prev_table.span = Some(header.span.start()..header.span.end());
353
354 let parent_key = &header.path;
355 let dotted = false;
356 let Some(parent_table) = descend_path(&mut self.root, parent_key, dotted, errors)
357 else {
358 return;
359 };
360 #[cfg(feature = "debug")]
361 trace(
362 &format!("key={key}",),
363 anstyle::AnsiColor::Blue.on_default(),
364 );
365 if header.is_array {
366 let entry = parent_table
367 .entry_format(key)
368 .or_insert(Item::ArrayOfTables(ArrayOfTables::new()));
369 let Some(array) = entry.as_array_of_tables_mut() else {
370 #[cfg(feature = "debug")]
371 trace(
372 "is_array_of_tables=false",
373 anstyle::AnsiColor::Red.on_default(),
374 );
375 let key_span = get_key_span(key).expect("all keys have spans");
376 let old_span = entry.span().unwrap_or_default();
377 let old_span = toml_parser::Span::new_unchecked(old_span.start, old_span.end);
378 errors.report_error(
379 ParseError::new("duplicate key")
380 .with_unexpected(key_span)
381 .with_context(old_span),
382 );
383 return;
384 };
385 array.push(prev_table);
386 let span = if let (Some(first), Some(last)) = (
387 array.values.first().and_then(|t| t.span()),
388 array.values.last().and_then(|t| t.span()),
389 ) {
390 Some((first.start)..(last.end))
391 } else {
392 None
393 };
394 array.span = span;
395 } else {
396 let existing = parent_table.insert_formatted(key, Item::Table(prev_table));
397 debug_assert!(existing.is_none());
398 }
399 } else {
400 prev_table.span = Some(Default::default());
401 self.root = prev_table;
402 }
403 }
404
405 fn start_table(&mut self, header: TableHeader, decor: Decor, errors: &mut dyn ErrorSink) {
406 if !header.is_array {
407 let root = &mut self.root;
410 if let (Some(parent_table), Some(key)) =
411 (descend_path(root, &header.path, false, errors), &header.key)
412 {
413 if let Some((old_key, old_value)) = parent_table.remove_entry(key.get()) {
414 match old_value {
415 Item::Table(t) if t.implicit && !t.is_dotted() => {
416 self.current_table = t;
417 }
418 old_value => {
420 #[cfg(feature = "debug")]
421 if let Item::Table(t) = &old_value {
422 trace(
423 &format!("t.dotted={}", t.is_dotted()),
424 anstyle::AnsiColor::Red.on_default(),
425 );
426 trace(
427 &format!("t.is_implicit={}", t.is_implicit()),
428 anstyle::AnsiColor::Red.on_default(),
429 );
430 } else {
431 trace(
432 &format!("old_value.type_str={}", old_value.type_name()),
433 anstyle::AnsiColor::Red.on_default(),
434 );
435 }
436 let old_span = old_key.span().expect("all items have spans");
437 let old_span =
438 toml_parser::Span::new_unchecked(old_span.start, old_span.end);
439 let key_span = get_key_span(key).expect("all keys have spans");
440 errors.report_error(
441 ParseError::new("duplicate key")
442 .with_unexpected(key_span)
443 .with_context(old_span),
444 );
445
446 if let Item::Table(t) = old_value {
447 self.current_table = t;
448 }
449 }
450 }
451 }
452 }
453 }
454
455 self.current_position += 1;
456 self.current_table.decor = decor;
457 self.current_table.set_implicit(false);
458 self.current_table.set_dotted(false);
459 self.current_table.set_position(Some(self.current_position));
460 self.current_table.span = Some(header.span.start()..header.span.end());
461 self.current_header = Some(header);
462 }
463
464 fn take_trailing(&mut self) -> RawString {
465 self.current_trailing
466 .take()
467 .map(|s| RawString::with_span(s.start()..s.end()))
468 .unwrap_or_default()
469 }
470}
471
472fn descend_path<'t>(
473 mut table: &'t mut Table,
474 path: &[Key],
475 dotted: bool,
476 errors: &mut dyn ErrorSink,
477) -> Option<&'t mut Table> {
478 #[cfg(feature = "debug")]
479 let _scope = TraceScope::new("document::descend_path");
480 #[cfg(feature = "debug")]
481 trace(
482 &format!(
483 "path={:?}",
484 path.iter().map(|k| k.get()).collect::<Vec<_>>()
485 ),
486 anstyle::AnsiColor::Blue.on_default(),
487 );
488 for key in path.iter() {
489 #[cfg(feature = "debug")]
490 trace(
491 &format!("path[_]={key:?}"),
492 anstyle::AnsiColor::Blue.on_default(),
493 );
494 table = match table.entry_format(key) {
495 crate::Entry::Vacant(entry) => {
496 let mut new_table = Table::new();
497 new_table.span = key.span();
498 new_table.set_implicit(true);
499 new_table.set_dotted(dotted);
500
501 entry.insert(Item::Table(new_table)).as_table_mut().unwrap()
502 }
503 crate::Entry::Occupied(entry) => {
504 match entry.into_mut() {
505 Item::ArrayOfTables(array) => {
506 debug_assert!(!array.is_empty());
507
508 let index = array.len() - 1;
509 let last_child = array.get_mut(index).unwrap();
510
511 last_child
512 }
513 Item::Table(sweet_child_of_mine) => {
514 if dotted && sweet_child_of_mine.is_implicit() {
515 sweet_child_of_mine.set_dotted(true);
519 }
520 let mixed_table_types = dotted && !sweet_child_of_mine.is_implicit();
524 if mixed_table_types {
525 #[cfg(feature = "debug")]
526 trace(
527 &format!("dotted={dotted}"),
528 anstyle::AnsiColor::Red.on_default(),
529 );
530 #[cfg(feature = "debug")]
531 trace(
532 &format!(
533 "sweet_child_of_mine.is_implicit={}",
534 sweet_child_of_mine.is_implicit()
535 ),
536 anstyle::AnsiColor::Red.on_default(),
537 );
538 let key_span = get_key_span(key).expect("all keys have spans");
539 errors.report_error(
540 ParseError::new("duplicate key").with_unexpected(key_span),
541 );
542 return None;
543 }
544 sweet_child_of_mine
545 }
546 Item::Value(existing) => {
547 let old_span = existing.span().expect("all items have spans");
548 let old_span =
549 toml_parser::Span::new_unchecked(old_span.start, old_span.end);
550 let key_span = get_key_span(key).expect("all keys have spans");
551 errors.report_error(
552 ParseError::new(format!(
553 "cannot extend value of type {} with a dotted key",
554 existing.type_name()
555 ))
556 .with_unexpected(key_span)
557 .with_context(old_span),
558 );
559 return None;
560 }
561 Item::None => unreachable!(),
562 }
563 }
564 };
565 }
566 Some(table)
567}
568
569fn get_key_span(key: &Key) -> Option<toml_parser::Span> {
570 key.as_repr()
571 .and_then(|r| r.span())
572 .map(|s| toml_parser::Span::new_unchecked(s.start, s.end))
573}