use serde_spanned::Spanned; use crate::alloc_prelude::*; use crate::de::parser::key::on_key; use crate::de::parser::prelude::*; use crate::de::parser::value::value; use crate::de::DeString; use crate::de::DeValue; use crate::de::{DeArray, DeTable}; use crate::map::Entry; /// ```bnf /// ;; TOML /// /// toml = expression *( newline expression ) /// /// expression = ( ( ws comment ) / /// ( ws keyval ws [ comment ] ) / /// ( ws table ws [ comment ] ) / /// ws ) /// ``` pub(crate) fn document<'i>( input: &mut Input<'_>, source: toml_parser::Source<'i>, errors: &mut dyn ErrorSink, ) -> Spanned> { #[cfg(feature = "debug")] let _scope = TraceScope::new("document::document"); let mut state = State::default(); while let Some(event) = input.next_token() { match event.kind() { EventKind::InlineTableOpen | EventKind::InlineTableClose | EventKind::ArrayOpen | EventKind::ArrayClose | EventKind::Scalar | EventKind::ValueSep | EventKind::Error | EventKind::KeySep | EventKind::KeyValSep | EventKind::StdTableClose | EventKind::ArrayTableClose => { #[cfg(feature = "debug")] trace( &format!("unexpected {event:?}"), anstyle::AnsiColor::Red.on_default(), ); continue; } EventKind::StdTableOpen | EventKind::ArrayTableOpen => { state.finish_table(errors); let header = on_table(event, input, source, errors); state.start_table(header, errors); } EventKind::SimpleKey => { let (path, key) = on_key(event, input, source, errors); let Some(key) = key else { break; }; let Some(next_event) = input.next_token() else { break; }; let keyval_event = if next_event.kind() == EventKind::Whitespace { let Some(next_event) = input.next_token() else { break; }; next_event } else { next_event }; if keyval_event.kind() != EventKind::KeyValSep { break; } if input .first() .map(|e| e.kind() == EventKind::Whitespace) .unwrap_or(false) { let _ = input.next_token(); } let value = value(input, source, errors); state.capture_key_value(path, key, value, errors); } EventKind::Whitespace | EventKind::Comment | EventKind::Newline => { state.capture_trailing(event); } } } state.finish_table(errors); let span = Default::default(); Spanned::new(span, state.root) } /// ```bnf /// ;; Standard Table /// /// std-table = std-table-open key *( table-key-sep key) std-table-close /// /// ;; Array Table /// /// array-table = array-table-open key *( table-key-sep key) array-table-close /// ``` fn on_table<'i>( open_event: &toml_parser::parser::Event, input: &mut Input<'_>, source: toml_parser::Source<'i>, errors: &mut dyn ErrorSink, ) -> TableHeader<'i> { #[cfg(feature = "debug")] let _scope = TraceScope::new("document::on_table"); let is_array = open_event.kind() == EventKind::ArrayTableOpen; let mut current_path = None; let mut current_key = None; let mut current_span = open_event.span(); let mut current_prefix = None; let mut current_suffix = None; while let Some(event) = input.next_token() { match event.kind() { EventKind::InlineTableOpen | EventKind::InlineTableClose | EventKind::ArrayOpen | EventKind::ArrayClose | EventKind::Scalar | EventKind::ValueSep | EventKind::Error | EventKind::KeySep | EventKind::KeyValSep | EventKind::StdTableOpen | EventKind::ArrayTableOpen | EventKind::Comment | EventKind::Newline => { #[cfg(feature = "debug")] trace( &format!("unexpected {event:?}"), anstyle::AnsiColor::Red.on_default(), ); continue; } EventKind::ArrayTableClose | EventKind::StdTableClose => { current_span = current_span.append(event.span()); break; } EventKind::SimpleKey => { current_prefix.get_or_insert_with(|| event.span().before()); let (path, key) = on_key(event, input, source, errors); current_path = Some(path); current_key = key; current_suffix.get_or_insert_with(|| event.span().after()); } EventKind::Whitespace => { if current_key.is_some() { current_suffix = Some(event.span()); } else { current_prefix = Some(event.span()); } } } } TableHeader { path: current_path.unwrap_or_default(), key: current_key, span: current_span, is_array, } } struct TableHeader<'i> { path: Vec>>, key: Option>>, span: toml_parser::Span, is_array: bool, } #[derive(Default)] struct State<'i> { root: DeTable<'i>, current_table: DeTable<'i>, current_header: Option>, current_position: usize, } impl<'i> State<'i> { fn capture_trailing(&mut self, _event: &toml_parser::parser::Event) {} fn capture_key_value( &mut self, path: Vec>>, key: Spanned>, value: Spanned>, errors: &mut dyn ErrorSink, ) { #[cfg(feature = "debug")] let _scope = TraceScope::new("document::capture_key_value"); #[cfg(feature = "debug")] trace( &format!( "path={:?}", path.iter().map(|k| k.get_ref()).collect::>() ), anstyle::AnsiColor::Blue.on_default(), ); #[cfg(feature = "debug")] trace( &format!("key={key}",), anstyle::AnsiColor::Blue.on_default(), ); #[cfg(feature = "debug")] trace( &format!("value={value:?}",), anstyle::AnsiColor::Blue.on_default(), ); let dotted = true; let Some(parent_table) = descend_path(&mut self.current_table, &path, dotted, errors) else { return; }; // "Likewise, using dotted keys to redefine tables already defined in [table] form is not allowed" let mixed_table_types = parent_table.is_dotted() == path.is_empty(); if mixed_table_types { let key_span = get_key_span(&key); errors.report_error(ParseError::new("duplicate key").with_unexpected(key_span)); return; } let key_span = get_key_span(&key); match parent_table.entry(key) { Entry::Vacant(o) => { o.insert(value); } Entry::Occupied(existing) => { // "Since tables cannot be defined more than once, redefining such tables using a [table] header is not allowed" let old_span = get_key_span(existing.key()); errors.report_error( ParseError::new("duplicate key") .with_unexpected(key_span) .with_context(old_span), ); } } } fn finish_table(&mut self, errors: &mut dyn ErrorSink) { #[cfg(feature = "debug")] let _scope = TraceScope::new("document::finish_table"); let prev_table = core::mem::take(&mut self.current_table); if let Some(header) = self.current_header.take() { let Some(key) = &header.key else { return; }; let header_span = header.span.start()..header.span.end(); let prev_table = Spanned::new(header_span.clone(), DeValue::Table(prev_table)); let parent_key = &header.path; let dotted = false; let Some(parent_table) = descend_path(&mut self.root, parent_key, dotted, errors) else { return; }; #[cfg(feature = "debug")] trace( &format!("key={key}",), anstyle::AnsiColor::Blue.on_default(), ); if header.is_array { let entry = parent_table.entry(key.clone()).or_insert_with(|| { let mut array = DeArray::new(); array.set_array_of_tables(true); Spanned::new(header_span, DeValue::Array(array)) }); let Some(array) = entry .as_mut() .as_array_mut() .filter(|a| a.is_array_of_tables()) else { let key_span = get_key_span(key); let old_span = entry.span(); let old_span = toml_parser::Span::new_unchecked(old_span.start, old_span.end); errors.report_error( ParseError::new("duplicate key") .with_unexpected(key_span) .with_context(old_span), ); return; }; array.push(prev_table); } else { let existing = parent_table.insert(key.clone(), prev_table); debug_assert!(existing.is_none()); } } else { self.root = prev_table; } } fn start_table(&mut self, header: TableHeader<'i>, errors: &mut dyn ErrorSink) { if !header.is_array { // 1. Look up the table on start to ensure the duplicate_key error points to the right line // 2. Ensure any child tables from an implicit table are preserved let root = &mut self.root; if let (Some(parent_table), Some(key)) = (descend_path(root, &header.path, false, errors), &header.key) { if let Some((old_key, old_value)) = parent_table.remove_entry(key) { match old_value.into_inner() { DeValue::Table(t) if t.is_implicit() && !t.is_dotted() => { self.current_table = t; } // 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. old_value => { let old_span = get_key_span(&old_key); let key_span = get_key_span(key); errors.report_error( ParseError::new("duplicate key") .with_unexpected(key_span) .with_context(old_span), ); if let DeValue::Table(t) = old_value { self.current_table = t; } } } } } } self.current_position += 1; self.current_table.set_implicit(false); self.current_table.set_dotted(false); self.current_header = Some(header); } } fn descend_path<'t, 'i>( mut table: &'t mut DeTable<'i>, path: &[Spanned>], dotted: bool, errors: &mut dyn ErrorSink, ) -> Option<&'t mut DeTable<'i>> { #[cfg(feature = "debug")] let _scope = TraceScope::new("document::descend_path"); #[cfg(feature = "debug")] trace( &format!( "path={:?}", path.iter().map(|k| k.get_ref()).collect::>() ), anstyle::AnsiColor::Blue.on_default(), ); for key in path.iter() { table = match table.entry(key.clone()) { Entry::Vacant(entry) => { let mut new_table = DeTable::new(); new_table.set_implicit(true); new_table.set_dotted(dotted); let value = DeValue::Table(new_table); let value = Spanned::new(key.span(), value); let value = entry.insert(value); value.as_mut().as_table_mut().unwrap() } Entry::Occupied(entry) => { let spanned = entry.into_mut(); let old_span = spanned.span(); match spanned.as_mut() { DeValue::Array(ref mut array) => { if !array.is_array_of_tables() { let old_span = toml_parser::Span::new_unchecked(old_span.start, old_span.end); let key_span = get_key_span(key); errors.report_error( ParseError::new( "cannot extend value of type array with a dotted key", ) .with_unexpected(key_span) .with_context(old_span), ); return None; } debug_assert!(!array.is_empty()); let index = array.len() - 1; let last_child = array.get_mut(index).unwrap(); match last_child.as_mut() { DeValue::Table(table) => table, existing => { let old_span = toml_parser::Span::new_unchecked(old_span.start, old_span.end); let key_span = get_key_span(key); errors.report_error( ParseError::new(format!( "cannot extend value of type {} with a dotted key", existing.type_str() )) .with_unexpected(key_span) .with_context(old_span), ); return None; } } } DeValue::Table(ref mut sweet_child_of_mine) => { if sweet_child_of_mine.is_inline() { let key_span = get_key_span(key); errors.report_error( ParseError::new( "cannot extend value of type inline table with a dotted key", ) .with_unexpected(key_span), ); return None; } // 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. if dotted && !sweet_child_of_mine.is_implicit() { let key_span = get_key_span(key); errors.report_error( ParseError::new("duplicate key").with_unexpected(key_span), ); return None; } sweet_child_of_mine } existing => { let old_span = toml_parser::Span::new_unchecked(old_span.start, old_span.end); let key_span = get_key_span(key); errors.report_error( ParseError::new(format!( "cannot extend value of type {} with a dotted key", existing.type_str() )) .with_unexpected(key_span) .with_context(old_span), ); return None; } } } }; } Some(table) } fn get_key_span(key: &Spanned>) -> toml_parser::Span { let key_span = key.span(); toml_parser::Span::new_unchecked(key_span.start, key_span.end) }