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