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;
6#[cfg(feature = "debug")]
7use crate::debug::DebugErrorSink;
8#[cfg(feature = "debug")]
9use crate::debug::DebugEventReceiver;
10use crate::decoder::Encoding;
11use crate::lexer::Token;
12use crate::lexer::TokenKind;
13use crate::ErrorSink;
14use crate::Expected;
15use crate::ParseError;
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    let Some(current_token) = tokens.next_token() else {
630        let previous_span = tokens
631            .previous_tokens()
632            .find(|t| {
633                !matches!(
634                    t.kind(),
635                    TokenKind::Whitespace
636                        | TokenKind::Comment
637                        | TokenKind::Newline
638                        | TokenKind::Eof
639                )
640            })
641            .map(|t| t.span())
642            .unwrap_or_default();
643        error.report_error(
644            ParseError::new("missing value")
645                .with_context(previous_span)
646                .with_expected(&[Expected::Description("value")])
647                .with_unexpected(previous_span.after()),
648        );
649        return;
650    };
651
652    match current_token.kind() {
653        TokenKind::Comment
654        | TokenKind::Comma
655        | TokenKind::Newline
656        | TokenKind::Eof
657        | TokenKind::Whitespace => {
658            let fake_key = current_token.span().before();
659            let encoding = None;
660            receiver.scalar(fake_key, encoding, error);
661            seek(tokens, -1);
662        }
663        TokenKind::Equals => {
664            error.report_error(
665                ParseError::new("extra `=`")
666                    .with_context(current_token.span())
667                    .with_expected(&[])
668                    .with_unexpected(current_token.span()),
669            );
670            receiver.error(current_token.span(), error);
671            value(tokens, receiver, error);
672        }
673        TokenKind::LeftCurlyBracket => {
674            on_inline_table_open(tokens, current_token, receiver, error);
675        }
676        TokenKind::RightCurlyBracket => {
677            error.report_error(
678                ParseError::new("missing inline table opening")
679                    .with_context(current_token.span())
680                    .with_expected(&[Expected::Literal("{")])
681                    .with_unexpected(current_token.span().before()),
682            );
683
684            let _ = receiver.inline_table_open(current_token.span().before(), error);
685            receiver.inline_table_close(current_token.span(), error);
686        }
687        TokenKind::LeftSquareBracket => {
688            on_array_open(tokens, current_token, receiver, error);
689        }
690        TokenKind::RightSquareBracket => {
691            error.report_error(
692                ParseError::new("missing array opening")
693                    .with_context(current_token.span())
694                    .with_expected(&[Expected::Literal("[")])
695                    .with_unexpected(current_token.span().before()),
696            );
697
698            let _ = receiver.array_open(current_token.span().before(), error);
699            receiver.array_close(current_token.span(), error);
700        }
701        TokenKind::LiteralString
702        | TokenKind::BasicString
703        | TokenKind::MlLiteralString
704        | TokenKind::MlBasicString
705        | TokenKind::Dot
706        | TokenKind::Atom => {
707            on_scalar(tokens, current_token, receiver, error);
708        }
709    }
710}
711
712/// Parse a scalar value
713///
714/// ```abnf
715/// val = string / boolean / array / inline-table / date-time / float / integer
716/// ```
717fn on_scalar(
718    tokens: &mut Stream<'_>,
719    scalar: &Token,
720    receiver: &mut dyn EventReceiver,
721    error: &mut dyn ErrorSink,
722) {
723    let mut span = scalar.span();
724    let encoding = match scalar.kind() {
725        TokenKind::Comment
726        | TokenKind::Comma
727        | TokenKind::Newline
728        | TokenKind::Eof
729        | TokenKind::Whitespace
730        | TokenKind::Equals
731        | TokenKind::LeftCurlyBracket
732        | TokenKind::RightCurlyBracket
733        | TokenKind::LeftSquareBracket
734        | TokenKind::RightSquareBracket => {
735            unreachable!()
736        }
737        TokenKind::LiteralString => Some(Encoding::LiteralString),
738        TokenKind::BasicString => Some(Encoding::BasicString),
739        TokenKind::MlLiteralString => Some(Encoding::MlLiteralString),
740        TokenKind::MlBasicString => Some(Encoding::MlBasicString),
741        TokenKind::Dot | TokenKind::Atom => {
742            while let Some(next_token) = tokens.first() {
743                match next_token.kind() {
744                    TokenKind::Comment
745                    | TokenKind::Comma
746                    | TokenKind::Newline
747                    | TokenKind::Eof
748                    | TokenKind::Equals
749                    | TokenKind::LeftCurlyBracket
750                    | TokenKind::RightCurlyBracket
751                    | TokenKind::LeftSquareBracket
752                    | TokenKind::RightSquareBracket
753                    | TokenKind::LiteralString
754                    | TokenKind::BasicString
755                    | TokenKind::MlLiteralString
756                    | TokenKind::MlBasicString => {
757                        break;
758                    }
759                    TokenKind::Whitespace => {
760                        if let Some(second) = tokens.get(1) {
761                            if second.kind() == TokenKind::Atom {
762                                span = span.append(second.span());
763                                let _ = tokens.next_slice(2);
764                                continue;
765                            }
766                        }
767                        break;
768                    }
769                    TokenKind::Dot | TokenKind::Atom => {
770                        span = span.append(next_token.span());
771                        let _ = tokens.next_token();
772                    }
773                }
774            }
775            None
776        }
777    };
778    receiver.scalar(span, encoding, error);
779}
780
781/// Parse an array
782///
783/// ```abnf
784/// ;; Array
785///
786/// array = array-open [ array-values ] ws-comment-newline array-close
787///
788/// array-values =  ws-comment-newline val ws-comment-newline array-sep array-values
789/// array-values =/ ws-comment-newline val ws-comment-newline [ array-sep ]
790/// ```
791fn on_array_open(
792    tokens: &mut Stream<'_>,
793    array_open: &Token,
794    receiver: &mut dyn EventReceiver,
795    error: &mut dyn ErrorSink,
796) {
797    if !receiver.array_open(array_open.span(), error) {
798        ignore_to_value_close(tokens, TokenKind::RightSquareBracket, receiver, error);
799        return;
800    }
801
802    enum State {
803        NeedsValue,
804        NeedsComma,
805    }
806
807    let mut state = State::NeedsValue;
808    while let Some(current_token) = tokens.next_token() {
809        match current_token.kind() {
810            TokenKind::Comment => {
811                on_comment(tokens, current_token, receiver, error);
812            }
813            TokenKind::Whitespace => {
814                receiver.whitespace(current_token.span(), error);
815            }
816            TokenKind::Newline => {
817                receiver.newline(current_token.span(), error);
818            }
819            TokenKind::Eof => {
820                break;
821            }
822            TokenKind::Comma => match state {
823                State::NeedsValue => {
824                    error.report_error(
825                        ParseError::new("extra comma in array")
826                            .with_context(array_open.span())
827                            .with_expected(&[Expected::Description("value")])
828                            .with_unexpected(current_token.span()),
829                    );
830                    receiver.error(current_token.span(), error);
831                }
832                State::NeedsComma => {
833                    receiver.value_sep(current_token.span(), error);
834
835                    state = State::NeedsValue;
836                }
837            },
838            TokenKind::Equals => {
839                error.report_error(
840                    ParseError::new("unexpected `=` in array")
841                        .with_context(array_open.span())
842                        .with_expected(&[Expected::Description("value"), Expected::Literal("]")])
843                        .with_unexpected(current_token.span()),
844                );
845                receiver.error(current_token.span(), error);
846            }
847            TokenKind::LeftCurlyBracket => {
848                if !matches!(state, State::NeedsValue) {
849                    error.report_error(
850                        ParseError::new("missing comma between array elements")
851                            .with_context(array_open.span())
852                            .with_expected(&[Expected::Literal(",")])
853                            .with_unexpected(current_token.span().before()),
854                    );
855                    receiver.value_sep(current_token.span().before(), error);
856                }
857
858                on_inline_table_open(tokens, current_token, receiver, error);
859
860                state = State::NeedsComma;
861            }
862            TokenKind::RightCurlyBracket => {
863                if !matches!(state, State::NeedsValue) {
864                    error.report_error(
865                        ParseError::new("missing comma between array elements")
866                            .with_context(array_open.span())
867                            .with_expected(&[Expected::Literal(",")])
868                            .with_unexpected(current_token.span().before()),
869                    );
870                    receiver.value_sep(current_token.span().before(), error);
871                }
872
873                error.report_error(
874                    ParseError::new("missing inline table opening")
875                        .with_context(current_token.span())
876                        .with_expected(&[Expected::Literal("{")])
877                        .with_unexpected(current_token.span().before()),
878                );
879
880                let _ = receiver.inline_table_open(current_token.span().before(), error);
881                receiver.inline_table_close(current_token.span(), error);
882
883                state = State::NeedsComma;
884            }
885            TokenKind::LeftSquareBracket => {
886                if !matches!(state, State::NeedsValue) {
887                    error.report_error(
888                        ParseError::new("missing comma between array elements")
889                            .with_context(array_open.span())
890                            .with_expected(&[Expected::Literal(",")])
891                            .with_unexpected(current_token.span().before()),
892                    );
893                    receiver.value_sep(current_token.span().before(), error);
894                }
895
896                on_array_open(tokens, current_token, receiver, error);
897
898                state = State::NeedsComma;
899            }
900            TokenKind::RightSquareBracket => {
901                receiver.array_close(current_token.span(), error);
902
903                return;
904            }
905            TokenKind::LiteralString
906            | TokenKind::BasicString
907            | TokenKind::MlLiteralString
908            | TokenKind::MlBasicString
909            | TokenKind::Dot
910            | TokenKind::Atom => {
911                if !matches!(state, State::NeedsValue) {
912                    error.report_error(
913                        ParseError::new("missing comma between array elements")
914                            .with_context(array_open.span())
915                            .with_expected(&[Expected::Literal(",")])
916                            .with_unexpected(current_token.span().before()),
917                    );
918                    receiver.value_sep(current_token.span().before(), error);
919                }
920
921                on_scalar(tokens, current_token, receiver, error);
922
923                state = State::NeedsComma;
924            }
925        }
926    }
927
928    let previous_span = tokens
929        .previous_tokens()
930        .find(|t| {
931            !matches!(
932                t.kind(),
933                TokenKind::Whitespace | TokenKind::Comment | TokenKind::Newline | TokenKind::Eof
934            )
935        })
936        .map(|t| t.span())
937        .unwrap_or_default();
938    error.report_error(
939        ParseError::new("unclosed array")
940            .with_context(array_open.span())
941            .with_expected(&[Expected::Literal("]")])
942            .with_unexpected(previous_span.after()),
943    );
944    receiver.array_close(previous_span.after(), error);
945}
946
947/// Parse an inline table
948///
949/// ```abnf
950/// ;; Inline Table
951///
952/// inline-table = inline-table-open [ inline-table-keyvals ] ws-comment-newline inline-table-close
953///
954/// inline-table-keyvals =  ws-comment-newline keyval ws-comment-newline inline-table-sep inline-table-keyvals
955/// inline-table-keyvals =/ ws-comment-newline keyval ws-comment-newline [ inline-table-sep ]
956/// ```
957fn on_inline_table_open(
958    tokens: &mut Stream<'_>,
959    inline_table_open: &Token,
960    receiver: &mut dyn EventReceiver,
961    error: &mut dyn ErrorSink,
962) {
963    if !receiver.inline_table_open(inline_table_open.span(), error) {
964        ignore_to_value_close(tokens, TokenKind::RightCurlyBracket, receiver, error);
965        return;
966    }
967
968    #[allow(clippy::enum_variant_names)]
969    #[derive(Debug)]
970    enum State {
971        NeedsKey,
972        NeedsEquals,
973        NeedsValue,
974        NeedsComma,
975    }
976
977    impl State {
978        fn expected(&self) -> &'static [Expected] {
979            match self {
980                Self::NeedsKey => &[Expected::Description("key")],
981                Self::NeedsEquals => &[Expected::Literal("=")],
982                Self::NeedsValue => &[Expected::Description("value")],
983                Self::NeedsComma => &[Expected::Literal(",")],
984            }
985        }
986    }
987
988    let mut state = State::NeedsKey;
989    while let Some(current_token) = tokens.next_token() {
990        match current_token.kind() {
991            TokenKind::Comment => {
992                on_comment(tokens, current_token, receiver, error);
993            }
994            TokenKind::Whitespace => {
995                receiver.whitespace(current_token.span(), error);
996            }
997            TokenKind::Newline => {
998                receiver.newline(current_token.span(), error);
999            }
1000            TokenKind::Eof => {
1001                break;
1002            }
1003            TokenKind::Comma => match state {
1004                State::NeedsKey | State::NeedsEquals | State::NeedsValue => {
1005                    error.report_error(
1006                        ParseError::new("extra comma in inline table")
1007                            .with_context(inline_table_open.span())
1008                            .with_expected(state.expected())
1009                            .with_unexpected(current_token.span().before()),
1010                    );
1011                    receiver.error(current_token.span(), error);
1012                }
1013                State::NeedsComma => {
1014                    receiver.value_sep(current_token.span(), error);
1015
1016                    state = State::NeedsKey;
1017                }
1018            },
1019            TokenKind::Equals => match state {
1020                State::NeedsKey => {
1021                    let fake_key = current_token.span().before();
1022                    let encoding = None;
1023                    receiver.simple_key(fake_key, encoding, error);
1024
1025                    receiver.key_val_sep(current_token.span(), error);
1026
1027                    state = State::NeedsValue;
1028                }
1029                State::NeedsEquals => {
1030                    receiver.key_val_sep(current_token.span(), error);
1031
1032                    state = State::NeedsValue;
1033                }
1034                State::NeedsValue | State::NeedsComma => {
1035                    error.report_error(
1036                        ParseError::new("extra assignment between key-value pairs")
1037                            .with_context(inline_table_open.span())
1038                            .with_expected(state.expected())
1039                            .with_unexpected(current_token.span().before()),
1040                    );
1041                    receiver.error(current_token.span(), error);
1042                }
1043            },
1044            TokenKind::LeftCurlyBracket => match state {
1045                State::NeedsKey | State::NeedsComma => {
1046                    error.report_error(
1047                        ParseError::new("missing key for inline table element")
1048                            .with_context(inline_table_open.span())
1049                            .with_expected(state.expected())
1050                            .with_unexpected(current_token.span().before()),
1051                    );
1052                    receiver.error(current_token.span(), error);
1053                    ignore_to_value_close(tokens, TokenKind::RightCurlyBracket, receiver, error);
1054                }
1055                State::NeedsEquals => {
1056                    error.report_error(
1057                        ParseError::new("missing assignment between key-value pairs")
1058                            .with_context(inline_table_open.span())
1059                            .with_expected(state.expected())
1060                            .with_unexpected(current_token.span().before()),
1061                    );
1062
1063                    on_inline_table_open(tokens, current_token, receiver, error);
1064
1065                    state = State::NeedsComma;
1066                }
1067                State::NeedsValue => {
1068                    on_inline_table_open(tokens, current_token, receiver, error);
1069
1070                    state = State::NeedsComma;
1071                }
1072            },
1073            TokenKind::RightCurlyBracket => {
1074                match state {
1075                    State::NeedsKey => {}
1076                    State::NeedsEquals => {
1077                        receiver.key_val_sep(current_token.span().before(), error);
1078                        receiver.scalar(
1079                            current_token.span().before(),
1080                            Some(Encoding::LiteralString),
1081                            error,
1082                        );
1083                    }
1084                    State::NeedsValue => {
1085                        receiver.scalar(
1086                            current_token.span().before(),
1087                            Some(Encoding::LiteralString),
1088                            error,
1089                        );
1090                    }
1091                    State::NeedsComma => {}
1092                }
1093                receiver.inline_table_close(current_token.span(), error);
1094
1095                return;
1096            }
1097            TokenKind::LeftSquareBracket => match state {
1098                State::NeedsKey | State::NeedsComma => {
1099                    error.report_error(
1100                        ParseError::new("missing key for inline table element")
1101                            .with_context(inline_table_open.span())
1102                            .with_expected(state.expected())
1103                            .with_unexpected(current_token.span().before()),
1104                    );
1105                    receiver.error(current_token.span(), error);
1106                    ignore_to_value_close(tokens, TokenKind::RightSquareBracket, receiver, error);
1107                }
1108                State::NeedsEquals => {
1109                    error.report_error(
1110                        ParseError::new("missing assignment between key-value pairs")
1111                            .with_context(inline_table_open.span())
1112                            .with_expected(state.expected())
1113                            .with_unexpected(current_token.span().before()),
1114                    );
1115
1116                    on_array_open(tokens, current_token, receiver, error);
1117
1118                    state = State::NeedsComma;
1119                }
1120                State::NeedsValue => {
1121                    on_array_open(tokens, current_token, receiver, error);
1122
1123                    state = State::NeedsComma;
1124                }
1125            },
1126            TokenKind::RightSquareBracket => match state {
1127                State::NeedsKey | State::NeedsEquals | State::NeedsComma => {
1128                    error.report_error(
1129                        ParseError::new("invalid inline table element")
1130                            .with_context(inline_table_open.span())
1131                            .with_expected(state.expected())
1132                            .with_unexpected(current_token.span().before()),
1133                    );
1134                    receiver.error(current_token.span(), error);
1135                }
1136                State::NeedsValue => {
1137                    error.report_error(
1138                        ParseError::new("missing array opening")
1139                            .with_context(current_token.span())
1140                            .with_expected(&[Expected::Literal("[")])
1141                            .with_unexpected(current_token.span().before()),
1142                    );
1143
1144                    let _ = receiver.array_open(current_token.span().before(), error);
1145                    receiver.array_close(current_token.span(), error);
1146
1147                    state = State::NeedsComma;
1148                }
1149            },
1150            TokenKind::LiteralString
1151            | TokenKind::BasicString
1152            | TokenKind::MlLiteralString
1153            | TokenKind::MlBasicString
1154            | TokenKind::Dot
1155            | TokenKind::Atom => match state {
1156                State::NeedsKey => {
1157                    if current_token.kind() == TokenKind::Dot {
1158                        receiver.simple_key(
1159                            current_token.span().before(),
1160                            current_token.kind().encoding(),
1161                            error,
1162                        );
1163                        seek(tokens, -1);
1164                        opt_dot_keys(tokens, receiver, error);
1165                        state = State::NeedsEquals;
1166                    } else {
1167                        receiver.simple_key(
1168                            current_token.span(),
1169                            current_token.kind().encoding(),
1170                            error,
1171                        );
1172                        opt_dot_keys(tokens, receiver, error);
1173                        state = State::NeedsEquals;
1174                    }
1175                }
1176                State::NeedsEquals => {
1177                    error.report_error(
1178                        ParseError::new("missing assignment between key-value pairs")
1179                            .with_context(inline_table_open.span())
1180                            .with_expected(state.expected())
1181                            .with_unexpected(current_token.span().before()),
1182                    );
1183
1184                    on_scalar(tokens, current_token, receiver, error);
1185
1186                    state = State::NeedsComma;
1187                }
1188                State::NeedsValue => {
1189                    on_scalar(tokens, current_token, receiver, error);
1190
1191                    state = State::NeedsComma;
1192                }
1193                State::NeedsComma => {
1194                    error.report_error(
1195                        ParseError::new("missing comma between key-value pairs")
1196                            .with_context(inline_table_open.span())
1197                            .with_expected(state.expected())
1198                            .with_unexpected(current_token.span().before()),
1199                    );
1200
1201                    if current_token.kind() == TokenKind::Dot {
1202                        receiver.simple_key(
1203                            current_token.span().before(),
1204                            current_token.kind().encoding(),
1205                            error,
1206                        );
1207                        seek(tokens, -1);
1208                        opt_dot_keys(tokens, receiver, error);
1209                        state = State::NeedsEquals;
1210                    } else {
1211                        receiver.simple_key(
1212                            current_token.span(),
1213                            current_token.kind().encoding(),
1214                            error,
1215                        );
1216                        opt_dot_keys(tokens, receiver, error);
1217                        state = State::NeedsEquals;
1218                    }
1219                }
1220            },
1221        }
1222    }
1223
1224    let previous_span = tokens
1225        .previous_tokens()
1226        .find(|t| {
1227            !matches!(
1228                t.kind(),
1229                TokenKind::Whitespace | TokenKind::Comment | TokenKind::Newline | TokenKind::Eof
1230            )
1231        })
1232        .map(|t| t.span())
1233        .unwrap_or_default();
1234    match state {
1235        State::NeedsKey => {}
1236        State::NeedsEquals => {
1237            receiver.key_val_sep(previous_span.after(), error);
1238            receiver.scalar(previous_span.after(), Some(Encoding::LiteralString), error);
1239        }
1240        State::NeedsValue => {
1241            receiver.scalar(previous_span.after(), Some(Encoding::LiteralString), error);
1242        }
1243        State::NeedsComma => {}
1244    }
1245    error.report_error(
1246        ParseError::new("unclosed inline table")
1247            .with_context(inline_table_open.span())
1248            .with_expected(&[Expected::Literal("}")])
1249            .with_unexpected(previous_span.after()),
1250    );
1251    receiver.inline_table_close(previous_span.after(), error);
1252}
1253
1254/// Parse whitespace, if present
1255///
1256/// ```abnf
1257/// ws = *wschar
1258/// ```
1259fn opt_whitespace(
1260    tokens: &mut Stream<'_>,
1261    receiver: &mut dyn EventReceiver,
1262    error: &mut dyn ErrorSink,
1263) {
1264    if let Some(ws_token) = next_token_if(tokens, |k| matches!(k, TokenKind::Whitespace)) {
1265        receiver.whitespace(ws_token.span(), error);
1266    }
1267}
1268
1269/// Parse EOL decor, if present
1270///
1271/// ```abnf
1272/// toml = expression *( newline expression )
1273///
1274/// expression =  ws [ on_comment ]
1275/// expression =/ ws keyval ws [ on_comment ]
1276/// expression =/ ws table ws [ on_comment ]
1277///
1278/// ;; Whitespace
1279///
1280/// ws = *wschar
1281/// wschar =  %x20  ; Space
1282/// wschar =/ %x09  ; Horizontal tab
1283///
1284/// ;; Newline
1285///
1286/// newline =  %x0A     ; LF
1287/// newline =/ %x0D.0A  ; CRLF
1288///
1289/// ;; Comment
1290///
1291/// comment = comment-start-symbol *non-eol
1292/// ```
1293fn ws_comment_newline(
1294    tokens: &mut Stream<'_>,
1295    receiver: &mut dyn EventReceiver,
1296    error: &mut dyn ErrorSink,
1297) {
1298    let mut first = None;
1299    while let Some(current_token) = tokens.next_token() {
1300        let first = first.get_or_insert(current_token.span());
1301        match current_token.kind() {
1302            TokenKind::Dot
1303            | TokenKind::Equals
1304            | TokenKind::Comma
1305            | TokenKind::LeftSquareBracket
1306            | TokenKind::RightSquareBracket
1307            | TokenKind::LeftCurlyBracket
1308            | TokenKind::RightCurlyBracket
1309            | TokenKind::LiteralString
1310            | TokenKind::BasicString
1311            | TokenKind::MlLiteralString
1312            | TokenKind::MlBasicString
1313            | TokenKind::Atom => {
1314                let context = first.append(current_token.span());
1315                error.report_error(
1316                    ParseError::new("unexpected key or value")
1317                        .with_context(context)
1318                        .with_expected(&[Expected::Literal("\n"), Expected::Literal("#")])
1319                        .with_unexpected(current_token.span().before()),
1320                );
1321
1322                receiver.error(current_token.span(), error);
1323                ignore_to_newline(tokens, receiver, error);
1324                break;
1325            }
1326            TokenKind::Comment => {
1327                on_comment(tokens, current_token, receiver, error);
1328                break;
1329            }
1330            TokenKind::Whitespace => {
1331                receiver.whitespace(current_token.span(), error);
1332                continue;
1333            }
1334            TokenKind::Newline => {
1335                receiver.newline(current_token.span(), error);
1336                break;
1337            }
1338            TokenKind::Eof => {
1339                break;
1340            }
1341        }
1342    }
1343}
1344
1345/// Start EOL from [`TokenKind::Comment`]
1346fn on_comment(
1347    tokens: &mut Stream<'_>,
1348    comment_token: &Token,
1349    receiver: &mut dyn EventReceiver,
1350    error: &mut dyn ErrorSink,
1351) {
1352    receiver.comment(comment_token.span(), error);
1353
1354    let Some(current_token) = tokens.next_token() else {
1355        return;
1356    };
1357    match current_token.kind() {
1358        TokenKind::Dot
1359        | TokenKind::Equals
1360        | TokenKind::Comma
1361        | TokenKind::LeftSquareBracket
1362        | TokenKind::RightSquareBracket
1363        | TokenKind::LeftCurlyBracket
1364        | TokenKind::RightCurlyBracket
1365        | TokenKind::Whitespace
1366        | TokenKind::Comment
1367        | TokenKind::LiteralString
1368        | TokenKind::BasicString
1369        | TokenKind::MlLiteralString
1370        | TokenKind::MlBasicString
1371        | TokenKind::Atom => {
1372            let context = comment_token.span().append(current_token.span());
1373            error.report_error(
1374                ParseError::new("unexpected content between comment and newline")
1375                    .with_context(context)
1376                    .with_expected(&[Expected::Literal("\n")])
1377                    .with_unexpected(current_token.span().before()),
1378            );
1379
1380            receiver.error(current_token.span(), error);
1381            ignore_to_newline(tokens, receiver, error);
1382        }
1383        TokenKind::Newline => {
1384            receiver.newline(current_token.span(), error);
1385        }
1386        TokenKind::Eof => {}
1387    }
1388}
1389
1390fn eof(tokens: &mut Stream<'_>, receiver: &mut dyn EventReceiver, error: &mut dyn ErrorSink) {
1391    let Some(current_token) = tokens.next_token() else {
1392        return;
1393    };
1394
1395    match current_token.kind() {
1396        TokenKind::Dot
1397        | TokenKind::Equals
1398        | TokenKind::Comma
1399        | TokenKind::LeftSquareBracket
1400        | TokenKind::RightSquareBracket
1401        | TokenKind::LeftCurlyBracket
1402        | TokenKind::RightCurlyBracket
1403        | TokenKind::LiteralString
1404        | TokenKind::BasicString
1405        | TokenKind::MlLiteralString
1406        | TokenKind::MlBasicString
1407        | TokenKind::Atom
1408        | TokenKind::Comment
1409        | TokenKind::Whitespace
1410        | TokenKind::Newline => {
1411            error.report_error(
1412                ParseError::new("unexpected content")
1413                    .with_context(current_token.span())
1414                    .with_expected(&[])
1415                    .with_unexpected(current_token.span().before()),
1416            );
1417
1418            receiver.error(current_token.span(), error);
1419            while let Some(current_token) = tokens.next_token() {
1420                if current_token.kind() == TokenKind::Eof {
1421                    continue;
1422                }
1423                receiver.error(current_token.span(), error);
1424            }
1425        }
1426        TokenKind::Eof => {}
1427    }
1428}
1429
1430// Don't bother recovering until [`TokenKind::Newline`]
1431#[cold]
1432fn ignore_to_newline(
1433    tokens: &mut Stream<'_>,
1434    receiver: &mut dyn EventReceiver,
1435    error: &mut dyn ErrorSink,
1436) {
1437    while let Some(current_token) = tokens.next_token() {
1438        match current_token.kind() {
1439            TokenKind::Dot
1440            | TokenKind::Equals
1441            | TokenKind::Comma
1442            | TokenKind::LeftSquareBracket
1443            | TokenKind::RightSquareBracket
1444            | TokenKind::LeftCurlyBracket
1445            | TokenKind::RightCurlyBracket
1446            | TokenKind::LiteralString
1447            | TokenKind::BasicString
1448            | TokenKind::MlLiteralString
1449            | TokenKind::MlBasicString
1450            | TokenKind::Atom => {
1451                receiver.error(current_token.span(), error);
1452            }
1453            TokenKind::Comment => {
1454                on_comment(tokens, current_token, receiver, error);
1455                break;
1456            }
1457            TokenKind::Whitespace => {
1458                receiver.whitespace(current_token.span(), error);
1459            }
1460            TokenKind::Newline => {
1461                receiver.newline(current_token.span(), error);
1462                break;
1463            }
1464            TokenKind::Eof => {
1465                break;
1466            }
1467        }
1468    }
1469}
1470
1471/// Don't bother recovering until the matching [`TokenKind`]
1472///
1473/// Attempts to ignore nested `[]`, `{}`.
1474#[cold]
1475fn ignore_to_value_close(
1476    tokens: &mut Stream<'_>,
1477    closing_kind: TokenKind,
1478    receiver: &mut dyn EventReceiver,
1479    error: &mut dyn ErrorSink,
1480) {
1481    let mut array_count: usize = 0;
1482    let mut inline_table_count: usize = 0;
1483    while let Some(current_token) = tokens.next_token() {
1484        match current_token.kind() {
1485            TokenKind::Dot
1486            | TokenKind::Equals
1487            | TokenKind::Comma
1488            | TokenKind::LiteralString
1489            | TokenKind::BasicString
1490            | TokenKind::MlLiteralString
1491            | TokenKind::MlBasicString
1492            | TokenKind::Atom => {
1493                receiver.error(current_token.span(), error);
1494            }
1495            TokenKind::Comment => {
1496                on_comment(tokens, current_token, receiver, error);
1497            }
1498            TokenKind::Whitespace => {
1499                receiver.whitespace(current_token.span(), error);
1500            }
1501            TokenKind::Newline => {
1502                receiver.newline(current_token.span(), error);
1503            }
1504            TokenKind::LeftSquareBracket => {
1505                receiver.error(current_token.span(), error);
1506                array_count += 1;
1507            }
1508            TokenKind::RightSquareBracket => {
1509                if array_count == 0 && current_token.kind() == closing_kind {
1510                    receiver.array_close(current_token.span(), error);
1511                    break;
1512                } else {
1513                    receiver.error(current_token.span(), error);
1514                    array_count = array_count.saturating_sub(1);
1515                }
1516            }
1517            TokenKind::LeftCurlyBracket => {
1518                receiver.error(current_token.span(), error);
1519                inline_table_count += 1;
1520            }
1521            TokenKind::RightCurlyBracket => {
1522                if inline_table_count == 0 && current_token.kind() == closing_kind {
1523                    receiver.inline_table_close(current_token.span(), error);
1524                    break;
1525                } else {
1526                    receiver.error(current_token.span(), error);
1527                    inline_table_count = inline_table_count.saturating_sub(1);
1528                }
1529            }
1530            TokenKind::Eof => {
1531                break;
1532            }
1533        }
1534    }
1535}
1536
1537#[cold]
1538fn on_missing_key(
1539    tokens: &mut Stream<'_>,
1540    token: &Token,
1541    invalid_description: &'static str,
1542    receiver: &mut dyn EventReceiver,
1543    error: &mut dyn ErrorSink,
1544) {
1545    error.report_error(
1546        ParseError::new(invalid_description)
1547            .with_context(token.span())
1548            .with_expected(&[Expected::Description("key")])
1549            .with_unexpected(token.span().before()),
1550    );
1551
1552    if token.kind() == TokenKind::Eof {
1553    } else if token.kind() == TokenKind::Newline {
1554        receiver.newline(token.span(), error);
1555    } else if token.kind() == TokenKind::Comment {
1556        on_comment(tokens, token, receiver, error);
1557    } else {
1558        receiver.error(token.span(), error);
1559    }
1560}
1561
1562#[cold]
1563fn on_missing_expression_key(
1564    tokens: &mut Stream<'_>,
1565    token: &Token,
1566    receiver: &mut dyn EventReceiver,
1567    error: &mut dyn ErrorSink,
1568) {
1569    error.report_error(
1570        ParseError::new("invalid key-value pair")
1571            .with_context(token.span())
1572            .with_expected(&[Expected::Description("key")])
1573            .with_unexpected(token.span().before()),
1574    );
1575
1576    receiver.error(token.span(), error);
1577    ignore_to_newline(tokens, receiver, error);
1578}
1579
1580#[cold]
1581fn on_missing_std_table(
1582    tokens: &mut Stream<'_>,
1583    token: &Token,
1584    receiver: &mut dyn EventReceiver,
1585    error: &mut dyn ErrorSink,
1586) {
1587    error.report_error(
1588        ParseError::new("missing table open")
1589            .with_context(token.span())
1590            .with_expected(&[Expected::Literal("[")])
1591            .with_unexpected(token.span().before()),
1592    );
1593
1594    receiver.error(token.span(), error);
1595    ignore_to_newline(tokens, receiver, error);
1596}
1597
1598fn next_token_if<'i, F: Fn(TokenKind) -> bool>(
1599    tokens: &mut Stream<'i>,
1600    pred: F,
1601) -> Option<&'i Token> {
1602    match tokens.first() {
1603        Some(next) if pred(next.kind()) => tokens.next_token(),
1604        _ => None,
1605    }
1606}
1607
1608fn seek(stream: &mut Stream<'_>, offset: isize) {
1609    let current = stream.checkpoint();
1610    stream.reset_to_start();
1611    let start = stream.checkpoint();
1612    let old_offset = current.offset_from(&start);
1613    let new_offset = (old_offset as isize).saturating_add(offset) as usize;
1614    if new_offset < stream.eof_offset() {
1615        #[cfg(feature = "unsafe")] // SAFETY: bounds were checked
1616        unsafe {
1617            stream.next_slice_unchecked(new_offset)
1618        };
1619        #[cfg(not(feature = "unsafe"))]
1620        stream.next_slice(new_offset);
1621    } else {
1622        stream.finish();
1623    }
1624}
1625
1626const UNQUOTED_STRING: &str = "unquoted string";