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