Skip to main content

toml_parser/parser/
document.rs

1use winnow::stream::Offset as _;
2use winnow::stream::Stream as _;
3use winnow::stream::TokenSlice;
4
5use super::EventReceiver;
6use crate::ErrorSink;
7use crate::Expected;
8use crate::ParseError;
9#[cfg(feature = "debug")]
10use crate::debug::DebugErrorSink;
11#[cfg(feature = "debug")]
12use crate::debug::DebugEventReceiver;
13use crate::decoder::Encoding;
14use crate::lexer::Token;
15use crate::lexer::TokenKind;
16
17/// Parse lexed tokens into [`Event`][super::Event]s
18pub fn parse_document(
19    tokens: &[Token],
20    receiver: &mut dyn EventReceiver,
21    error: &mut dyn ErrorSink,
22) {
23    let mut tokens = TokenSlice::new(tokens);
24    #[cfg(feature = "debug")]
25    let mut receiver = DebugEventReceiver::new(receiver);
26    #[cfg(feature = "debug")]
27    let receiver = &mut receiver;
28    #[cfg(feature = "debug")]
29    let mut error = DebugErrorSink::new(error);
30    #[cfg(feature = "debug")]
31    let error = &mut error;
32    document(&mut tokens, receiver, error);
33    eof(&mut tokens, receiver, error);
34}
35
36/// Parse lexed tokens into [`Event`][super::Event]s
37pub fn parse_key(tokens: &[Token], receiver: &mut dyn EventReceiver, error: &mut dyn ErrorSink) {
38    let mut tokens = TokenSlice::new(tokens);
39    #[cfg(feature = "debug")]
40    let mut receiver = DebugEventReceiver::new(receiver);
41    #[cfg(feature = "debug")]
42    let receiver = &mut receiver;
43    #[cfg(feature = "debug")]
44    let mut error = DebugErrorSink::new(error);
45    #[cfg(feature = "debug")]
46    let error = &mut error;
47    key(&mut tokens, "invalid key", receiver, error);
48    eof(&mut tokens, receiver, error);
49}
50
51/// Parse lexed tokens into [`Event`][super::Event]s
52pub fn parse_simple_key(
53    tokens: &[Token],
54    receiver: &mut dyn EventReceiver,
55    error: &mut dyn ErrorSink,
56) {
57    let mut tokens = TokenSlice::new(tokens);
58    #[cfg(feature = "debug")]
59    let mut receiver = DebugEventReceiver::new(receiver);
60    #[cfg(feature = "debug")]
61    let receiver = &mut receiver;
62    #[cfg(feature = "debug")]
63    let mut error = DebugErrorSink::new(error);
64    #[cfg(feature = "debug")]
65    let error = &mut error;
66    simple_key(&mut tokens, "invalid key", receiver, error);
67    eof(&mut tokens, receiver, error);
68}
69
70/// Parse lexed tokens into [`Event`][super::Event]s
71pub fn parse_value(tokens: &[Token], receiver: &mut dyn EventReceiver, error: &mut dyn ErrorSink) {
72    let mut tokens = TokenSlice::new(tokens);
73    #[cfg(feature = "debug")]
74    let mut receiver = DebugEventReceiver::new(receiver);
75    #[cfg(feature = "debug")]
76    let receiver = &mut receiver;
77    #[cfg(feature = "debug")]
78    let mut error = DebugErrorSink::new(error);
79    #[cfg(feature = "debug")]
80    let error = &mut error;
81    value(&mut tokens, receiver, error);
82    eof(&mut tokens, receiver, error);
83}
84
85type Stream<'i> = TokenSlice<'i, Token>;
86
87/// Parse a TOML Document
88///
89/// Only the order of [`Event`][super::Event]s is validated and not [`Event`][super::Event] content nor semantics like duplicate
90/// keys.
91///
92/// ```abnf
93/// toml = expression *( newline expression )
94///
95/// expression =  ws [ comment ]
96/// expression =/ ws keyval ws [ comment ]
97/// expression =/ ws table ws [ comment ]
98///
99/// ;; Key-Value pairs
100///
101/// keyval = key keyval-sep val
102/// key = simple-key / dotted-key
103/// val = string / boolean / array / inline-table / date-time / float / integer
104///
105/// simple-key = quoted-key / unquoted-key
106///
107/// ;; Quoted and dotted key
108///
109/// quoted-key = basic-string / literal-string
110/// dotted-key = simple-key 1*( dot-sep simple-key )
111///
112/// dot-sep   = ws %x2E ws  ; . Period
113/// keyval-sep = ws %x3D ws ; =
114///
115/// ;; Array
116///
117/// array = array-open [ array-values ] ws-comment-newline array-close
118///
119/// array-open =  %x5B ; [
120/// array-close = %x5D ; ]
121///
122/// array-values =  ws-comment-newline val ws-comment-newline array-sep array-values
123/// array-values =/ ws-comment-newline val ws-comment-newline [ array-sep ]
124///
125/// array-sep = %x2C  ; , Comma
126///
127/// ;; Table
128///
129/// table = std-table / array-table
130///
131/// ;; Standard Table
132///
133/// std-table = std-table-open key std-table-close
134///
135/// ;; Inline Table
136///
137/// inline-table = inline-table-open [ inline-table-keyvals ] ws-comment-newline inline-table-close
138///
139/// inline-table-keyvals =  ws-comment-newline keyval ws-comment-newline inline-table-sep inline-table-keyvals
140/// inline-table-keyvals =/ ws-comment-newline keyval ws-comment-newline [ inline-table-sep ]
141///
142/// ;; Array Table
143///
144/// array-table = array-table-open key array-table-close
145/// ```
146fn document(tokens: &mut Stream<'_>, receiver: &mut dyn EventReceiver, error: &mut dyn ErrorSink) {
147    while let Some(current_token) = tokens.next_token() {
148        match current_token.kind() {
149            TokenKind::LeftSquareBracket => on_table(tokens, current_token, receiver, error),
150            TokenKind::RightSquareBracket => {
151                on_missing_std_table(tokens, current_token, receiver, error);
152            }
153            TokenKind::LiteralString => on_expression_key(
154                tokens,
155                current_token,
156                Some(Encoding::LiteralString),
157                receiver,
158                error,
159            ),
160            TokenKind::BasicString => on_expression_key(
161                tokens,
162                current_token,
163                Some(Encoding::BasicString),
164                receiver,
165                error,
166            ),
167            TokenKind::MlLiteralString => on_expression_key(
168                tokens,
169                current_token,
170                Some(Encoding::MlLiteralString),
171                receiver,
172                error,
173            ),
174            TokenKind::MlBasicString => on_expression_key(
175                tokens,
176                current_token,
177                Some(Encoding::MlBasicString),
178                receiver,
179                error,
180            ),
181            TokenKind::Atom => on_expression_key(tokens, current_token, None, receiver, error),
182            TokenKind::Equals => {
183                let fake_key = current_token.span().before();
184                let encoding = None;
185                receiver.simple_key(fake_key, encoding, error);
186                on_expression_key_val_sep(tokens, current_token, receiver, error);
187            }
188            TokenKind::Dot => {
189                on_expression_dot(tokens, current_token, receiver, error);
190            }
191            TokenKind::Comma | TokenKind::RightCurlyBracket | TokenKind::LeftCurlyBracket => {
192                on_missing_expression_key(tokens, current_token, receiver, error);
193            }
194            TokenKind::Whitespace => receiver.whitespace(current_token.span(), error),
195            TokenKind::Newline => receiver.newline(current_token.span(), error),
196            TokenKind::Comment => on_comment(tokens, current_token, receiver, error),
197            TokenKind::Eof => {
198                break;
199            }
200        }
201    }
202}
203
204/// Start a table from the open token
205///
206/// This eats to EOL
207///
208/// ```abnf
209/// ;; Table
210///
211/// table = std-table / array-table
212///
213/// ;; Standard Table
214///
215/// std-table = std-table-open key std-table-close
216///
217/// ;; Array Table
218///
219/// array-table = array-table-open key array-table-close
220/// ```
221fn on_table(
222    tokens: &mut Stream<'_>,
223    open_token: &Token,
224    receiver: &mut dyn EventReceiver,
225    error: &mut dyn ErrorSink,
226) {
227    let is_array_table = if let Some(second_open_token) =
228        next_token_if(tokens, |k| matches!(k, TokenKind::LeftSquareBracket))
229    {
230        let span = open_token.span().append(second_open_token.span());
231        receiver.array_table_open(span, error);
232        true
233    } else {
234        let span = open_token.span();
235        receiver.std_table_open(span, error);
236        false
237    };
238
239    opt_whitespace(tokens, receiver, error);
240
241    let valid_key = key(tokens, "invalid table", receiver, error);
242
243    opt_whitespace(tokens, receiver, error);
244
245    let mut success = false;
246    if let Some(close_token) = next_token_if(tokens, |k| matches!(k, TokenKind::RightSquareBracket))
247    {
248        if is_array_table {
249            if let Some(second_close_token) =
250                next_token_if(tokens, |k| matches!(k, TokenKind::RightSquareBracket))
251            {
252                let span = close_token.span().append(second_close_token.span());
253                receiver.array_table_close(span, error);
254                success = true;
255            } else {
256                let context = open_token.span().append(close_token.span());
257                error.report_error(
258                    ParseError::new("unclosed array table")
259                        .with_context(context)
260                        .with_expected(&[Expected::Literal("]")])
261                        .with_unexpected(close_token.span().after()),
262                );
263            }
264        } else {
265            receiver.std_table_close(close_token.span(), error);
266            success = true;
267        }
268    } else if valid_key {
269        let last_key_token = tokens
270            .previous_tokens()
271            .find(|t| t.kind() != TokenKind::Whitespace)
272            .unwrap_or(open_token);
273        let context = open_token.span().append(last_key_token.span());
274        if is_array_table {
275            error.report_error(
276                ParseError::new("unclosed array table")
277                    .with_context(context)
278                    .with_expected(&[Expected::Literal("]]")])
279                    .with_unexpected(last_key_token.span().after()),
280            );
281        } else {
282            error.report_error(
283                ParseError::new("unclosed table")
284                    .with_context(context)
285                    .with_expected(&[Expected::Literal("]")])
286                    .with_unexpected(last_key_token.span().after()),
287            );
288        }
289    }
290
291    if success {
292        ws_comment_newline(tokens, receiver, error);
293    } else {
294        ignore_to_newline(tokens, receiver, error);
295    }
296}
297
298/// Parse a TOML key
299///
300/// ```abnf
301/// ;; Key-Value pairs
302///
303/// key = simple-key / dotted-key
304///
305/// simple-key = quoted-key / unquoted-key
306///
307/// ;; Quoted and dotted key
308///
309/// quoted-key = basic-string / literal-string
310/// dotted-key = simple-key 1*( dot-sep simple-key )
311///
312/// dot-sep   = ws %x2E ws  ; . Period
313/// ```
314fn key(
315    tokens: &mut Stream<'_>,
316    invalid_description: &'static str,
317    receiver: &mut dyn EventReceiver,
318    error: &mut dyn ErrorSink,
319) -> bool {
320    while let Some(current_token) = tokens.next_token() {
321        let encoding = match current_token.kind() {
322            TokenKind::RightSquareBracket
323            | TokenKind::Comment
324            | TokenKind::Equals
325            | TokenKind::Comma
326            | TokenKind::LeftSquareBracket
327            | TokenKind::LeftCurlyBracket
328            | TokenKind::RightCurlyBracket
329            | TokenKind::Newline
330            | TokenKind::Eof => {
331                let fake_key = current_token.span().before();
332                let encoding = None;
333                receiver.simple_key(fake_key, encoding, error);
334                seek(tokens, -1);
335                return false;
336            }
337            TokenKind::Whitespace => {
338                receiver.whitespace(current_token.span(), error);
339                continue;
340            }
341            TokenKind::Dot => {
342                let fake_key = current_token.span().before();
343                let encoding = None;
344                receiver.simple_key(fake_key, encoding, error);
345                receiver.key_sep(current_token.span(), error);
346                continue;
347            }
348            TokenKind::LiteralString => Some(Encoding::LiteralString),
349            TokenKind::BasicString => Some(Encoding::BasicString),
350            TokenKind::MlLiteralString => Some(Encoding::MlLiteralString),
351            TokenKind::MlBasicString => Some(Encoding::MlBasicString),
352            TokenKind::Atom => None,
353        };
354        receiver.simple_key(current_token.span(), encoding, error);
355        return opt_dot_keys(tokens, receiver, error);
356    }
357
358    let previous_span = tokens
359        .previous_tokens()
360        .find(|t| {
361            !matches!(
362                t.kind(),
363                TokenKind::Whitespace | TokenKind::Comment | TokenKind::Newline | TokenKind::Eof
364            )
365        })
366        .map(|t| t.span())
367        .unwrap_or_default();
368    error.report_error(
369        ParseError::new(invalid_description)
370            .with_context(previous_span)
371            .with_expected(&[Expected::Description("key")])
372            .with_unexpected(previous_span.after()),
373    );
374    false
375}
376
377/// Start an expression from a key compatible token  type
378///
379/// ```abnf
380/// expression =  ws [ comment ]
381/// expression =/ ws keyval ws [ comment ]
382/// expression =/ ws table ws [ comment ]
383///
384/// ;; Key-Value pairs
385///
386/// keyval = key keyval-sep val
387/// ```
388fn on_expression_key<'i>(
389    tokens: &mut Stream<'i>,
390    key_token: &'i Token,
391    encoding: Option<Encoding>,
392    receiver: &mut dyn EventReceiver,
393    error: &mut dyn ErrorSink,
394) {
395    receiver.simple_key(key_token.span(), encoding, error);
396    opt_dot_keys(tokens, receiver, error);
397
398    opt_whitespace(tokens, receiver, error);
399
400    let Some(eq_token) = next_token_if(tokens, |k| matches!(k, TokenKind::Equals)) else {
401        if let Some(peek_token) = tokens.first() {
402            let span = peek_token.span().before();
403            error.report_error(
404                ParseError::new("key with no value")
405                    .with_context(span)
406                    .with_expected(&[Expected::Literal("=")])
407                    .with_unexpected(span),
408            );
409        }
410        ignore_to_newline(tokens, receiver, error);
411        return;
412    };
413    on_expression_key_val_sep(tokens, eq_token, receiver, error);
414}
415
416fn on_expression_dot<'i>(
417    tokens: &mut Stream<'i>,
418    dot_token: &'i Token,
419    receiver: &mut dyn EventReceiver,
420    error: &mut dyn ErrorSink,
421) {
422    receiver.simple_key(dot_token.span().before(), None, error);
423    seek(tokens, -1);
424    opt_dot_keys(tokens, receiver, error);
425
426    opt_whitespace(tokens, receiver, error);
427
428    let Some(eq_token) = next_token_if(tokens, |k| matches!(k, TokenKind::Equals)) else {
429        if let Some(peek_token) = tokens.first() {
430            let span = peek_token.span().before();
431            error.report_error(
432                ParseError::new("missing value for key")
433                    .with_context(span)
434                    .with_expected(&[Expected::Literal("=")])
435                    .with_unexpected(span),
436            );
437        }
438        ignore_to_newline(tokens, receiver, error);
439        return;
440    };
441    on_expression_key_val_sep(tokens, eq_token, receiver, error);
442}
443
444fn on_expression_key_val_sep<'i>(
445    tokens: &mut Stream<'i>,
446    eq_token: &'i Token,
447    receiver: &mut dyn EventReceiver,
448    error: &mut dyn ErrorSink,
449) {
450    receiver.key_val_sep(eq_token.span(), error);
451
452    opt_whitespace(tokens, receiver, error);
453
454    value(tokens, receiver, error);
455
456    ws_comment_newline(tokens, receiver, error);
457}
458
459/// Parse a TOML simple key
460///
461/// ```abnf
462/// ;; Key-Value pairs
463///
464/// simple-key = quoted-key / unquoted-key
465///
466/// ;; Quoted and dotted key
467///
468/// quoted-key = basic-string / literal-string
469/// ```
470fn simple_key(
471    tokens: &mut Stream<'_>,
472    invalid_description: &'static str,
473    receiver: &mut dyn EventReceiver,
474    error: &mut dyn ErrorSink,
475) {
476    let Some(current_token) = tokens.next_token() else {
477        let previous_span = tokens
478            .previous_tokens()
479            .find(|t| {
480                !matches!(
481                    t.kind(),
482                    TokenKind::Whitespace
483                        | TokenKind::Comment
484                        | TokenKind::Newline
485                        | TokenKind::Eof
486                )
487            })
488            .map(|t| t.span())
489            .unwrap_or_default();
490        error.report_error(
491            ParseError::new(invalid_description)
492                .with_context(previous_span)
493                .with_expected(&[Expected::Description("key")])
494                .with_unexpected(previous_span.after()),
495        );
496        return;
497    };
498
499    const EXPECTED_KEYS: [Expected; 3] = [
500        Expected::Description(Encoding::LiteralString.description()),
501        Expected::Description(Encoding::BasicString.description()),
502        Expected::Description(UNQUOTED_STRING),
503    ];
504
505    let kind = match current_token.kind() {
506        TokenKind::Dot
507        | TokenKind::RightSquareBracket
508        | TokenKind::Comment
509        | TokenKind::Equals
510        | TokenKind::Comma
511        | TokenKind::LeftSquareBracket
512        | TokenKind::LeftCurlyBracket
513        | TokenKind::RightCurlyBracket
514        | TokenKind::Newline
515        | TokenKind::Eof
516        | TokenKind::Whitespace => {
517            on_missing_key(tokens, current_token, invalid_description, receiver, error);
518            return;
519        }
520        TokenKind::LiteralString => Some(Encoding::LiteralString),
521        TokenKind::BasicString => Some(Encoding::BasicString),
522        TokenKind::MlLiteralString => {
523            error.report_error(
524                ParseError::new(invalid_description)
525                    .with_context(current_token.span())
526                    .with_expected(&EXPECTED_KEYS)
527                    .with_unexpected(current_token.span()),
528            );
529            Some(Encoding::MlLiteralString)
530        }
531        TokenKind::MlBasicString => {
532            error.report_error(
533                ParseError::new(invalid_description)
534                    .with_context(current_token.span())
535                    .with_expected(&EXPECTED_KEYS)
536                    .with_unexpected(current_token.span()),
537            );
538            Some(Encoding::MlBasicString)
539        }
540        TokenKind::Atom => None,
541    };
542    receiver.simple_key(current_token.span(), kind, error);
543}
544
545/// Start a key from the first key compatible token type
546///
547/// Returns the last key on success
548///
549/// This will swallow the trailing [`TokenKind::Whitespace`]
550///
551/// ```abnf
552/// key = simple-key / dotted-key
553///
554/// simple-key = quoted-key / unquoted-key
555///
556/// ;; Quoted and dotted key
557///
558/// quoted-key = basic-string / literal-string
559/// dotted-key = simple-key 1*( dot-sep simple-key )
560///
561/// dot-sep   = ws %x2E ws  ; . Period
562/// ```
563fn opt_dot_keys(
564    tokens: &mut Stream<'_>,
565    receiver: &mut dyn EventReceiver,
566    error: &mut dyn ErrorSink,
567) -> bool {
568    opt_whitespace(tokens, receiver, error);
569
570    let mut success = true;
571    'dot: while let Some(dot_token) = next_token_if(tokens, |k| matches!(k, TokenKind::Dot)) {
572        receiver.key_sep(dot_token.span(), error);
573
574        while let Some(current_token) = tokens.next_token() {
575            let kind = match current_token.kind() {
576                TokenKind::Equals
577                | TokenKind::Comma
578                | TokenKind::LeftSquareBracket
579                | TokenKind::RightSquareBracket
580                | TokenKind::LeftCurlyBracket
581                | TokenKind::RightCurlyBracket
582                | TokenKind::Comment
583                | TokenKind::Newline
584                | TokenKind::Eof => {
585                    let fake_key = current_token.span().before();
586                    let encoding = None;
587                    receiver.simple_key(fake_key, encoding, error);
588                    seek(tokens, -1);
589
590                    success = false;
591                    break 'dot;
592                }
593                TokenKind::Whitespace => {
594                    receiver.whitespace(current_token.span(), error);
595                    continue;
596                }
597                TokenKind::Dot => {
598                    let fake_key = current_token.span().before();
599                    let encoding = None;
600                    receiver.simple_key(fake_key, encoding, error);
601                    receiver.key_sep(current_token.span(), error);
602                    continue;
603                }
604                TokenKind::LiteralString => Some(Encoding::LiteralString),
605                TokenKind::BasicString => Some(Encoding::BasicString),
606                TokenKind::MlLiteralString => Some(Encoding::MlLiteralString),
607                TokenKind::MlBasicString => Some(Encoding::MlBasicString),
608                TokenKind::Atom => None,
609            };
610            receiver.simple_key(current_token.span(), kind, error);
611            opt_whitespace(tokens, receiver, error);
612            continue 'dot;
613        }
614
615        let fake_key = dot_token.span().after();
616        let encoding = None;
617        receiver.simple_key(fake_key, encoding, error);
618    }
619
620    success
621}
622
623/// Parse a value
624///
625/// ```abnf
626/// val = string / boolean / array / inline-table / date-time / float / integer
627/// ```
628fn value(tokens: &mut Stream<'_>, receiver: &mut dyn EventReceiver, error: &mut dyn ErrorSink) {
629    // Skip extra `=` tokens.
630    let current_token = loop {
631        let Some(current_token) = tokens.next_token() else {
632            let previous_span = tokens
633                .previous_tokens()
634                .find(|t| {
635                    !matches!(
636                        t.kind(),
637                        TokenKind::Whitespace
638                            | TokenKind::Comment
639                            | TokenKind::Newline
640                            | TokenKind::Eof
641                    )
642                })
643                .map(|t| t.span())
644                .unwrap_or_default();
645            error.report_error(
646                ParseError::new("missing value")
647                    .with_context(previous_span)
648                    .with_expected(&[Expected::Description("value")])
649                    .with_unexpected(previous_span.after()),
650            );
651            return;
652        };
653        if current_token.kind() != TokenKind::Equals {
654            break current_token;
655        }
656        error.report_error(
657            ParseError::new("extra `=`")
658                .with_context(current_token.span())
659                .with_expected(&[])
660                .with_unexpected(current_token.span()),
661        );
662        receiver.error(current_token.span(), error);
663    };
664
665    match current_token.kind() {
666        TokenKind::Comment
667        | TokenKind::Comma
668        | TokenKind::Newline
669        | TokenKind::Eof
670        | TokenKind::Whitespace => {
671            let fake_key = current_token.span().before();
672            let encoding = None;
673            receiver.scalar(fake_key, encoding, error);
674            seek(tokens, -1);
675        }
676        // Handled by the while loop above
677        TokenKind::Equals => unreachable!(),
678        TokenKind::LeftCurlyBracket => {
679            on_inline_table_open(tokens, current_token, receiver, error);
680        }
681        TokenKind::RightCurlyBracket => {
682            error.report_error(
683                ParseError::new("missing inline table opening")
684                    .with_context(current_token.span())
685                    .with_expected(&[Expected::Literal("{")])
686                    .with_unexpected(current_token.span().before()),
687            );
688
689            let _ = receiver.inline_table_open(current_token.span().before(), error);
690            receiver.inline_table_close(current_token.span(), error);
691        }
692        TokenKind::LeftSquareBracket => {
693            on_array_open(tokens, current_token, receiver, error);
694        }
695        TokenKind::RightSquareBracket => {
696            error.report_error(
697                ParseError::new("missing array opening")
698                    .with_context(current_token.span())
699                    .with_expected(&[Expected::Literal("[")])
700                    .with_unexpected(current_token.span().before()),
701            );
702
703            let _ = receiver.array_open(current_token.span().before(), error);
704            receiver.array_close(current_token.span(), error);
705        }
706        TokenKind::LiteralString
707        | TokenKind::BasicString
708        | TokenKind::MlLiteralString
709        | TokenKind::MlBasicString
710        | TokenKind::Dot
711        | TokenKind::Atom => {
712            on_scalar(tokens, current_token, receiver, error);
713        }
714    }
715}
716
717/// Parse a scalar value
718///
719/// ```abnf
720/// val = string / boolean / array / inline-table / date-time / float / integer
721/// ```
722fn on_scalar(
723    tokens: &mut Stream<'_>,
724    scalar: &Token,
725    receiver: &mut dyn EventReceiver,
726    error: &mut dyn ErrorSink,
727) {
728    let mut span = scalar.span();
729    let encoding = match scalar.kind() {
730        TokenKind::Comment
731        | TokenKind::Comma
732        | TokenKind::Newline
733        | TokenKind::Eof
734        | TokenKind::Whitespace
735        | TokenKind::Equals
736        | TokenKind::LeftCurlyBracket
737        | TokenKind::RightCurlyBracket
738        | TokenKind::LeftSquareBracket
739        | TokenKind::RightSquareBracket => {
740            unreachable!()
741        }
742        TokenKind::LiteralString => Some(Encoding::LiteralString),
743        TokenKind::BasicString => Some(Encoding::BasicString),
744        TokenKind::MlLiteralString => Some(Encoding::MlLiteralString),
745        TokenKind::MlBasicString => Some(Encoding::MlBasicString),
746        TokenKind::Dot | TokenKind::Atom => {
747            while let Some(next_token) = tokens.first() {
748                match next_token.kind() {
749                    TokenKind::Comment
750                    | TokenKind::Comma
751                    | TokenKind::Newline
752                    | TokenKind::Eof
753                    | TokenKind::Equals
754                    | TokenKind::LeftCurlyBracket
755                    | TokenKind::RightCurlyBracket
756                    | TokenKind::LeftSquareBracket
757                    | TokenKind::RightSquareBracket
758                    | TokenKind::LiteralString
759                    | TokenKind::BasicString
760                    | TokenKind::MlLiteralString
761                    | TokenKind::MlBasicString => {
762                        break;
763                    }
764                    TokenKind::Whitespace => {
765                        if let Some(second) = tokens.get(1) {
766                            if second.kind() == TokenKind::Atom {
767                                span = span.append(second.span());
768                                let _ = tokens.next_slice(2);
769                                continue;
770                            }
771                        }
772                        break;
773                    }
774                    TokenKind::Dot | TokenKind::Atom => {
775                        span = span.append(next_token.span());
776                        let _ = tokens.next_token();
777                    }
778                }
779            }
780            None
781        }
782    };
783    receiver.scalar(span, encoding, error);
784}
785
786/// Parse an array
787///
788/// ```abnf
789/// ;; Array
790///
791/// array = array-open [ array-values ] ws-comment-newline array-close
792///
793/// array-values =  ws-comment-newline val ws-comment-newline array-sep array-values
794/// array-values =/ ws-comment-newline val ws-comment-newline [ array-sep ]
795/// ```
796fn on_array_open(
797    tokens: &mut Stream<'_>,
798    array_open: &Token,
799    receiver: &mut dyn EventReceiver,
800    error: &mut dyn ErrorSink,
801) {
802    if !receiver.array_open(array_open.span(), error) {
803        ignore_to_value_close(tokens, TokenKind::RightSquareBracket, receiver, error);
804        return;
805    }
806
807    enum State {
808        NeedsValue,
809        NeedsComma,
810    }
811
812    let mut state = State::NeedsValue;
813    while let Some(current_token) = tokens.next_token() {
814        match current_token.kind() {
815            TokenKind::Comment => {
816                on_comment(tokens, current_token, receiver, error);
817            }
818            TokenKind::Whitespace => {
819                receiver.whitespace(current_token.span(), error);
820            }
821            TokenKind::Newline => {
822                receiver.newline(current_token.span(), error);
823            }
824            TokenKind::Eof => {
825                break;
826            }
827            TokenKind::Comma => match state {
828                State::NeedsValue => {
829                    error.report_error(
830                        ParseError::new("extra comma in array")
831                            .with_context(array_open.span())
832                            .with_expected(&[Expected::Description("value")])
833                            .with_unexpected(current_token.span()),
834                    );
835                    receiver.error(current_token.span(), error);
836                }
837                State::NeedsComma => {
838                    receiver.value_sep(current_token.span(), error);
839
840                    state = State::NeedsValue;
841                }
842            },
843            TokenKind::Equals => {
844                error.report_error(
845                    ParseError::new("unexpected `=` in array")
846                        .with_context(array_open.span())
847                        .with_expected(&[Expected::Description("value"), Expected::Literal("]")])
848                        .with_unexpected(current_token.span()),
849                );
850                receiver.error(current_token.span(), error);
851            }
852            TokenKind::LeftCurlyBracket => {
853                if !matches!(state, State::NeedsValue) {
854                    error.report_error(
855                        ParseError::new("missing comma between array elements")
856                            .with_context(array_open.span())
857                            .with_expected(&[Expected::Literal(",")])
858                            .with_unexpected(current_token.span().before()),
859                    );
860                    receiver.value_sep(current_token.span().before(), error);
861                }
862
863                on_inline_table_open(tokens, current_token, receiver, error);
864
865                state = State::NeedsComma;
866            }
867            TokenKind::RightCurlyBracket => {
868                if !matches!(state, State::NeedsValue) {
869                    error.report_error(
870                        ParseError::new("missing comma between array elements")
871                            .with_context(array_open.span())
872                            .with_expected(&[Expected::Literal(",")])
873                            .with_unexpected(current_token.span().before()),
874                    );
875                    receiver.value_sep(current_token.span().before(), error);
876                }
877
878                error.report_error(
879                    ParseError::new("missing inline table opening")
880                        .with_context(current_token.span())
881                        .with_expected(&[Expected::Literal("{")])
882                        .with_unexpected(current_token.span().before()),
883                );
884
885                let _ = receiver.inline_table_open(current_token.span().before(), error);
886                receiver.inline_table_close(current_token.span(), error);
887
888                state = State::NeedsComma;
889            }
890            TokenKind::LeftSquareBracket => {
891                if !matches!(state, State::NeedsValue) {
892                    error.report_error(
893                        ParseError::new("missing comma between array elements")
894                            .with_context(array_open.span())
895                            .with_expected(&[Expected::Literal(",")])
896                            .with_unexpected(current_token.span().before()),
897                    );
898                    receiver.value_sep(current_token.span().before(), error);
899                }
900
901                on_array_open(tokens, current_token, receiver, error);
902
903                state = State::NeedsComma;
904            }
905            TokenKind::RightSquareBracket => {
906                receiver.array_close(current_token.span(), error);
907
908                return;
909            }
910            TokenKind::LiteralString
911            | TokenKind::BasicString
912            | TokenKind::MlLiteralString
913            | TokenKind::MlBasicString
914            | TokenKind::Dot
915            | TokenKind::Atom => {
916                if !matches!(state, State::NeedsValue) {
917                    error.report_error(
918                        ParseError::new("missing comma between array elements")
919                            .with_context(array_open.span())
920                            .with_expected(&[Expected::Literal(",")])
921                            .with_unexpected(current_token.span().before()),
922                    );
923                    receiver.value_sep(current_token.span().before(), error);
924                }
925
926                on_scalar(tokens, current_token, receiver, error);
927
928                state = State::NeedsComma;
929            }
930        }
931    }
932
933    let previous_span = tokens
934        .previous_tokens()
935        .find(|t| {
936            !matches!(
937                t.kind(),
938                TokenKind::Whitespace | TokenKind::Comment | TokenKind::Newline | TokenKind::Eof
939            )
940        })
941        .map(|t| t.span())
942        .unwrap_or_default();
943    error.report_error(
944        ParseError::new("unclosed array")
945            .with_context(array_open.span())
946            .with_expected(&[Expected::Literal("]")])
947            .with_unexpected(previous_span.after()),
948    );
949    receiver.array_close(previous_span.after(), error);
950}
951
952/// Parse an inline table
953///
954/// ```abnf
955/// ;; Inline Table
956///
957/// inline-table = inline-table-open [ inline-table-keyvals ] ws-comment-newline inline-table-close
958///
959/// inline-table-keyvals =  ws-comment-newline keyval ws-comment-newline inline-table-sep inline-table-keyvals
960/// inline-table-keyvals =/ ws-comment-newline keyval ws-comment-newline [ inline-table-sep ]
961/// ```
962fn on_inline_table_open(
963    tokens: &mut Stream<'_>,
964    inline_table_open: &Token,
965    receiver: &mut dyn EventReceiver,
966    error: &mut dyn ErrorSink,
967) {
968    if !receiver.inline_table_open(inline_table_open.span(), error) {
969        ignore_to_value_close(tokens, TokenKind::RightCurlyBracket, receiver, error);
970        return;
971    }
972
973    #[allow(clippy::enum_variant_names)]
974    #[derive(Debug)]
975    enum State {
976        NeedsKey,
977        NeedsEquals,
978        NeedsValue,
979        NeedsComma,
980    }
981
982    impl State {
983        fn expected(&self) -> &'static [Expected] {
984            match self {
985                Self::NeedsKey => &[Expected::Description("key")],
986                Self::NeedsEquals => &[Expected::Literal("=")],
987                Self::NeedsValue => &[Expected::Description("value")],
988                Self::NeedsComma => &[Expected::Literal(",")],
989            }
990        }
991    }
992
993    let mut state = State::NeedsKey;
994    while let Some(current_token) = tokens.next_token() {
995        match current_token.kind() {
996            TokenKind::Comment => {
997                on_comment(tokens, current_token, receiver, error);
998            }
999            TokenKind::Whitespace => {
1000                receiver.whitespace(current_token.span(), error);
1001            }
1002            TokenKind::Newline => {
1003                receiver.newline(current_token.span(), error);
1004            }
1005            TokenKind::Eof => {
1006                break;
1007            }
1008            TokenKind::Comma => match state {
1009                State::NeedsKey | State::NeedsEquals | State::NeedsValue => {
1010                    error.report_error(
1011                        ParseError::new("extra comma in inline table")
1012                            .with_context(inline_table_open.span())
1013                            .with_expected(state.expected())
1014                            .with_unexpected(current_token.span().before()),
1015                    );
1016                    receiver.error(current_token.span(), error);
1017                }
1018                State::NeedsComma => {
1019                    receiver.value_sep(current_token.span(), error);
1020
1021                    state = State::NeedsKey;
1022                }
1023            },
1024            TokenKind::Equals => match state {
1025                State::NeedsKey => {
1026                    let fake_key = current_token.span().before();
1027                    let encoding = None;
1028                    receiver.simple_key(fake_key, encoding, error);
1029
1030                    receiver.key_val_sep(current_token.span(), error);
1031
1032                    state = State::NeedsValue;
1033                }
1034                State::NeedsEquals => {
1035                    receiver.key_val_sep(current_token.span(), error);
1036
1037                    state = State::NeedsValue;
1038                }
1039                State::NeedsValue | State::NeedsComma => {
1040                    error.report_error(
1041                        ParseError::new("extra assignment between key-value pairs")
1042                            .with_context(inline_table_open.span())
1043                            .with_expected(state.expected())
1044                            .with_unexpected(current_token.span().before()),
1045                    );
1046                    receiver.error(current_token.span(), error);
1047                }
1048            },
1049            TokenKind::LeftCurlyBracket => match state {
1050                State::NeedsKey | State::NeedsComma => {
1051                    error.report_error(
1052                        ParseError::new("missing key for inline table element")
1053                            .with_context(inline_table_open.span())
1054                            .with_expected(state.expected())
1055                            .with_unexpected(current_token.span().before()),
1056                    );
1057                    receiver.error(current_token.span(), error);
1058                    ignore_to_value_close(tokens, TokenKind::RightCurlyBracket, receiver, error);
1059                }
1060                State::NeedsEquals => {
1061                    error.report_error(
1062                        ParseError::new("missing assignment between key-value pairs")
1063                            .with_context(inline_table_open.span())
1064                            .with_expected(state.expected())
1065                            .with_unexpected(current_token.span().before()),
1066                    );
1067
1068                    on_inline_table_open(tokens, current_token, receiver, error);
1069
1070                    state = State::NeedsComma;
1071                }
1072                State::NeedsValue => {
1073                    on_inline_table_open(tokens, current_token, receiver, error);
1074
1075                    state = State::NeedsComma;
1076                }
1077            },
1078            TokenKind::RightCurlyBracket => {
1079                match state {
1080                    State::NeedsKey => {}
1081                    State::NeedsEquals => {
1082                        receiver.key_val_sep(current_token.span().before(), error);
1083                        receiver.scalar(
1084                            current_token.span().before(),
1085                            Some(Encoding::LiteralString),
1086                            error,
1087                        );
1088                    }
1089                    State::NeedsValue => {
1090                        receiver.scalar(
1091                            current_token.span().before(),
1092                            Some(Encoding::LiteralString),
1093                            error,
1094                        );
1095                    }
1096                    State::NeedsComma => {}
1097                }
1098                receiver.inline_table_close(current_token.span(), error);
1099
1100                return;
1101            }
1102            TokenKind::LeftSquareBracket => match state {
1103                State::NeedsKey | State::NeedsComma => {
1104                    error.report_error(
1105                        ParseError::new("missing key for inline table element")
1106                            .with_context(inline_table_open.span())
1107                            .with_expected(state.expected())
1108                            .with_unexpected(current_token.span().before()),
1109                    );
1110                    receiver.error(current_token.span(), error);
1111                    ignore_to_value_close(tokens, TokenKind::RightSquareBracket, receiver, error);
1112                }
1113                State::NeedsEquals => {
1114                    error.report_error(
1115                        ParseError::new("missing assignment between key-value pairs")
1116                            .with_context(inline_table_open.span())
1117                            .with_expected(state.expected())
1118                            .with_unexpected(current_token.span().before()),
1119                    );
1120
1121                    on_array_open(tokens, current_token, receiver, error);
1122
1123                    state = State::NeedsComma;
1124                }
1125                State::NeedsValue => {
1126                    on_array_open(tokens, current_token, receiver, error);
1127
1128                    state = State::NeedsComma;
1129                }
1130            },
1131            TokenKind::RightSquareBracket => match state {
1132                State::NeedsKey | State::NeedsEquals | State::NeedsComma => {
1133                    error.report_error(
1134                        ParseError::new("invalid inline table element")
1135                            .with_context(inline_table_open.span())
1136                            .with_expected(state.expected())
1137                            .with_unexpected(current_token.span().before()),
1138                    );
1139                    receiver.error(current_token.span(), error);
1140                }
1141                State::NeedsValue => {
1142                    error.report_error(
1143                        ParseError::new("missing array opening")
1144                            .with_context(current_token.span())
1145                            .with_expected(&[Expected::Literal("[")])
1146                            .with_unexpected(current_token.span().before()),
1147                    );
1148
1149                    let _ = receiver.array_open(current_token.span().before(), error);
1150                    receiver.array_close(current_token.span(), error);
1151
1152                    state = State::NeedsComma;
1153                }
1154            },
1155            TokenKind::LiteralString
1156            | TokenKind::BasicString
1157            | TokenKind::MlLiteralString
1158            | TokenKind::MlBasicString
1159            | TokenKind::Dot
1160            | TokenKind::Atom => match state {
1161                State::NeedsKey => {
1162                    if current_token.kind() == TokenKind::Dot {
1163                        receiver.simple_key(
1164                            current_token.span().before(),
1165                            current_token.kind().encoding(),
1166                            error,
1167                        );
1168                        seek(tokens, -1);
1169                        opt_dot_keys(tokens, receiver, error);
1170                        state = State::NeedsEquals;
1171                    } else {
1172                        receiver.simple_key(
1173                            current_token.span(),
1174                            current_token.kind().encoding(),
1175                            error,
1176                        );
1177                        opt_dot_keys(tokens, receiver, error);
1178                        state = State::NeedsEquals;
1179                    }
1180                }
1181                State::NeedsEquals => {
1182                    error.report_error(
1183                        ParseError::new("missing assignment between key-value pairs")
1184                            .with_context(inline_table_open.span())
1185                            .with_expected(state.expected())
1186                            .with_unexpected(current_token.span().before()),
1187                    );
1188
1189                    on_scalar(tokens, current_token, receiver, error);
1190
1191                    state = State::NeedsComma;
1192                }
1193                State::NeedsValue => {
1194                    on_scalar(tokens, current_token, receiver, error);
1195
1196                    state = State::NeedsComma;
1197                }
1198                State::NeedsComma => {
1199                    error.report_error(
1200                        ParseError::new("missing comma between key-value pairs")
1201                            .with_context(inline_table_open.span())
1202                            .with_expected(state.expected())
1203                            .with_unexpected(current_token.span().before()),
1204                    );
1205
1206                    if current_token.kind() == TokenKind::Dot {
1207                        receiver.simple_key(
1208                            current_token.span().before(),
1209                            current_token.kind().encoding(),
1210                            error,
1211                        );
1212                        seek(tokens, -1);
1213                        opt_dot_keys(tokens, receiver, error);
1214                        state = State::NeedsEquals;
1215                    } else {
1216                        receiver.simple_key(
1217                            current_token.span(),
1218                            current_token.kind().encoding(),
1219                            error,
1220                        );
1221                        opt_dot_keys(tokens, receiver, error);
1222                        state = State::NeedsEquals;
1223                    }
1224                }
1225            },
1226        }
1227    }
1228
1229    let previous_span = tokens
1230        .previous_tokens()
1231        .find(|t| {
1232            !matches!(
1233                t.kind(),
1234                TokenKind::Whitespace | TokenKind::Comment | TokenKind::Newline | TokenKind::Eof
1235            )
1236        })
1237        .map(|t| t.span())
1238        .unwrap_or_default();
1239    match state {
1240        State::NeedsKey => {}
1241        State::NeedsEquals => {
1242            receiver.key_val_sep(previous_span.after(), error);
1243            receiver.scalar(previous_span.after(), Some(Encoding::LiteralString), error);
1244        }
1245        State::NeedsValue => {
1246            receiver.scalar(previous_span.after(), Some(Encoding::LiteralString), error);
1247        }
1248        State::NeedsComma => {}
1249    }
1250    error.report_error(
1251        ParseError::new("unclosed inline table")
1252            .with_context(inline_table_open.span())
1253            .with_expected(&[Expected::Literal("}")])
1254            .with_unexpected(previous_span.after()),
1255    );
1256    receiver.inline_table_close(previous_span.after(), error);
1257}
1258
1259/// Parse whitespace, if present
1260///
1261/// ```abnf
1262/// ws = *wschar
1263/// ```
1264fn opt_whitespace(
1265    tokens: &mut Stream<'_>,
1266    receiver: &mut dyn EventReceiver,
1267    error: &mut dyn ErrorSink,
1268) {
1269    if let Some(ws_token) = next_token_if(tokens, |k| matches!(k, TokenKind::Whitespace)) {
1270        receiver.whitespace(ws_token.span(), error);
1271    }
1272}
1273
1274/// Parse EOL decor, if present
1275///
1276/// ```abnf
1277/// toml = expression *( newline expression )
1278///
1279/// expression =  ws [ on_comment ]
1280/// expression =/ ws keyval ws [ on_comment ]
1281/// expression =/ ws table ws [ on_comment ]
1282///
1283/// ;; Whitespace
1284///
1285/// ws = *wschar
1286/// wschar =  %x20  ; Space
1287/// wschar =/ %x09  ; Horizontal tab
1288///
1289/// ;; Newline
1290///
1291/// newline =  %x0A     ; LF
1292/// newline =/ %x0D.0A  ; CRLF
1293///
1294/// ;; Comment
1295///
1296/// comment = comment-start-symbol *non-eol
1297/// ```
1298fn ws_comment_newline(
1299    tokens: &mut Stream<'_>,
1300    receiver: &mut dyn EventReceiver,
1301    error: &mut dyn ErrorSink,
1302) {
1303    let mut first = None;
1304    while let Some(current_token) = tokens.next_token() {
1305        let first = first.get_or_insert(current_token.span());
1306        match current_token.kind() {
1307            TokenKind::Dot
1308            | TokenKind::Equals
1309            | TokenKind::Comma
1310            | TokenKind::LeftSquareBracket
1311            | TokenKind::RightSquareBracket
1312            | TokenKind::LeftCurlyBracket
1313            | TokenKind::RightCurlyBracket
1314            | TokenKind::LiteralString
1315            | TokenKind::BasicString
1316            | TokenKind::MlLiteralString
1317            | TokenKind::MlBasicString
1318            | TokenKind::Atom => {
1319                let context = first.append(current_token.span());
1320                error.report_error(
1321                    ParseError::new("unexpected key or value")
1322                        .with_context(context)
1323                        .with_expected(&[Expected::Literal("\n"), Expected::Literal("#")])
1324                        .with_unexpected(current_token.span().before()),
1325                );
1326
1327                receiver.error(current_token.span(), error);
1328                ignore_to_newline(tokens, receiver, error);
1329                break;
1330            }
1331            TokenKind::Comment => {
1332                on_comment(tokens, current_token, receiver, error);
1333                break;
1334            }
1335            TokenKind::Whitespace => {
1336                receiver.whitespace(current_token.span(), error);
1337                continue;
1338            }
1339            TokenKind::Newline => {
1340                receiver.newline(current_token.span(), error);
1341                break;
1342            }
1343            TokenKind::Eof => {
1344                break;
1345            }
1346        }
1347    }
1348}
1349
1350/// Start EOL from [`TokenKind::Comment`]
1351fn on_comment(
1352    tokens: &mut Stream<'_>,
1353    comment_token: &Token,
1354    receiver: &mut dyn EventReceiver,
1355    error: &mut dyn ErrorSink,
1356) {
1357    receiver.comment(comment_token.span(), error);
1358
1359    let Some(current_token) = tokens.next_token() else {
1360        return;
1361    };
1362    match current_token.kind() {
1363        TokenKind::Dot
1364        | TokenKind::Equals
1365        | TokenKind::Comma
1366        | TokenKind::LeftSquareBracket
1367        | TokenKind::RightSquareBracket
1368        | TokenKind::LeftCurlyBracket
1369        | TokenKind::RightCurlyBracket
1370        | TokenKind::Whitespace
1371        | TokenKind::Comment
1372        | TokenKind::LiteralString
1373        | TokenKind::BasicString
1374        | TokenKind::MlLiteralString
1375        | TokenKind::MlBasicString
1376        | TokenKind::Atom => {
1377            let context = comment_token.span().append(current_token.span());
1378            error.report_error(
1379                ParseError::new("unexpected content between comment and newline")
1380                    .with_context(context)
1381                    .with_expected(&[Expected::Literal("\n")])
1382                    .with_unexpected(current_token.span().before()),
1383            );
1384
1385            receiver.error(current_token.span(), error);
1386            ignore_to_newline(tokens, receiver, error);
1387        }
1388        TokenKind::Newline => {
1389            receiver.newline(current_token.span(), error);
1390        }
1391        TokenKind::Eof => {}
1392    }
1393}
1394
1395fn eof(tokens: &mut Stream<'_>, receiver: &mut dyn EventReceiver, error: &mut dyn ErrorSink) {
1396    let Some(current_token) = tokens.next_token() else {
1397        return;
1398    };
1399
1400    match current_token.kind() {
1401        TokenKind::Dot
1402        | TokenKind::Equals
1403        | TokenKind::Comma
1404        | TokenKind::LeftSquareBracket
1405        | TokenKind::RightSquareBracket
1406        | TokenKind::LeftCurlyBracket
1407        | TokenKind::RightCurlyBracket
1408        | TokenKind::LiteralString
1409        | TokenKind::BasicString
1410        | TokenKind::MlLiteralString
1411        | TokenKind::MlBasicString
1412        | TokenKind::Atom
1413        | TokenKind::Comment
1414        | TokenKind::Whitespace
1415        | TokenKind::Newline => {
1416            error.report_error(
1417                ParseError::new("unexpected content")
1418                    .with_context(current_token.span())
1419                    .with_expected(&[])
1420                    .with_unexpected(current_token.span().before()),
1421            );
1422
1423            receiver.error(current_token.span(), error);
1424            while let Some(current_token) = tokens.next_token() {
1425                if current_token.kind() == TokenKind::Eof {
1426                    continue;
1427                }
1428                receiver.error(current_token.span(), error);
1429            }
1430        }
1431        TokenKind::Eof => {}
1432    }
1433}
1434
1435// Don't bother recovering until [`TokenKind::Newline`]
1436#[cold]
1437fn ignore_to_newline(
1438    tokens: &mut Stream<'_>,
1439    receiver: &mut dyn EventReceiver,
1440    error: &mut dyn ErrorSink,
1441) {
1442    while let Some(current_token) = tokens.next_token() {
1443        match current_token.kind() {
1444            TokenKind::Dot
1445            | TokenKind::Equals
1446            | TokenKind::Comma
1447            | TokenKind::LeftSquareBracket
1448            | TokenKind::RightSquareBracket
1449            | TokenKind::LeftCurlyBracket
1450            | TokenKind::RightCurlyBracket
1451            | TokenKind::LiteralString
1452            | TokenKind::BasicString
1453            | TokenKind::MlLiteralString
1454            | TokenKind::MlBasicString
1455            | TokenKind::Atom => {
1456                receiver.error(current_token.span(), error);
1457            }
1458            TokenKind::Comment => {
1459                on_comment(tokens, current_token, receiver, error);
1460                break;
1461            }
1462            TokenKind::Whitespace => {
1463                receiver.whitespace(current_token.span(), error);
1464            }
1465            TokenKind::Newline => {
1466                receiver.newline(current_token.span(), error);
1467                break;
1468            }
1469            TokenKind::Eof => {
1470                break;
1471            }
1472        }
1473    }
1474}
1475
1476/// Don't bother recovering until the matching [`TokenKind`]
1477///
1478/// Attempts to ignore nested `[]`, `{}`.
1479#[cold]
1480fn ignore_to_value_close(
1481    tokens: &mut Stream<'_>,
1482    closing_kind: TokenKind,
1483    receiver: &mut dyn EventReceiver,
1484    error: &mut dyn ErrorSink,
1485) {
1486    let mut array_count: usize = 0;
1487    let mut inline_table_count: usize = 0;
1488    while let Some(current_token) = tokens.next_token() {
1489        match current_token.kind() {
1490            TokenKind::Dot
1491            | TokenKind::Equals
1492            | TokenKind::Comma
1493            | TokenKind::LiteralString
1494            | TokenKind::BasicString
1495            | TokenKind::MlLiteralString
1496            | TokenKind::MlBasicString
1497            | TokenKind::Atom => {
1498                receiver.error(current_token.span(), error);
1499            }
1500            TokenKind::Comment => {
1501                on_comment(tokens, current_token, receiver, error);
1502            }
1503            TokenKind::Whitespace => {
1504                receiver.whitespace(current_token.span(), error);
1505            }
1506            TokenKind::Newline => {
1507                receiver.newline(current_token.span(), error);
1508            }
1509            TokenKind::LeftSquareBracket => {
1510                receiver.error(current_token.span(), error);
1511                array_count += 1;
1512            }
1513            TokenKind::RightSquareBracket => {
1514                if array_count == 0 && current_token.kind() == closing_kind {
1515                    receiver.array_close(current_token.span(), error);
1516                    break;
1517                } else {
1518                    receiver.error(current_token.span(), error);
1519                    array_count = array_count.saturating_sub(1);
1520                }
1521            }
1522            TokenKind::LeftCurlyBracket => {
1523                receiver.error(current_token.span(), error);
1524                inline_table_count += 1;
1525            }
1526            TokenKind::RightCurlyBracket => {
1527                if inline_table_count == 0 && current_token.kind() == closing_kind {
1528                    receiver.inline_table_close(current_token.span(), error);
1529                    break;
1530                } else {
1531                    receiver.error(current_token.span(), error);
1532                    inline_table_count = inline_table_count.saturating_sub(1);
1533                }
1534            }
1535            TokenKind::Eof => {
1536                break;
1537            }
1538        }
1539    }
1540}
1541
1542#[cold]
1543fn on_missing_key(
1544    tokens: &mut Stream<'_>,
1545    token: &Token,
1546    invalid_description: &'static str,
1547    receiver: &mut dyn EventReceiver,
1548    error: &mut dyn ErrorSink,
1549) {
1550    error.report_error(
1551        ParseError::new(invalid_description)
1552            .with_context(token.span())
1553            .with_expected(&[Expected::Description("key")])
1554            .with_unexpected(token.span().before()),
1555    );
1556
1557    if token.kind() == TokenKind::Eof {
1558    } else if token.kind() == TokenKind::Newline {
1559        receiver.newline(token.span(), error);
1560    } else if token.kind() == TokenKind::Comment {
1561        on_comment(tokens, token, receiver, error);
1562    } else {
1563        receiver.error(token.span(), error);
1564    }
1565}
1566
1567#[cold]
1568fn on_missing_expression_key(
1569    tokens: &mut Stream<'_>,
1570    token: &Token,
1571    receiver: &mut dyn EventReceiver,
1572    error: &mut dyn ErrorSink,
1573) {
1574    error.report_error(
1575        ParseError::new("invalid key-value pair")
1576            .with_context(token.span())
1577            .with_expected(&[Expected::Description("key")])
1578            .with_unexpected(token.span().before()),
1579    );
1580
1581    receiver.error(token.span(), error);
1582    ignore_to_newline(tokens, receiver, error);
1583}
1584
1585#[cold]
1586fn on_missing_std_table(
1587    tokens: &mut Stream<'_>,
1588    token: &Token,
1589    receiver: &mut dyn EventReceiver,
1590    error: &mut dyn ErrorSink,
1591) {
1592    error.report_error(
1593        ParseError::new("missing table open")
1594            .with_context(token.span())
1595            .with_expected(&[Expected::Literal("[")])
1596            .with_unexpected(token.span().before()),
1597    );
1598
1599    receiver.error(token.span(), error);
1600    ignore_to_newline(tokens, receiver, error);
1601}
1602
1603fn next_token_if<'i, F: Fn(TokenKind) -> bool>(
1604    tokens: &mut Stream<'i>,
1605    pred: F,
1606) -> Option<&'i Token> {
1607    match tokens.first() {
1608        Some(next) if pred(next.kind()) => tokens.next_token(),
1609        _ => None,
1610    }
1611}
1612
1613fn seek(stream: &mut Stream<'_>, offset: isize) {
1614    let current = stream.checkpoint();
1615    stream.reset_to_start();
1616    let start = stream.checkpoint();
1617    let old_offset = current.offset_from(&start);
1618    let new_offset = (old_offset as isize).saturating_add(offset) as usize;
1619    if new_offset < stream.eof_offset() {
1620        #[cfg(feature = "unsafe")] // SAFETY: bounds were checked
1621        unsafe {
1622            stream.next_slice_unchecked(new_offset)
1623        };
1624        #[cfg(not(feature = "unsafe"))]
1625        stream.next_slice(new_offset);
1626    } else {
1627        stream.finish();
1628    }
1629}
1630
1631const UNQUOTED_STRING: &str = "unquoted string";