toml_parser/parser/
document.rs

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