1use crate::key::Key;
2use crate::parser::array::on_array;
3use crate::parser::key::on_key;
4use crate::parser::prelude::*;
5use crate::parser::value::on_scalar;
6use crate::repr::Decor;
7use crate::{InlineTable, Item, RawString, Value};
8
9use indexmap::map::Entry;
10
11pub(crate) fn on_inline_table(
17 open_event: &toml_parser::parser::Event,
18 input: &mut Input<'_>,
19 source: toml_parser::Source<'_>,
20 errors: &mut dyn ErrorSink,
21) -> Value {
22 #[cfg(feature = "debug")]
23 let _scope = TraceScope::new("inline_table::on_inline_table");
24 let mut result = InlineTable::new();
25 let mut close_span = open_event.span();
26
27 let mut state = State::default();
28 state.open(open_event);
29 while let Some(event) = input.next_token() {
30 close_span = event.span();
31 match event.kind() {
32 EventKind::StdTableOpen
33 | EventKind::ArrayTableOpen
34 | EventKind::StdTableClose
35 | EventKind::ArrayClose
36 | EventKind::ArrayTableClose
37 | EventKind::KeySep => {
38 #[cfg(feature = "debug")]
39 trace(
40 &format!("unexpected {event:?}"),
41 anstyle::AnsiColor::Red.on_default(),
42 );
43 break;
44 }
45 EventKind::Error => {
46 #[cfg(feature = "debug")]
47 trace(
48 &format!("unexpected {event:?}"),
49 anstyle::AnsiColor::Red.on_default(),
50 );
51 continue;
52 }
53 EventKind::SimpleKey => {
54 let (path, key) = on_key(event, input, source, errors);
55 state.capture_key(event, path, key);
56 }
57 EventKind::KeyValSep => {
58 state.finish_key(event);
59 }
60 EventKind::InlineTableOpen => {
61 let value = on_inline_table(event, input, source, errors);
62 state.capture_value(event, value);
63 }
64 EventKind::ArrayOpen => {
65 let value = on_array(event, input, source, errors);
66 state.capture_value(event, value);
67 }
68 EventKind::Scalar => {
69 let value = on_scalar(event, source, errors);
70 state.capture_value(event, value);
71 }
72 EventKind::ValueSep => {
73 state.finish_value(event, &mut result, errors);
74 state.sep_value(event);
75 }
76 EventKind::Whitespace | EventKind::Comment | EventKind::Newline => {
77 state.whitespace(event);
78 }
79 EventKind::InlineTableClose => {
80 state.finish_value(event, &mut result, errors);
81 state.close(open_event, event, &mut result);
82 break;
83 }
84 }
85 }
86 if result.span.is_none() {
87 result.span = Some(open_event.span().start()..close_span.end());
88 }
89
90 Value::InlineTable(result)
91}
92
93#[derive(Default)]
94struct State {
95 current_prefix: Option<toml_parser::Span>,
96 current_key: Option<(Vec<Key>, Key)>,
97 seen_keyval_sep: bool,
98 current_value: Option<Value>,
99 trailing_start: Option<usize>,
100 current_suffix: Option<toml_parser::Span>,
101}
102
103impl State {
104 fn open(&mut self, open_event: &toml_parser::parser::Event) {
105 self.trailing_start = Some(open_event.span().end());
106 }
107
108 fn whitespace(&mut self, event: &toml_parser::parser::Event) {
109 #[cfg(feature = "debug")]
110 let _scope = TraceScope::new("inline_table::whitespace");
111 let decor = if self.is_prefix() {
112 self.current_prefix.get_or_insert(event.span())
113 } else {
114 self.current_suffix.get_or_insert(event.span())
115 };
116 *decor = decor.append(event.span());
117 }
118
119 fn is_prefix(&self) -> bool {
120 if self.seen_keyval_sep {
121 self.current_value.is_none()
122 } else {
123 self.current_key.is_none()
124 }
125 }
126
127 fn capture_key(
128 &mut self,
129 event: &toml_parser::parser::Event,
130 path: Vec<Key>,
131 key: Option<Key>,
132 ) {
133 #[cfg(feature = "debug")]
134 let _scope = TraceScope::new("inline_table::capture_key");
135 self.trailing_start = None;
136 self.current_prefix
137 .get_or_insert_with(|| event.span().before());
138 if let Some(key) = key {
139 self.current_key = Some((path, key));
140 }
141 }
142
143 fn finish_key(&mut self, event: &toml_parser::parser::Event) {
144 #[cfg(feature = "debug")]
145 let _scope = TraceScope::new("inline_table::finish_key");
146 self.seen_keyval_sep = true;
147 if let Some(last_key) = self.current_key.as_mut().map(|(_, k)| k) {
148 let prefix = self
149 .current_prefix
150 .take()
151 .expect("setting a key should set a prefix");
152 let suffix = self
153 .current_suffix
154 .take()
155 .unwrap_or_else(|| event.span().before());
156 let prefix = RawString::with_span(prefix.start()..prefix.end());
157 let suffix = RawString::with_span(suffix.start()..suffix.end());
158 let leaf_decor = Decor::new(prefix, suffix);
159 *last_key.leaf_decor_mut() = leaf_decor;
160 }
161 }
162
163 fn capture_value(&mut self, event: &toml_parser::parser::Event, value: Value) {
164 #[cfg(feature = "debug")]
165 let _scope = TraceScope::new("inline_table::capture_value");
166 self.current_prefix
167 .get_or_insert_with(|| event.span().before());
168 self.current_value = Some(value);
169 }
170
171 fn finish_value(
172 &mut self,
173 event: &toml_parser::parser::Event,
174 result: &mut InlineTable,
175 errors: &mut dyn ErrorSink,
176 ) {
177 #[cfg(feature = "debug")]
178 let _scope = TraceScope::new("inline_table::finish_value");
179 self.seen_keyval_sep = false;
180 if let (Some((path, key)), Some(mut value)) =
181 (self.current_key.take(), self.current_value.take())
182 {
183 let prefix = self
184 .current_prefix
185 .take()
186 .expect("setting a value should set a prefix");
187 let suffix = self
188 .current_suffix
189 .take()
190 .unwrap_or_else(|| event.span().before());
191 let Some(table) = descend_path(result, &path, true, errors) else {
192 return;
193 };
194
195 let decor = value.decor_mut();
196 decor.set_prefix(RawString::with_span(prefix.start()..prefix.end()));
197 decor.set_suffix(RawString::with_span(suffix.start()..suffix.end()));
198
199 let mixed_table_types = table.is_dotted() == path.is_empty();
201 if mixed_table_types {
202 #[cfg(feature = "debug")]
203 trace(
204 &format!("table.dotted={}", table.is_dotted()),
205 anstyle::AnsiColor::Red.on_default(),
206 );
207 #[cfg(feature = "debug")]
208 trace(
209 &format!("path.is_empty={}", path.is_empty()),
210 anstyle::AnsiColor::Red.on_default(),
211 );
212 let key_span = get_key_span(&key).unwrap_or_else(|| event.span());
213 errors.report_error(ParseError::new("duplicate key").with_unexpected(key_span));
214 } else {
215 let key_span = get_key_span(&key).unwrap_or_else(|| event.span());
216 match table.items.entry(key) {
217 Entry::Vacant(o) => {
218 o.insert(Item::Value(value));
219 }
220 Entry::Occupied(o) => {
221 let old_span = get_key_span(o.key()).unwrap_or_else(|| event.span());
222 errors.report_error(
223 ParseError::new("duplicate key")
224 .with_unexpected(key_span)
225 .with_context(old_span),
226 );
227 }
228 }
229 }
230 }
231 }
232
233 fn sep_value(&mut self, event: &toml_parser::parser::Event) {
234 self.trailing_start = Some(event.span().end());
235 }
236
237 fn close(
238 &mut self,
239 open_event: &toml_parser::parser::Event,
240 close_event: &toml_parser::parser::Event,
241 result: &mut InlineTable,
242 ) {
243 #[cfg(feature = "debug")]
244 let _scope = TraceScope::new("inline_table::close");
245 let trailing_comma = self.trailing_start.is_some() && !result.is_empty();
246 let span = open_event.span().append(close_event.span());
247 let trailing_start = self
248 .trailing_start
249 .unwrap_or_else(|| close_event.span().start());
250 let trailing_end = close_event.span().start();
251
252 result.set_trailing_comma(trailing_comma);
253 result.set_trailing(RawString::with_span(trailing_start..trailing_end));
254 result.span = Some(span.start()..span.end());
255 }
256}
257
258fn descend_path<'a>(
259 mut table: &'a mut InlineTable,
260 path: &'a [Key],
261 dotted: bool,
262 errors: &mut dyn ErrorSink,
263) -> Option<&'a mut InlineTable> {
264 #[cfg(feature = "debug")]
265 let _scope = TraceScope::new("inline_table::descend_path");
266 #[cfg(feature = "debug")]
267 trace(
268 &format!(
269 "path={:?}",
270 path.iter().map(|k| k.get()).collect::<Vec<_>>()
271 ),
272 anstyle::AnsiColor::Blue.on_default(),
273 );
274 for key in path.iter() {
275 #[cfg(feature = "debug")]
276 trace(
277 &format!("path[_]={key:?}"),
278 anstyle::AnsiColor::Blue.on_default(),
279 );
280 table = match table.entry_format(key) {
281 crate::InlineEntry::Vacant(entry) => {
282 let mut new_table = InlineTable::new();
283 new_table.span = key.span();
284 new_table.set_implicit(true);
285 new_table.set_dotted(dotted);
286 entry
287 .insert(Value::InlineTable(new_table))
288 .as_inline_table_mut()
289 .unwrap()
290 }
291 crate::InlineEntry::Occupied(entry) => {
292 match entry.into_mut() {
293 Value::InlineTable(sweet_child_of_mine) => {
294 let mixed_table_types = dotted && !sweet_child_of_mine.is_implicit();
298 if mixed_table_types {
299 #[cfg(feature = "debug")]
300 trace(
301 &format!("dotted={dotted}"),
302 anstyle::AnsiColor::Red.on_default(),
303 );
304 #[cfg(feature = "debug")]
305 trace(
306 &format!(
307 "sweet_child_of_mine.is_implicit={}",
308 sweet_child_of_mine.is_implicit()
309 ),
310 anstyle::AnsiColor::Red.on_default(),
311 );
312 let key_span = get_key_span(key).expect("all keys have spans");
313 errors.report_error(
314 ParseError::new("duplicate key").with_unexpected(key_span),
315 );
316 return None;
317 }
318 sweet_child_of_mine
319 }
320 existing => {
321 let key_span = get_key_span(key).expect("all keys have spans");
322 errors.report_error(
323 ParseError::new(format!(
324 "cannot extend value of type {} with a dotted key",
325 existing.type_name()
326 ))
327 .with_unexpected(key_span),
328 );
329 return None;
330 }
331 }
332 }
333 };
334 }
335 Some(table)
336}
337
338fn get_key_span(key: &Key) -> Option<toml_parser::Span> {
339 key.as_repr()
340 .and_then(|r| r.span())
341 .map(|s| toml_parser::Span::new_unchecked(s.start, s.end))
342}