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