Skip to main content

saphyr_parser/
scanner.rs

1//! Home to the YAML Scanner.
2//!
3//! The scanner is the lowest-level parsing utility. It is the lexer / tokenizer, reading input a
4//! character at a time and emitting tokens that can later be interpreted by the [`crate::parser`]
5//! to check for more context and validity.
6//!
7//! Due to the grammar of YAML, the scanner has to have some context and is not error-free.
8
9#![allow(clippy::cast_possible_wrap)]
10#![allow(clippy::cast_sign_loss)]
11
12use alloc::{
13    borrow::{Cow, ToOwned},
14    collections::VecDeque,
15    string::String,
16    vec::Vec,
17};
18use core::char;
19
20use thiserror::Error;
21
22use crate::{
23    char_traits::{
24        as_hex, is_anchor_char, is_blank_or_breakz, is_break, is_breakz, is_flow, is_hex,
25        is_tag_char, is_uri_char,
26    },
27    input::{Input, SkipTabs},
28};
29
30/// The encoding of the input. Currently, only UTF-8 is supported.
31#[derive(Clone, Copy, PartialEq, Debug, Eq)]
32pub enum TEncoding {
33    /// UTF-8 encoding.
34    Utf8,
35}
36
37/// The style as which the scalar was written in the YAML document.
38#[derive(Clone, Copy, PartialEq, Debug, Eq, Hash, PartialOrd, Ord)]
39pub enum ScalarStyle {
40    /// A YAML plain scalar.
41    Plain,
42    /// A YAML single quoted scalar.
43    SingleQuoted,
44    /// A YAML double quoted scalar.
45    DoubleQuoted,
46
47    /// A YAML literal block (`|` block).
48    ///
49    /// See [8.1.2](https://yaml.org/spec/1.2.2/#812-literal-style).
50    /// In literal blocks, any indented character is content, including white space characters.
51    /// There is no way to escape characters, nor to break a long line.
52    Literal,
53    /// A YAML folded block (`>` block).
54    ///
55    /// See [8.1.3](https://yaml.org/spec/1.2.2/#813-folded-style).
56    /// In folded blocks, any indented character is content, including white space characters.
57    /// There is no way to escape characters. Content is subject to line folding, allowing breaking
58    /// long lines.
59    Folded,
60}
61
62/// A location in a yaml document.
63#[derive(Clone, Copy, PartialEq, Debug, Eq, Default)]
64pub struct Marker {
65    /// The index (in chars) in the input string.
66    index: usize,
67    /// The line (1-indexed).
68    line: usize,
69    /// The column (1-indexed).
70    col: usize,
71}
72
73impl Marker {
74    /// Create a new [`Marker`] at the given position.
75    #[must_use]
76    pub fn new(index: usize, line: usize, col: usize) -> Marker {
77        Marker { index, line, col }
78    }
79
80    /// Return the index (in bytes) of the marker in the source.
81    #[must_use]
82    pub fn index(&self) -> usize {
83        self.index
84    }
85
86    /// Return the line of the marker in the source.
87    #[must_use]
88    pub fn line(&self) -> usize {
89        self.line
90    }
91
92    /// Return the column of the marker in the source.
93    #[must_use]
94    pub fn col(&self) -> usize {
95        self.col
96    }
97}
98
99/// A range of locations in a Yaml document.
100#[derive(Clone, Copy, PartialEq, Debug, Eq, Default)]
101pub struct Span {
102    /// The start (inclusive) of the range.
103    pub start: Marker,
104    /// The end (exclusive) of the range.
105    pub end: Marker,
106}
107
108impl Span {
109    /// Create a new [`Span`] for the given range.
110    #[must_use]
111    pub fn new(start: Marker, end: Marker) -> Span {
112        Span { start, end }
113    }
114
115    /// Create a empty [`Span`] at a given location.
116    ///
117    /// An empty span doesn't contain any characters, but its position may still be meaningful.
118    /// For example, for an indented sequence [`SequenceEnd`] has a location but an empty span.
119    ///
120    /// [`SequenceEnd`]: crate::Event::SequenceEnd
121    #[must_use]
122    pub fn empty(mark: Marker) -> Span {
123        Span {
124            start: mark,
125            end: mark,
126        }
127    }
128
129    /// Return the length of the span (in characters).
130    #[must_use]
131    pub fn len(&self) -> usize {
132        self.end.index - self.start.index
133    }
134
135    /// Return whether the [`Span`] has a length of zero.
136    #[must_use]
137    pub fn is_empty(&self) -> bool {
138        self.len() == 0
139    }
140}
141
142/// An error that occurred while scanning.
143#[derive(Clone, PartialEq, Debug, Eq, Error)]
144#[error("{} at byte {} line {} column {}", .info, .mark.index, .mark.line, .mark.col + 1,)]
145pub struct ScanError {
146    /// The position at which the error happened in the source.
147    mark: Marker,
148    /// Human-readable details about the error.
149    info: String,
150}
151
152impl ScanError {
153    /// Create a new error from a location and an error string.
154    #[must_use]
155    pub fn new(loc: Marker, info: String) -> ScanError {
156        ScanError { mark: loc, info }
157    }
158
159    /// Convenience alias for string slices.
160    #[must_use]
161    pub fn new_str(loc: Marker, info: &str) -> ScanError {
162        ScanError {
163            mark: loc,
164            info: info.to_owned(),
165        }
166    }
167
168    /// Return the marker pointing to the error in the source.
169    #[must_use]
170    pub fn marker(&self) -> &Marker {
171        &self.mark
172    }
173
174    /// Return the information string describing the error that happened.
175    #[must_use]
176    pub fn info(&self) -> &str {
177        self.info.as_ref()
178    }
179}
180
181/// The contents of a scanner token.
182#[derive(Clone, PartialEq, Debug, Eq)]
183pub enum TokenType<'input> {
184    /// The start of the stream. Sent first, before even [`TokenType::DocumentStart`].
185    StreamStart(TEncoding),
186    /// The end of the stream, EOF.
187    StreamEnd,
188    /// A YAML version directive.
189    VersionDirective(
190        /// Major
191        u32,
192        /// Minor
193        u32,
194    ),
195    /// A YAML tag directive (e.g.: `!!str`, `!foo!bar`, ...).
196    TagDirective(
197        /// Handle
198        Cow<'input, str>,
199        /// Prefix
200        Cow<'input, str>,
201    ),
202    /// The start of a YAML document (`---`).
203    DocumentStart,
204    /// The end of a YAML document (`...`).
205    DocumentEnd,
206    /// The start of a sequence block.
207    ///
208    /// Sequence blocks are arrays starting with a `-`.
209    BlockSequenceStart,
210    /// The start of a sequence mapping.
211    ///
212    /// Sequence mappings are "dictionaries" with "key: value" entries.
213    BlockMappingStart,
214    /// End of the corresponding `BlockSequenceStart` or `BlockMappingStart`.
215    BlockEnd,
216    /// Start of an inline sequence (`[ a, b ]`).
217    FlowSequenceStart,
218    /// End of an inline sequence.
219    FlowSequenceEnd,
220    /// Start of an inline mapping (`{ a: b, c: d }`).
221    FlowMappingStart,
222    /// End of an inline mapping.
223    FlowMappingEnd,
224    /// An entry in a block sequence (c.f.: [`TokenType::BlockSequenceStart`]).
225    BlockEntry,
226    /// An entry in a flow sequence (c.f.: [`TokenType::FlowSequenceStart`]).
227    FlowEntry,
228    /// A key in a mapping.
229    Key,
230    /// A value in a mapping.
231    Value,
232    /// A reference to an anchor.
233    Alias(Cow<'input, str>),
234    /// A YAML anchor (`&`/`*`).
235    Anchor(Cow<'input, str>),
236    /// A YAML tag (starting with bangs `!`).
237    Tag(
238        /// The handle of the tag.
239        String,
240        /// The suffix of the tag.
241        String,
242    ),
243    /// A regular YAML scalar.
244    Scalar(ScalarStyle, Cow<'input, str>),
245    /// A reserved YAML directive.
246    ReservedDirective(
247        /// Name
248        String,
249        /// Parameters
250        Vec<String>,
251    ),
252}
253
254/// A scanner token.
255#[derive(Clone, PartialEq, Debug, Eq)]
256pub struct Token<'input>(pub Span, pub TokenType<'input>);
257
258/// A scalar that was parsed and may correspond to a simple key.
259///
260/// Upon scanning the following yaml:
261/// ```yaml
262/// a: b
263/// ```
264/// We do not know that `a` is a key for a map until we have reached the following `:`. For this
265/// YAML, we would store `a` as a scalar token in the [`Scanner`], but not emit it yet. It would be
266/// kept inside the scanner until more context is fetched and we are able to know whether it is a
267/// plain scalar or a key.
268///
269/// For example, see the following 2 yaml documents:
270/// ```yaml
271/// ---
272/// a: b # Here, `a` is a key.
273/// ...
274/// ---
275/// a # Here, `a` is a plain scalar.
276/// ...
277/// ```
278/// An instance of [`SimpleKey`] is created in the [`Scanner`] when such ambiguity occurs.
279///
280/// In both documents, scanning `a` would lead to the creation of a [`SimpleKey`] with
281/// [`Self::possible`] set to `true`. The token for `a` would be pushed in the [`Scanner`] but not
282/// yet emitted. Instead, more context would be fetched (through [`Scanner::fetch_more_tokens`]).
283///
284/// In the first document, upon reaching the `:`, the [`SimpleKey`] would be inspected and our
285/// scalar `a` since it is a possible key, would be "turned" into a key. This is done by prepending
286/// a [`TokenType::Key`] to our scalar token in the [`Scanner`]. This way, the
287/// [`crate::parser::Parser`] would read the [`TokenType::Key`] token before the
288/// [`TokenType::Scalar`] token.
289///
290/// In the second document however, reaching the EOF would stale the [`SimpleKey`] and no
291/// [`TokenType::Key`] would be emitted by the scanner.
292#[derive(Clone, PartialEq, Debug, Eq)]
293struct SimpleKey {
294    /// Whether the token this [`SimpleKey`] refers to may still be a key.
295    ///
296    /// Sometimes, when we have more context, we notice that what we thought could be a key no
297    /// longer can be. In that case, [`Self::possible`] is set to `false`.
298    ///
299    /// For instance, let us consider the following invalid YAML:
300    /// ```yaml
301    /// key
302    ///   : value
303    /// ```
304    /// Upon reading the `\n` after `key`, the [`SimpleKey`] that was created for `key` is staled
305    /// and [`Self::possible`] set to `false`.
306    possible: bool,
307    /// Whether the token this [`SimpleKey`] refers to is required to be a key.
308    ///
309    /// With more context, we may know for sure that the token must be a key. If the YAML is
310    /// invalid, it may happen that the token be deemed not a key. In such event, an error has to
311    /// be raised. This boolean helps us know when to raise such error.
312    ///
313    /// TODO(ethiraric, 30/12/2023): Example of when this happens.
314    required: bool,
315    /// The index of the token referred to by the [`SimpleKey`].
316    ///
317    /// This is the index in the scanner, which takes into account both the tokens that have been
318    /// emitted and those about to be emitted. See [`Scanner::tokens_parsed`] and
319    /// [`Scanner::tokens`] for more details.
320    token_number: usize,
321    /// The position at which the token the [`SimpleKey`] refers to is.
322    mark: Marker,
323}
324
325impl SimpleKey {
326    /// Create a new [`SimpleKey`] at the given `Marker` and with the given flow level.
327    fn new(mark: Marker) -> SimpleKey {
328        SimpleKey {
329            possible: false,
330            required: false,
331            token_number: 0,
332            mark,
333        }
334    }
335}
336
337/// An indentation level on the stack of indentations.
338#[derive(Clone, Debug, Default)]
339struct Indent {
340    /// The former indentation level.
341    indent: isize,
342    /// Whether, upon closing, this indents generates a `BlockEnd` token.
343    ///
344    /// There are levels of indentation which do not start a block. Examples of this would be:
345    /// ```yaml
346    /// -
347    ///   foo # ok
348    /// -
349    /// bar # ko, bar needs to be indented further than the `-`.
350    /// - [
351    ///  baz, # ok
352    /// quux # ko, quux needs to be indented further than the '-'.
353    /// ] # ko, the closing bracket needs to be indented further than the `-`.
354    /// ```
355    ///
356    /// The indentation level created by the `-` is for a single entry in the sequence. Emitting a
357    /// `BlockEnd` when this indentation block ends would generate one `BlockEnd` per entry in the
358    /// sequence, although we must have exactly one to end the sequence.
359    needs_block_end: bool,
360}
361
362/// The knowledge we have about an implicit mapping.
363///
364/// Implicit mappings occur in flow sequences where the opening `{` for a mapping in a flow
365/// sequence is omitted:
366/// ```yaml
367/// [ a: b, c: d ]
368/// # Equivalent to
369/// [ { a: b }, { c: d } ]
370/// # Equivalent to
371/// - a: b
372/// - c: d
373/// ```
374///
375/// The state must be carefully tracked for each nested flow sequence since we must emit a
376/// [`FlowMappingStart`] event when encountering `a` and `c` in our previous example without a
377/// character hinting us. Similarly, we must emit a [`FlowMappingEnd`] event when we reach the `,`
378/// or the `]`. If the state is not properly tracked, we may omit to emit these events or emit them
379/// out-of-order.
380///
381/// [`FlowMappingStart`]: TokenType::FlowMappingStart
382/// [`FlowMappingEnd`]: TokenType::FlowMappingEnd
383#[derive(Debug, Clone, PartialEq)]
384enum ImplicitMappingState {
385    /// It is possible there is an implicit mapping.
386    ///
387    /// This state is the one when we have just encountered the opening `[`. We need more context
388    /// to know whether an implicit mapping follows.
389    Possible,
390    /// We are inside the implcit mapping.
391    ///
392    /// Note that this state is not set immediately (we need to have encountered the `:` to know).
393    Inside,
394}
395
396/// The YAML scanner.
397///
398/// This corresponds to the low-level interface when reading YAML. The scanner emits token as they
399/// are read (akin to a lexer), but it also holds sufficient context to be able to disambiguate
400/// some of the constructs. It has understanding of indentation and whitespace and is able to
401/// generate error messages for some invalid YAML constructs.
402///
403/// It is however not a full parser and needs [`crate::parser::Parser`] to fully detect invalid
404/// YAML documents.
405#[derive(Debug)]
406#[allow(clippy::struct_excessive_bools)]
407pub struct Scanner<'input, T> {
408    /// The input source.
409    ///
410    /// This must implement [`Input`].
411    input: T,
412    /// The position of the cursor within the reader.
413    mark: Marker,
414    /// Buffer for tokens to be returned.
415    ///
416    /// This buffer can hold some temporary tokens that are not yet ready to be returned. For
417    /// instance, if we just read a scalar, it can be a value or a key if an implicit mapping
418    /// follows. In this case, the token stays in the `VecDeque` but cannot be returned from
419    /// [`Self::next`] until we have more context.
420    tokens: VecDeque<Token<'input>>,
421    /// The last error that happened.
422    error: Option<ScanError>,
423
424    /// Whether we have already emitted the `StreamStart` token.
425    stream_start_produced: bool,
426    /// Whether we have already emitted the `StreamEnd` token.
427    stream_end_produced: bool,
428    /// In some flow contexts, the value of a mapping is allowed to be adjacent to the `:`. When it
429    /// is, the index at which the `:` may be must be stored in `adjacent_value_allowed_at`.
430    adjacent_value_allowed_at: usize,
431    /// Whether a simple key could potentially start at the current position.
432    ///
433    /// Simple keys are the opposite of complex keys which are keys starting with `?`.
434    simple_key_allowed: bool,
435    /// A stack of potential simple keys.
436    ///
437    /// Refer to the documentation of [`SimpleKey`] for a more in-depth explanation of what they
438    /// are.
439    simple_keys: Vec<SimpleKey>,
440    /// The current indentation level.
441    indent: isize,
442    /// List of all block indentation levels we are in (except the current one).
443    indents: Vec<Indent>,
444    /// Level of nesting of flow sequences.
445    flow_level: u8,
446    /// The number of tokens that have been returned from the scanner.
447    ///
448    /// This excludes the tokens from [`Self::tokens`].
449    tokens_parsed: usize,
450    /// Whether a token is ready to be taken from [`Self::tokens`].
451    token_available: bool,
452    /// Whether all characters encountered since the last newline were whitespace.
453    leading_whitespace: bool,
454    /// Whether we started a flow mapping.
455    ///
456    /// This is used to detect implicit flow mapping starts such as:
457    /// ```yaml
458    /// [ : foo ] # { null: "foo" }
459    /// ```
460    flow_mapping_started: bool,
461    /// An array of states, representing whether flow sequences have implicit mappings.
462    ///
463    /// When a flow mapping is possible (when encountering the first `[` or a `,` in a sequence),
464    /// the state is set to [`Possible`].
465    /// When we encounter the `:`, we know we are in an implicit mapping and can set the state to
466    /// [`Inside`].
467    ///
468    /// There is one entry in this [`Vec`] for each nested flow sequence that we are in.
469    /// The entries are created with the opening `]` and popped with the closing `]`.
470    ///
471    /// [`Possible`]: ImplicitMappingState::Possible
472    /// [`Inside`]: ImplicitMappingState::Inside
473    implicit_flow_mapping_states: Vec<ImplicitMappingState>,
474    /// If a plain scalar was terminated by a `#` comment on its line, we set this
475    /// to detect an illegal multiline continuation on the following line.
476    interrupted_plain_by_comment: Option<Marker>,
477    buf_leading_break: String,
478    buf_trailing_breaks: String,
479    buf_whitespaces: String,
480}
481
482impl<T: Input + Clone> Clone for Scanner<'_, T> {
483    fn clone(&self) -> Self {
484        Self {
485            input: self.input.clone(),
486            mark: self.mark,
487            tokens: self.tokens.clone(),
488            error: self.error.clone(),
489            stream_start_produced: self.stream_start_produced,
490            stream_end_produced: self.stream_end_produced,
491            adjacent_value_allowed_at: self.adjacent_value_allowed_at,
492            simple_key_allowed: self.simple_key_allowed,
493            simple_keys: self.simple_keys.clone(),
494            indent: self.indent,
495            indents: self.indents.clone(),
496            flow_level: self.flow_level,
497            tokens_parsed: self.tokens_parsed,
498            token_available: self.token_available,
499            leading_whitespace: self.leading_whitespace,
500            flow_mapping_started: self.flow_mapping_started,
501            implicit_flow_mapping_states: self.implicit_flow_mapping_states.clone(),
502            interrupted_plain_by_comment: self.interrupted_plain_by_comment,
503            buf_leading_break: self.buf_leading_break.clone(),
504            buf_trailing_breaks: self.buf_trailing_breaks.clone(),
505            buf_whitespaces: self.buf_whitespaces.clone(),
506        }
507    }
508}
509
510impl<'input, T: Input> Iterator for Scanner<'input, T> {
511    type Item = Token<'input>;
512
513    fn next(&mut self) -> Option<Self::Item> {
514        if self.error.is_some() {
515            return None;
516        }
517        match self.next_token() {
518            Ok(Some(tok)) => {
519                debug_print!(
520                    "    \x1B[;32m\u{21B3} {:?} \x1B[;36m{:?}\x1B[;m",
521                    tok.1,
522                    tok.0
523                );
524                Some(tok)
525            }
526            Ok(tok) => tok,
527            Err(e) => {
528                self.error = Some(e);
529                None
530            }
531        }
532    }
533}
534
535/// A convenience alias for scanner functions that may fail without returning a value.
536pub type ScanResult = Result<(), ScanError>;
537
538impl<'input, T: Input> Scanner<'input, T> {
539    /// Creates the YAML tokenizer.
540    pub fn new(input: T) -> Self {
541        Scanner {
542            input,
543            mark: Marker::new(0, 1, 0),
544            tokens: VecDeque::new(),
545            error: None,
546
547            stream_start_produced: false,
548            stream_end_produced: false,
549            adjacent_value_allowed_at: 0,
550            simple_key_allowed: true,
551            simple_keys: Vec::new(),
552            indent: -1,
553            indents: Vec::new(),
554            flow_level: 0,
555            tokens_parsed: 0,
556            token_available: false,
557            leading_whitespace: true,
558            flow_mapping_started: false,
559            implicit_flow_mapping_states: vec![],
560            interrupted_plain_by_comment: None,
561
562            buf_leading_break: String::new(),
563            buf_trailing_breaks: String::new(),
564            buf_whitespaces: String::new(),
565        }
566    }
567
568    /// Get a copy of the last error that was encountered, if any.
569    ///
570    /// This does not clear the error state and further calls to [`Self::get_error`] will return (a
571    /// clone of) the same error.
572    #[inline]
573    pub fn get_error(&self) -> Option<ScanError> {
574        self.error.clone()
575    }
576
577    /// Consume the next character. It is assumed the next character is a blank.
578    #[inline]
579    fn skip_blank(&mut self) {
580        self.input.skip();
581
582        self.mark.index += 1;
583        self.mark.col += 1;
584    }
585
586    /// Consume the next character. It is assumed the next character is not a blank.
587    #[inline]
588    fn skip_non_blank(&mut self) {
589        self.input.skip();
590
591        self.mark.index += 1;
592        self.mark.col += 1;
593        self.leading_whitespace = false;
594    }
595
596    /// Consume the next characters. It is assumed none of the next characters are blanks.
597    #[inline]
598    fn skip_n_non_blank(&mut self, count: usize) {
599        self.input.skip_n(count);
600
601        self.mark.index += count;
602        self.mark.col += count;
603        self.leading_whitespace = false;
604    }
605
606    /// Consume the next character. It is assumed the next character is a newline.
607    #[inline]
608    fn skip_nl(&mut self) {
609        self.input.skip();
610
611        self.mark.index += 1;
612        self.mark.col = 0;
613        self.mark.line += 1;
614        self.leading_whitespace = true;
615    }
616
617    /// Consume a linebreak (either CR, LF or CRLF), if any. Do nothing if there's none.
618    #[inline]
619    fn skip_linebreak(&mut self) {
620        if self.input.next_2_are('\r', '\n') {
621            // While technically not a blank, this does not matter as `self.leading_whitespace`
622            // will be reset by `skip_nl`.
623            self.skip_blank();
624            self.skip_nl();
625        } else if self.input.next_is_break() {
626            self.skip_nl();
627        }
628    }
629
630    /// Return whether the [`TokenType::StreamStart`] event has been emitted.
631    #[inline]
632    pub fn stream_started(&self) -> bool {
633        self.stream_start_produced
634    }
635
636    /// Return whether the [`TokenType::StreamEnd`] event has been emitted.
637    #[inline]
638    pub fn stream_ended(&self) -> bool {
639        self.stream_end_produced
640    }
641
642    /// Get the current position in the input stream.
643    #[inline]
644    pub fn mark(&self) -> Marker {
645        self.mark
646    }
647
648    // Read and consume a line break (either `\r`, `\n` or `\r\n`).
649    //
650    // A `\n` is pushed into `s`.
651    //
652    // # Panics (in debug)
653    // If the next characters do not correspond to a line break.
654    #[inline]
655    fn read_break(&mut self, s: &mut String) {
656        self.skip_break();
657        s.push('\n');
658    }
659
660    // Read and consume a line break (either `\r`, `\n` or `\r\n`).
661    //
662    // # Panics (in debug)
663    // If the next characters do not correspond to a line break.
664    #[inline]
665    fn skip_break(&mut self) {
666        let c = self.input.peek();
667        let nc = self.input.peek_nth(1);
668        debug_assert!(is_break(c));
669        if c == '\r' && nc == '\n' {
670            self.skip_blank();
671        }
672        self.skip_nl();
673    }
674
675    /// Insert a token at the given position.
676    fn insert_token(&mut self, pos: usize, tok: Token<'input>) {
677        let old_len = self.tokens.len();
678        assert!(pos <= old_len);
679        self.tokens.insert(pos, tok);
680    }
681
682    fn allow_simple_key(&mut self) {
683        self.simple_key_allowed = true;
684    }
685
686    fn disallow_simple_key(&mut self) {
687        self.simple_key_allowed = false;
688    }
689
690    /// Fetch the next token in the stream.
691    ///
692    /// # Errors
693    /// Returns `ScanError` when the scanner does not find the next expected token.
694    pub fn fetch_next_token(&mut self) -> ScanResult {
695        self.input.lookahead(1);
696
697        if !self.stream_start_produced {
698            self.fetch_stream_start();
699            return Ok(());
700        }
701        self.skip_to_next_token()?;
702
703        debug_print!(
704            "  \x1B[38;5;244m\u{2192} fetch_next_token after whitespace {:?} {:?}\x1B[m",
705            self.mark,
706            self.input.peek()
707        );
708
709        self.stale_simple_keys()?;
710
711        let mark = self.mark;
712        self.unroll_indent(mark.col as isize);
713
714        self.input.lookahead(4);
715
716        if self.input.next_is_z() {
717            self.fetch_stream_end()?;
718            return Ok(());
719        }
720
721        if self.mark.col == 0 {
722            if self.input.next_char_is('%') {
723                return self.fetch_directive();
724            } else if self.input.next_is_document_start() {
725                return self.fetch_document_indicator(TokenType::DocumentStart);
726            } else if self.input.next_is_document_end() {
727                self.fetch_document_indicator(TokenType::DocumentEnd)?;
728                self.skip_ws_to_eol(SkipTabs::Yes)?;
729                if !self.input.next_is_breakz() {
730                    return Err(ScanError::new_str(
731                        self.mark,
732                        "invalid content after document end marker",
733                    ));
734                }
735                return Ok(());
736            }
737        }
738
739        if (self.mark.col as isize) < self.indent {
740            return Err(ScanError::new_str(self.mark, "invalid indentation"));
741        }
742
743        let c = self.input.peek();
744        let nc = self.input.peek_nth(1);
745        match c {
746            '[' => self.fetch_flow_collection_start(TokenType::FlowSequenceStart),
747            '{' => self.fetch_flow_collection_start(TokenType::FlowMappingStart),
748            ']' => self.fetch_flow_collection_end(TokenType::FlowSequenceEnd),
749            '}' => self.fetch_flow_collection_end(TokenType::FlowMappingEnd),
750            ',' => self.fetch_flow_entry(),
751            '-' if is_blank_or_breakz(nc) => self.fetch_block_entry(),
752            '?' if is_blank_or_breakz(nc) => self.fetch_key(),
753            ':' if is_blank_or_breakz(nc) => self.fetch_value(),
754            ':' if self.flow_level > 0
755                && (is_flow(nc) || self.mark.index == self.adjacent_value_allowed_at) =>
756            {
757                self.fetch_flow_value()
758            }
759            // Is it an alias?
760            '*' => self.fetch_anchor(true),
761            // Is it an anchor?
762            '&' => self.fetch_anchor(false),
763            '!' => self.fetch_tag(),
764            // Is it a literal scalar?
765            '|' if self.flow_level == 0 => self.fetch_block_scalar(true),
766            // Is it a folded scalar?
767            '>' if self.flow_level == 0 => self.fetch_block_scalar(false),
768            '\'' => self.fetch_flow_scalar(true),
769            '"' => self.fetch_flow_scalar(false),
770            // plain scalar
771            '-' if !is_blank_or_breakz(nc) => self.fetch_plain_scalar(),
772            ':' | '?' if !is_blank_or_breakz(nc) && self.flow_level == 0 => {
773                self.fetch_plain_scalar()
774            }
775            '%' | '@' | '`' => Err(ScanError::new(
776                self.mark,
777                format!("unexpected character: `{c}'"),
778            )),
779            _ => self.fetch_plain_scalar(),
780        }
781    }
782
783    /// Return the next token in the stream.
784    /// # Errors
785    /// Returns `ScanError` when scanning fails to find an expected next token.
786    pub fn next_token(&mut self) -> Result<Option<Token<'input>>, ScanError> {
787        if self.stream_end_produced {
788            return Ok(None);
789        }
790
791        if !self.token_available {
792            self.fetch_more_tokens()?;
793        }
794        let Some(t) = self.tokens.pop_front() else {
795            return Err(ScanError::new_str(
796                self.mark,
797                "did not find expected next token",
798            ));
799        };
800        self.token_available = false;
801        self.tokens_parsed += 1;
802
803        if let TokenType::StreamEnd = t.1 {
804            self.stream_end_produced = true;
805        }
806        Ok(Some(t))
807    }
808
809    /// Fetch tokens from the token stream.
810    /// # Errors
811    /// Returns `ScanError` when loading fails.
812    pub fn fetch_more_tokens(&mut self) -> ScanResult {
813        let mut need_more;
814        loop {
815            if self.tokens.is_empty() {
816                need_more = true;
817            } else {
818                need_more = false;
819                // Stale potential keys that we know won't be keys.
820                self.stale_simple_keys()?;
821                // If our next token to be emitted may be a key, fetch more context.
822                for sk in &self.simple_keys {
823                    if sk.possible && sk.token_number == self.tokens_parsed {
824                        need_more = true;
825                        break;
826                    }
827                }
828            }
829
830            if !need_more {
831                break;
832            }
833            self.fetch_next_token()?;
834        }
835        self.token_available = true;
836
837        Ok(())
838    }
839
840    /// Mark simple keys that can no longer be keys as such.
841    ///
842    /// This function sets `possible` to `false` to each key that, now we have more context, we
843    /// know will not be keys.
844    ///
845    /// # Errors
846    /// This function returns an error if one of the key we would stale was required to be a key.
847    fn stale_simple_keys(&mut self) -> ScanResult {
848        for sk in &mut self.simple_keys {
849            if sk.possible
850                // If not in a flow construct, simple keys cannot span multiple lines.
851                && self.flow_level == 0
852                    && (sk.mark.line < self.mark.line || sk.mark.index + 1024 < self.mark.index)
853            {
854                if sk.required {
855                    return Err(ScanError::new_str(self.mark, "simple key expect ':'"));
856                }
857                sk.possible = false;
858            }
859        }
860        Ok(())
861    }
862
863    /// Skip over all whitespace (`\t`, ` `, `\n`, `\r`) and comments until the next token.
864    ///
865    /// # Errors
866    /// This function returns an error if a tabulation is encountered where there should not be
867    /// one.
868    fn skip_to_next_token(&mut self) -> ScanResult {
869        loop {
870            // TODO(chenyh) BOM
871            match self.input.look_ch() {
872                // Tabs may not be used as indentation.
873                // "Indentation" only exists as long as a block is started, but does not exist
874                // inside of flow-style constructs. Tabs are allowed as part of leading
875                // whitespaces outside of indentation.
876                // If a flow-style construct is in an indented block, its contents must still be
877                // indented. Also, tabs are allowed anywhere in it if it has no content.
878                '\t' if self.is_within_block()
879                    && self.leading_whitespace
880                    && (self.mark.col as isize) < self.indent =>
881                {
882                    self.skip_ws_to_eol(SkipTabs::Yes)?;
883                    // If we have content on that line with a tab, return an error.
884                    if !self.input.next_is_breakz() {
885                        return Err(ScanError::new_str(
886                            self.mark,
887                            "tabs disallowed within this context (block indentation)",
888                        ));
889                    }
890                }
891                '\t' | ' ' => self.skip_blank(),
892                '\n' | '\r' => {
893                    self.input.lookahead(2);
894                    self.skip_linebreak();
895                    if self.flow_level == 0 {
896                        self.allow_simple_key();
897                    }
898                }
899                '#' => {
900                    let comment_length = self.input.skip_while_non_breakz();
901                    self.mark.index += comment_length;
902                    self.mark.col += comment_length;
903                }
904                _ => break,
905            }
906        }
907        // If a plain scalar was interrupted by a comment, and the next line could
908        // continue the scalar in block context, this is invalid.
909        if let Some(err_mark) = self.interrupted_plain_by_comment.take() {
910            // Ensure enough lookahead for the check below (peek and peek_nth) and for
911            // document indicator detection which needs 4 chars.
912            self.input.lookahead(4);
913            // BS4K should only trigger when the continuation would start on the immediate next
914            // line (no intervening empty/comment-only lines). A blank line resets the folding
915            // opportunity and thus should not error.
916            let is_immediate_next_line = self.mark.line == err_mark.line + 1;
917            if self.flow_level == 0
918                && is_immediate_next_line
919                && self.mark.col as isize > self.indent
920                && !self.input.next_is_z()
921                && !self.input.next_is_document_indicator()
922                && self.input.next_can_be_plain_scalar(false)
923            {
924                return Err(ScanError::new_str(
925                    err_mark,
926                    "comment intercepting the multiline text",
927                ));
928            }
929        }
930        Ok(())
931    }
932
933    /// Skip over YAML whitespace (` `, `\n`, `\r`).
934    ///
935    /// # Errors
936    /// This function returns an error if no whitespace was found.
937    fn skip_yaml_whitespace(&mut self) -> ScanResult {
938        let mut need_whitespace = true;
939        loop {
940            match self.input.look_ch() {
941                ' ' => {
942                    self.skip_blank();
943
944                    need_whitespace = false;
945                }
946                '\n' | '\r' => {
947                    self.input.lookahead(2);
948                    self.skip_linebreak();
949                    if self.flow_level == 0 {
950                        self.allow_simple_key();
951                    }
952                    need_whitespace = false;
953                }
954                '#' => {
955                    let comment_length = self.input.skip_while_non_breakz();
956                    self.mark.index += comment_length;
957                    self.mark.col += comment_length;
958                }
959                _ => break,
960            }
961        }
962
963        if need_whitespace {
964            Err(ScanError::new_str(self.mark(), "expected whitespace"))
965        } else {
966            Ok(())
967        }
968    }
969
970    fn skip_ws_to_eol(&mut self, skip_tabs: SkipTabs) -> Result<SkipTabs, ScanError> {
971        let (n_bytes, result) = self.input.skip_ws_to_eol(skip_tabs);
972        self.mark.col += n_bytes;
973        self.mark.index += n_bytes;
974        result.map_err(|msg| ScanError::new_str(self.mark, msg))
975    }
976
977    fn fetch_stream_start(&mut self) {
978        let mark = self.mark;
979        self.indent = -1;
980        self.stream_start_produced = true;
981        self.allow_simple_key();
982        self.tokens.push_back(Token(
983            Span::empty(mark),
984            TokenType::StreamStart(TEncoding::Utf8),
985        ));
986        self.simple_keys.push(SimpleKey::new(Marker::new(0, 0, 0)));
987    }
988
989    fn fetch_stream_end(&mut self) -> ScanResult {
990        // force new line
991        if self.mark.col != 0 {
992            self.mark.col = 0;
993            self.mark.line += 1;
994        }
995
996        // If the stream ended, we won't have more context. We can stall all the simple keys we
997        // had. If one was required, however, that was an error and we must propagate it.
998        for sk in &mut self.simple_keys {
999            if sk.required && sk.possible {
1000                return Err(ScanError::new_str(self.mark, "simple key expected"));
1001            }
1002            sk.possible = false;
1003        }
1004
1005        self.unroll_indent(-1);
1006        self.remove_simple_key()?;
1007        self.disallow_simple_key();
1008
1009        self.tokens
1010            .push_back(Token(Span::empty(self.mark), TokenType::StreamEnd));
1011        Ok(())
1012    }
1013
1014    fn fetch_directive(&mut self) -> ScanResult {
1015        self.unroll_indent(-1);
1016        self.remove_simple_key()?;
1017
1018        self.disallow_simple_key();
1019
1020        let tok = self.scan_directive()?;
1021        self.tokens.push_back(tok);
1022
1023        Ok(())
1024    }
1025
1026    fn scan_directive(&mut self) -> Result<Token<'input>, ScanError> {
1027        let start_mark = self.mark;
1028        self.skip_non_blank();
1029
1030        let name = self.scan_directive_name()?;
1031        let tok = match name.as_ref() {
1032            "YAML" => self.scan_version_directive_value(&start_mark)?,
1033            "TAG" => self.scan_tag_directive_value(&start_mark)?,
1034            _ => {
1035                let mut params = Vec::new();
1036                while self.input.next_is_blank() {
1037                    let n_blanks = self.input.skip_while_blank();
1038                    self.mark.index += n_blanks;
1039                    self.mark.col += n_blanks;
1040
1041                    if !is_blank_or_breakz(self.input.peek()) {
1042                        let mut param = String::new();
1043                        let n_chars = self.input.fetch_while_is_yaml_non_space(&mut param);
1044                        self.mark.index += n_chars;
1045                        self.mark.col += n_chars;
1046                        params.push(param);
1047                    }
1048                }
1049
1050                Token(
1051                    Span::new(start_mark, self.mark),
1052                    TokenType::ReservedDirective(name, params),
1053                )
1054            }
1055        };
1056
1057        self.skip_ws_to_eol(SkipTabs::Yes)?;
1058
1059        if self.input.next_is_breakz() {
1060            self.input.lookahead(2);
1061            self.skip_linebreak();
1062            Ok(tok)
1063        } else {
1064            Err(ScanError::new_str(
1065                start_mark,
1066                "while scanning a directive, did not find expected comment or line break",
1067            ))
1068        }
1069    }
1070
1071    fn scan_version_directive_value(&mut self, mark: &Marker) -> Result<Token<'input>, ScanError> {
1072        let n_blanks = self.input.skip_while_blank();
1073        self.mark.index += n_blanks;
1074        self.mark.col += n_blanks;
1075
1076        let major = self.scan_version_directive_number(mark)?;
1077
1078        if self.input.peek() != '.' {
1079            return Err(ScanError::new_str(
1080                *mark,
1081                "while scanning a YAML directive, did not find expected digit or '.' character",
1082            ));
1083        }
1084        self.skip_non_blank();
1085
1086        let minor = self.scan_version_directive_number(mark)?;
1087
1088        Ok(Token(
1089            Span::new(*mark, self.mark),
1090            TokenType::VersionDirective(major, minor),
1091        ))
1092    }
1093
1094    fn scan_directive_name(&mut self) -> Result<String, ScanError> {
1095        let start_mark = self.mark;
1096        let mut string = String::new();
1097
1098        let n_chars = self.input.fetch_while_is_yaml_non_space(&mut string);
1099        self.mark.index += n_chars;
1100        self.mark.col += n_chars;
1101
1102        if string.is_empty() {
1103            return Err(ScanError::new_str(
1104                start_mark,
1105                "while scanning a directive, could not find expected directive name",
1106            ));
1107        }
1108
1109        if !is_blank_or_breakz(self.input.peek()) {
1110            return Err(ScanError::new_str(
1111                start_mark,
1112                "while scanning a directive, found unexpected non-alphabetical character",
1113            ));
1114        }
1115
1116        Ok(string)
1117    }
1118
1119    fn scan_version_directive_number(&mut self, mark: &Marker) -> Result<u32, ScanError> {
1120        let mut val = 0u32;
1121        let mut length = 0usize;
1122        while let Some(digit) = self.input.look_ch().to_digit(10) {
1123            if length + 1 > 9 {
1124                return Err(ScanError::new_str(
1125                    *mark,
1126                    "while scanning a YAML directive, found extremely long version number",
1127                ));
1128            }
1129            length += 1;
1130            val = val * 10 + digit;
1131            self.skip_non_blank();
1132        }
1133
1134        if length == 0 {
1135            return Err(ScanError::new_str(
1136                *mark,
1137                "while scanning a YAML directive, did not find expected version number",
1138            ));
1139        }
1140
1141        Ok(val)
1142    }
1143
1144    fn scan_tag_directive_value(&mut self, mark: &Marker) -> Result<Token<'input>, ScanError> {
1145        let n_blanks = self.input.skip_while_blank();
1146        self.mark.index += n_blanks;
1147        self.mark.col += n_blanks;
1148
1149        let handle = self.scan_tag_handle(true, mark)?;
1150
1151        let n_blanks = self.input.skip_while_blank();
1152        self.mark.index += n_blanks;
1153        self.mark.col += n_blanks;
1154
1155        let prefix = self.scan_tag_prefix(mark)?;
1156
1157        self.input.lookahead(1);
1158
1159        if self.input.next_is_blank_or_breakz() {
1160            Ok(Token(
1161                Span::new(*mark, self.mark),
1162                TokenType::TagDirective(handle.into(), prefix.into()),
1163            ))
1164        } else {
1165            Err(ScanError::new_str(
1166                *mark,
1167                "while scanning TAG, did not find expected whitespace or line break",
1168            ))
1169        }
1170    }
1171
1172    fn fetch_tag(&mut self) -> ScanResult {
1173        self.save_simple_key();
1174        self.disallow_simple_key();
1175
1176        let tok = self.scan_tag()?;
1177        self.tokens.push_back(tok);
1178        Ok(())
1179    }
1180
1181    fn scan_tag(&mut self) -> Result<Token<'input>, ScanError> {
1182        let start_mark = self.mark;
1183        let mut handle = String::new();
1184        let mut suffix;
1185
1186        // Check if the tag is in the canonical form (verbatim).
1187        self.input.lookahead(2);
1188
1189        if self.input.nth_char_is(1, '<') {
1190            suffix = self.scan_verbatim_tag(&start_mark)?;
1191        } else {
1192            // The tag has either the '!suffix' or the '!handle!suffix'
1193            handle = self.scan_tag_handle(false, &start_mark)?;
1194            // Check if it is, indeed, handle.
1195            if handle.len() >= 2 && handle.starts_with('!') && handle.ends_with('!') {
1196                // A tag handle starting with "!!" is a secondary tag handle.
1197                let is_secondary_handle = handle == "!!";
1198                suffix =
1199                    self.scan_tag_shorthand_suffix(false, is_secondary_handle, "", &start_mark)?;
1200            } else {
1201                suffix = self.scan_tag_shorthand_suffix(false, false, &handle, &start_mark)?;
1202                "!".clone_into(&mut handle);
1203                // A special case: the '!' tag.  Set the handle to '' and the
1204                // suffix to '!'.
1205                if suffix.is_empty() {
1206                    handle.clear();
1207                    "!".clone_into(&mut suffix);
1208                }
1209            }
1210        }
1211
1212        if is_blank_or_breakz(self.input.look_ch())
1213            || (self.flow_level > 0 && self.input.next_is_flow())
1214        {
1215            // XXX: ex 7.2, an empty scalar can follow a secondary tag
1216            Ok(Token(
1217                Span::new(start_mark, self.mark),
1218                TokenType::Tag(handle, suffix),
1219            ))
1220        } else {
1221            Err(ScanError::new_str(
1222                start_mark,
1223                "while scanning a tag, did not find expected whitespace or line break",
1224            ))
1225        }
1226    }
1227
1228    fn scan_tag_handle(&mut self, directive: bool, mark: &Marker) -> Result<String, ScanError> {
1229        let mut string = String::new();
1230        if self.input.look_ch() != '!' {
1231            return Err(ScanError::new_str(
1232                *mark,
1233                "while scanning a tag, did not find expected '!'",
1234            ));
1235        }
1236
1237        string.push(self.input.peek());
1238        self.skip_non_blank();
1239
1240        let n_chars = self.input.fetch_while_is_alpha(&mut string);
1241        self.mark.index += n_chars;
1242        self.mark.col += n_chars;
1243
1244        // Check if the trailing character is '!' and copy it.
1245        if self.input.peek() == '!' {
1246            string.push(self.input.peek());
1247            self.skip_non_blank();
1248        } else if directive && string != "!" {
1249            // It's either the '!' tag or not really a tag handle.  If it's a %TAG
1250            // directive, it's an error.  If it's a tag token, it must be a part of
1251            // URI.
1252            return Err(ScanError::new_str(
1253                *mark,
1254                "while parsing a tag directive, did not find expected '!'",
1255            ));
1256        }
1257        Ok(string)
1258    }
1259
1260    /// Scan for a tag prefix (6.8.2.2).
1261    ///
1262    /// There are 2 kinds of tag prefixes:
1263    ///   - Local: Starts with a `!`, contains only URI chars (`!foo`)
1264    ///   - Global: Starts with a tag char, contains then URI chars (`!foo,2000:app/`)
1265    fn scan_tag_prefix(&mut self, start_mark: &Marker) -> Result<String, ScanError> {
1266        let mut string = String::new();
1267
1268        if self.input.look_ch() == '!' {
1269            // If we have a local tag, insert and skip `!`.
1270            string.push(self.input.peek());
1271            self.skip_non_blank();
1272        } else if !is_tag_char(self.input.peek()) {
1273            // Otherwise, check if the first global tag character is valid.
1274            return Err(ScanError::new_str(
1275                *start_mark,
1276                "invalid global tag character",
1277            ));
1278        } else if self.input.peek() == '%' {
1279            // If it is valid and an escape sequence, escape it.
1280            string.push(self.scan_uri_escapes(start_mark)?);
1281        } else {
1282            // Otherwise, push the first character.
1283            string.push(self.input.peek());
1284            self.skip_non_blank();
1285        }
1286
1287        while is_uri_char(self.input.look_ch()) {
1288            if self.input.peek() == '%' {
1289                string.push(self.scan_uri_escapes(start_mark)?);
1290            } else {
1291                string.push(self.input.peek());
1292                self.skip_non_blank();
1293            }
1294        }
1295
1296        Ok(string)
1297    }
1298
1299    /// Scan for a verbatim tag.
1300    ///
1301    /// The prefixing `!<` must _not_ have been skipped.
1302    fn scan_verbatim_tag(&mut self, start_mark: &Marker) -> Result<String, ScanError> {
1303        // Eat `!<`
1304        self.skip_non_blank();
1305        self.skip_non_blank();
1306
1307        let mut string = String::new();
1308        while is_uri_char(self.input.look_ch()) {
1309            if self.input.peek() == '%' {
1310                string.push(self.scan_uri_escapes(start_mark)?);
1311            } else {
1312                string.push(self.input.peek());
1313                self.skip_non_blank();
1314            }
1315        }
1316
1317        if self.input.peek() != '>' {
1318            return Err(ScanError::new_str(
1319                *start_mark,
1320                "while scanning a verbatim tag, did not find the expected '>'",
1321            ));
1322        }
1323        self.skip_non_blank();
1324
1325        Ok(string)
1326    }
1327
1328    fn scan_tag_shorthand_suffix(
1329        &mut self,
1330        _directive: bool,
1331        _is_secondary: bool,
1332        head: &str,
1333        mark: &Marker,
1334    ) -> Result<String, ScanError> {
1335        let mut length = head.len();
1336        let mut string = String::new();
1337
1338        // Copy the head if needed.
1339        // Note that we don't copy the leading '!' character.
1340        if length > 1 {
1341            string.extend(head.chars().skip(1));
1342        }
1343
1344        while is_tag_char(self.input.look_ch()) {
1345            // Check if it is a URI-escape sequence.
1346            if self.input.peek() == '%' {
1347                string.push(self.scan_uri_escapes(mark)?);
1348            } else {
1349                string.push(self.input.peek());
1350                self.skip_non_blank();
1351            }
1352
1353            length += 1;
1354        }
1355
1356        if length == 0 {
1357            return Err(ScanError::new_str(
1358                *mark,
1359                "while parsing a tag, did not find expected tag URI",
1360            ));
1361        }
1362
1363        Ok(string)
1364    }
1365
1366    fn scan_uri_escapes(&mut self, mark: &Marker) -> Result<char, ScanError> {
1367        let mut width = 0usize;
1368        let mut code = 0u32;
1369        loop {
1370            self.input.lookahead(3);
1371
1372            let c = self.input.peek_nth(1);
1373            let nc = self.input.peek_nth(2);
1374
1375            if !(self.input.peek() == '%' && is_hex(c) && is_hex(nc)) {
1376                return Err(ScanError::new_str(
1377                    *mark,
1378                    "while parsing a tag, found an invalid escape sequence",
1379                ));
1380            }
1381
1382            let byte = (as_hex(c) << 4) + as_hex(nc);
1383            if width == 0 {
1384                width = match byte {
1385                    _ if byte & 0x80 == 0x00 => 1,
1386                    _ if byte & 0xE0 == 0xC0 => 2,
1387                    _ if byte & 0xF0 == 0xE0 => 3,
1388                    _ if byte & 0xF8 == 0xF0 => 4,
1389                    _ => {
1390                        return Err(ScanError::new_str(
1391                            *mark,
1392                            "while parsing a tag, found an incorrect leading UTF-8 byte",
1393                        ));
1394                    }
1395                };
1396                code = byte;
1397            } else {
1398                if byte & 0xc0 != 0x80 {
1399                    return Err(ScanError::new_str(
1400                        *mark,
1401                        "while parsing a tag, found an incorrect trailing UTF-8 byte",
1402                    ));
1403                }
1404                code = (code << 8) + byte;
1405            }
1406
1407            self.skip_n_non_blank(3);
1408
1409            width -= 1;
1410            if width == 0 {
1411                break;
1412            }
1413        }
1414
1415        match char::from_u32(code) {
1416            Some(ch) => Ok(ch),
1417            None => Err(ScanError::new_str(
1418                *mark,
1419                "while parsing a tag, found an invalid UTF-8 codepoint",
1420            )),
1421        }
1422    }
1423
1424    fn fetch_anchor(&mut self, alias: bool) -> ScanResult {
1425        self.save_simple_key();
1426        self.disallow_simple_key();
1427
1428        let tok = self.scan_anchor(alias)?;
1429
1430        self.tokens.push_back(tok);
1431
1432        Ok(())
1433    }
1434
1435    fn scan_anchor(&mut self, alias: bool) -> Result<Token<'input>, ScanError> {
1436        let mut string = String::new();
1437        let start_mark = self.mark;
1438
1439        self.skip_non_blank();
1440        while is_anchor_char(self.input.look_ch()) {
1441            string.push(self.input.peek());
1442            self.skip_non_blank();
1443        }
1444
1445        if string.is_empty() {
1446            return Err(ScanError::new_str(
1447                start_mark,
1448                "while scanning an anchor or alias, did not find expected alphabetic or numeric character",
1449            ));
1450        }
1451
1452        let tok = if alias {
1453            TokenType::Alias(string.into())
1454        } else {
1455            TokenType::Anchor(string.into())
1456        };
1457        Ok(Token(Span::new(start_mark, self.mark), tok))
1458    }
1459
1460    fn fetch_flow_collection_start(&mut self, tok: TokenType<'input>) -> ScanResult {
1461        // The indicators '[' and '{' may start a simple key.
1462        self.save_simple_key();
1463
1464        self.roll_one_col_indent();
1465        self.increase_flow_level()?;
1466
1467        self.allow_simple_key();
1468
1469        let start_mark = self.mark;
1470        self.skip_non_blank();
1471
1472        if tok == TokenType::FlowMappingStart {
1473            self.flow_mapping_started = true;
1474        } else {
1475            self.implicit_flow_mapping_states
1476                .push(ImplicitMappingState::Possible);
1477        }
1478
1479        self.skip_ws_to_eol(SkipTabs::Yes)?;
1480
1481        self.tokens
1482            .push_back(Token(Span::new(start_mark, self.mark), tok));
1483        Ok(())
1484    }
1485
1486    fn fetch_flow_collection_end(&mut self, tok: TokenType<'input>) -> ScanResult {
1487        // A closing bracket without a corresponding opening is invalid YAML.
1488        if self.flow_level == 0 {
1489            return Err(ScanError::new_str(self.mark, "misplaced bracket"));
1490        }
1491
1492        self.remove_simple_key()?;
1493        self.decrease_flow_level();
1494
1495        self.disallow_simple_key();
1496
1497        if matches!(tok, TokenType::FlowSequenceEnd) {
1498            self.end_implicit_mapping(self.mark);
1499            // We are out exiting the flow sequence, nesting goes down 1 level.
1500            self.implicit_flow_mapping_states.pop();
1501        }
1502
1503        let start_mark = self.mark;
1504        self.skip_non_blank();
1505        self.skip_ws_to_eol(SkipTabs::Yes)?;
1506
1507        // A flow collection within a flow mapping can be a key. In that case, the value may be
1508        // adjacent to the `:`.
1509        // ```yaml
1510        // - [ {a: b}:value ]
1511        // ```
1512        if self.flow_level > 0 {
1513            self.adjacent_value_allowed_at = self.mark.index;
1514        }
1515
1516        self.tokens
1517            .push_back(Token(Span::new(start_mark, self.mark), tok));
1518        Ok(())
1519    }
1520
1521    /// Push the `FlowEntry` token and skip over the `,`.
1522    fn fetch_flow_entry(&mut self) -> ScanResult {
1523        self.remove_simple_key()?;
1524        self.allow_simple_key();
1525
1526        self.end_implicit_mapping(self.mark);
1527
1528        let start_mark = self.mark;
1529        self.skip_non_blank();
1530        self.skip_ws_to_eol(SkipTabs::Yes)?;
1531
1532        self.tokens.push_back(Token(
1533            Span::new(start_mark, self.mark),
1534            TokenType::FlowEntry,
1535        ));
1536        Ok(())
1537    }
1538
1539    fn increase_flow_level(&mut self) -> ScanResult {
1540        self.simple_keys.push(SimpleKey::new(Marker::new(0, 0, 0)));
1541        self.flow_level = self
1542            .flow_level
1543            .checked_add(1)
1544            .ok_or_else(|| ScanError::new_str(self.mark, "recursion limit exceeded"))?;
1545        Ok(())
1546    }
1547
1548    fn decrease_flow_level(&mut self) {
1549        if self.flow_level > 0 {
1550            self.flow_level -= 1;
1551            self.simple_keys.pop().unwrap();
1552        }
1553    }
1554
1555    /// Push the `Block*` token(s) and skip over the `-`.
1556    ///
1557    /// Add an indentation level and push a `BlockSequenceStart` token if needed, then push a
1558    /// `BlockEntry` token.
1559    /// This function only skips over the `-` and does not fetch the entry value.
1560    fn fetch_block_entry(&mut self) -> ScanResult {
1561        if self.flow_level > 0 {
1562            // - * only allowed in block
1563            return Err(ScanError::new_str(
1564                self.mark,
1565                r#""-" is only valid inside a block"#,
1566            ));
1567        }
1568        // Check if we are allowed to start a new entry.
1569        if !self.simple_key_allowed {
1570            return Err(ScanError::new_str(
1571                self.mark,
1572                "block sequence entries are not allowed in this context",
1573            ));
1574        }
1575
1576        // ???, fixes test G9HC.
1577        if let Some(Token(span, TokenType::Anchor(..) | TokenType::Tag(..))) = self.tokens.back() {
1578            if self.mark.col == 0 && span.start.col == 0 && self.indent > -1 {
1579                return Err(ScanError::new_str(
1580                    span.start,
1581                    "invalid indentation for anchor",
1582                ));
1583            }
1584        }
1585
1586        // Skip over the `-`.
1587        let mark = self.mark;
1588        self.skip_non_blank();
1589
1590        // generate BLOCK-SEQUENCE-START if indented
1591        self.roll_indent(mark.col, None, TokenType::BlockSequenceStart, mark);
1592        let found_tabs = self.skip_ws_to_eol(SkipTabs::Yes)?.found_tabs();
1593        self.input.lookahead(2);
1594        if found_tabs && self.input.next_char_is('-') && is_blank_or_breakz(self.input.peek_nth(1))
1595        {
1596            return Err(ScanError::new_str(
1597                self.mark,
1598                "'-' must be followed by a valid YAML whitespace",
1599            ));
1600        }
1601
1602        self.skip_ws_to_eol(SkipTabs::No)?;
1603        self.input.lookahead(1);
1604        if self.input.next_is_break() || self.input.next_is_flow() {
1605            self.roll_one_col_indent();
1606        }
1607
1608        self.remove_simple_key()?;
1609        self.allow_simple_key();
1610
1611        self.tokens
1612            .push_back(Token(Span::empty(self.mark), TokenType::BlockEntry));
1613
1614        Ok(())
1615    }
1616
1617    fn fetch_document_indicator(&mut self, t: TokenType<'input>) -> ScanResult {
1618        self.unroll_indent(-1);
1619        self.remove_simple_key()?;
1620        self.disallow_simple_key();
1621
1622        let mark = self.mark;
1623
1624        self.skip_n_non_blank(3);
1625
1626        self.tokens.push_back(Token(Span::new(mark, self.mark), t));
1627        Ok(())
1628    }
1629
1630    fn fetch_block_scalar(&mut self, literal: bool) -> ScanResult {
1631        self.save_simple_key();
1632        self.allow_simple_key();
1633        let tok = self.scan_block_scalar(literal)?;
1634
1635        self.tokens.push_back(tok);
1636        Ok(())
1637    }
1638
1639    #[allow(clippy::too_many_lines)]
1640    fn scan_block_scalar(&mut self, literal: bool) -> Result<Token<'input>, ScanError> {
1641        let start_mark = self.mark;
1642        let mut chomping = Chomping::Clip;
1643        let mut increment: usize = 0;
1644        let mut indent: usize = 0;
1645        let mut trailing_blank: bool;
1646        let mut leading_blank: bool = false;
1647        let style = if literal {
1648            ScalarStyle::Literal
1649        } else {
1650            ScalarStyle::Folded
1651        };
1652
1653        let mut string = String::new();
1654        let mut leading_break = String::new();
1655        let mut trailing_breaks = String::new();
1656        let mut chomping_break = String::new();
1657
1658        // skip '|' or '>'
1659        self.skip_non_blank();
1660        self.unroll_non_block_indents();
1661
1662        if self.input.look_ch() == '+' || self.input.peek() == '-' {
1663            if self.input.peek() == '+' {
1664                chomping = Chomping::Keep;
1665            } else {
1666                chomping = Chomping::Strip;
1667            }
1668            self.skip_non_blank();
1669            self.input.lookahead(1);
1670            if self.input.next_is_digit() {
1671                if self.input.peek() == '0' {
1672                    return Err(ScanError::new_str(
1673                        start_mark,
1674                        "while scanning a block scalar, found an indentation indicator equal to 0",
1675                    ));
1676                }
1677                increment = (self.input.peek() as usize) - ('0' as usize);
1678                self.skip_non_blank();
1679            }
1680        } else if self.input.next_is_digit() {
1681            if self.input.peek() == '0' {
1682                return Err(ScanError::new_str(
1683                    start_mark,
1684                    "while scanning a block scalar, found an indentation indicator equal to 0",
1685                ));
1686            }
1687
1688            increment = (self.input.peek() as usize) - ('0' as usize);
1689            self.skip_non_blank();
1690            self.input.lookahead(1);
1691            if self.input.peek() == '+' || self.input.peek() == '-' {
1692                if self.input.peek() == '+' {
1693                    chomping = Chomping::Keep;
1694                } else {
1695                    chomping = Chomping::Strip;
1696                }
1697                self.skip_non_blank();
1698            }
1699        }
1700
1701        self.skip_ws_to_eol(SkipTabs::Yes)?;
1702
1703        // Check if we are at the end of the line.
1704        self.input.lookahead(1);
1705        if !self.input.next_is_breakz() {
1706            return Err(ScanError::new_str(
1707                start_mark,
1708                "while scanning a block scalar, did not find expected comment or line break",
1709            ));
1710        }
1711
1712        if self.input.next_is_break() {
1713            self.input.lookahead(2);
1714            self.read_break(&mut chomping_break);
1715        }
1716
1717        if self.input.look_ch() == '\t' {
1718            return Err(ScanError::new_str(
1719                start_mark,
1720                "a block scalar content cannot start with a tab",
1721            ));
1722        }
1723
1724        if increment > 0 {
1725            indent = if self.indent >= 0 {
1726                (self.indent + increment as isize) as usize
1727            } else {
1728                increment
1729            }
1730        }
1731
1732        // Scan the leading line breaks and determine the indentation level if needed.
1733        if indent == 0 {
1734            self.skip_block_scalar_first_line_indent(&mut indent, &mut trailing_breaks);
1735        } else {
1736            self.skip_block_scalar_indent(indent, &mut trailing_breaks);
1737        }
1738
1739        // We have an end-of-stream with no content, e.g.:
1740        // ```yaml
1741        // - |+
1742        // ```
1743        if self.input.next_is_z() {
1744            let contents = match chomping {
1745                // We strip trailing linebreaks. Nothing remain.
1746                Chomping::Strip => String::new(),
1747                // There was no newline after the chomping indicator.
1748                _ if self.mark.line == start_mark.line() => String::new(),
1749                // We clip lines, and there was a newline after the chomping indicator.
1750                // All other breaks are ignored.
1751                Chomping::Clip => chomping_break,
1752                // We keep lines. There was a newline after the chomping indicator but nothing
1753                // else.
1754                Chomping::Keep if trailing_breaks.is_empty() => chomping_break,
1755                // Otherwise, the newline after chomping is ignored.
1756                Chomping::Keep => trailing_breaks,
1757            };
1758            return Ok(Token(
1759                Span::new(start_mark, self.mark),
1760                TokenType::Scalar(style, contents.into()),
1761            ));
1762        }
1763
1764        if self.mark.col < indent && (self.mark.col as isize) > self.indent {
1765            return Err(ScanError::new_str(
1766                self.mark,
1767                "wrongly indented line in block scalar",
1768            ));
1769        }
1770
1771        let mut line_buffer = String::with_capacity(100);
1772        let start_mark = self.mark;
1773        while self.mark.col == indent && !self.input.next_is_z() {
1774            if indent == 0 {
1775                self.input.lookahead(4);
1776                if self.input.next_is_document_end() {
1777                    break;
1778                }
1779            }
1780
1781            // We are at the first content character of a content line.
1782            trailing_blank = self.input.next_is_blank();
1783            if !literal && !leading_break.is_empty() && !leading_blank && !trailing_blank {
1784                string.push_str(&trailing_breaks);
1785                if trailing_breaks.is_empty() {
1786                    string.push(' ');
1787                }
1788            } else {
1789                string.push_str(&leading_break);
1790                string.push_str(&trailing_breaks);
1791            }
1792
1793            leading_break.clear();
1794            trailing_breaks.clear();
1795
1796            leading_blank = self.input.next_is_blank();
1797
1798            self.scan_block_scalar_content_line(&mut string, &mut line_buffer);
1799
1800            // break on EOF
1801            self.input.lookahead(2);
1802            if self.input.next_is_z() {
1803                break;
1804            }
1805
1806            self.read_break(&mut leading_break);
1807
1808            // Eat the following indentation spaces and line breaks.
1809            self.skip_block_scalar_indent(indent, &mut trailing_breaks);
1810        }
1811
1812        // Chomp the tail.
1813        if chomping != Chomping::Strip {
1814            string.push_str(&leading_break);
1815            // If we had reached an eof but the last character wasn't an end-of-line, check if the
1816            // last line was indented at least as the rest of the scalar, then we need to consider
1817            // there is a newline.
1818            if self.input.next_is_z() && self.mark.col >= indent.max(1) {
1819                string.push('\n');
1820            }
1821        }
1822
1823        if chomping == Chomping::Keep {
1824            string.push_str(&trailing_breaks);
1825        }
1826
1827        Ok(Token(
1828            Span::new(start_mark, self.mark),
1829            TokenType::Scalar(style, string.into()),
1830        ))
1831    }
1832
1833    /// Retrieve the contents of the line, parsing it as a block scalar.
1834    ///
1835    /// The contents will be appended to `string`. `line_buffer` is used as a temporary buffer to
1836    /// store bytes before pushing them to `string` and thus avoiding reallocating more than
1837    /// necessary. `line_buffer` is assumed to be empty upon calling this function. It will be
1838    /// `clear`ed before the end of the function.
1839    ///
1840    /// This function assumed the first character to read is the first content character in the
1841    /// line. This function does not consume the line break character(s) after the line.
1842    fn scan_block_scalar_content_line(&mut self, string: &mut String, line_buffer: &mut String) {
1843        // Start by evaluating characters in the buffer.
1844        while !self.input.buf_is_empty() && !self.input.next_is_breakz() {
1845            string.push(self.input.peek());
1846            // We may technically skip non-blank characters. However, the only distinction is
1847            // to determine what is leading whitespace and what is not. Here, we read the
1848            // contents of the line until either eof or a linebreak. We know we will not read
1849            // `self.leading_whitespace` until the end of the line, where it will be reset.
1850            // This allows us to call a slightly less expensive function.
1851            self.skip_blank();
1852        }
1853
1854        // All characters that were in the buffer were consumed. We need to check if more
1855        // follow.
1856        if self.input.buf_is_empty() {
1857            // We will read all consecutive non-breakz characters. We push them into a
1858            // temporary buffer. The main difference with going through `self.buffer` is that
1859            // characters are appended here as their real size (1B for ascii, or up to 4 bytes for
1860            // UTF-8). We can then use the internal `line_buffer` `Vec` to push data into `string`
1861            // (using `String::push_str`).
1862            while let Some(c) = self.input.raw_read_non_breakz_ch() {
1863                line_buffer.push(c);
1864            }
1865
1866            // We need to manually update our position; we haven't called a `skip` function.
1867            let n_chars = line_buffer.chars().count();
1868            self.mark.col += n_chars;
1869            self.mark.index += n_chars;
1870
1871            // We can now append our bytes to our `string`.
1872            string.reserve(line_buffer.len());
1873            string.push_str(line_buffer);
1874            // This clears the _contents_ without touching the _capacity_.
1875            line_buffer.clear();
1876        }
1877    }
1878
1879    /// Skip the block scalar indentation and empty lines.
1880    fn skip_block_scalar_indent(&mut self, indent: usize, breaks: &mut String) {
1881        loop {
1882            // Consume all spaces. Tabs cannot be used as indentation.
1883            if indent < self.input.bufmaxlen() - 2 {
1884                self.input.lookahead(self.input.bufmaxlen());
1885                while self.mark.col < indent && self.input.peek() == ' ' {
1886                    self.skip_blank();
1887                }
1888            } else {
1889                loop {
1890                    self.input.lookahead(self.input.bufmaxlen());
1891                    while !self.input.buf_is_empty()
1892                        && self.mark.col < indent
1893                        && self.input.peek() == ' '
1894                    {
1895                        self.skip_blank();
1896                    }
1897                    // If we reached our indent, we can break. We must also break if we have
1898                    // reached content or EOF; that is, the buffer is not empty and the next
1899                    // character is not a space.
1900                    if self.mark.col == indent
1901                        || (!self.input.buf_is_empty() && self.input.peek() != ' ')
1902                    {
1903                        break;
1904                    }
1905                }
1906                self.input.lookahead(2);
1907            }
1908
1909            // If our current line is empty, skip over the break and continue looping.
1910            if self.input.next_is_break() {
1911                self.read_break(breaks);
1912            } else {
1913                // Otherwise, we have a content line. Return control.
1914                break;
1915            }
1916        }
1917    }
1918
1919    /// Determine the indentation level for a block scalar from the first line of its contents.
1920    ///
1921    /// The function skips over whitespace-only lines and sets `indent` to the the longest
1922    /// whitespace line that was encountered.
1923    fn skip_block_scalar_first_line_indent(&mut self, indent: &mut usize, breaks: &mut String) {
1924        let mut max_indent = 0;
1925        loop {
1926            // Consume all spaces. Tabs cannot be used as indentation.
1927            while self.input.look_ch() == ' ' {
1928                self.skip_blank();
1929            }
1930
1931            if self.mark.col > max_indent {
1932                max_indent = self.mark.col;
1933            }
1934
1935            if self.input.next_is_break() {
1936                // If our current line is empty, skip over the break and continue looping.
1937                self.input.lookahead(2);
1938                self.read_break(breaks);
1939            } else {
1940                // Otherwise, we have a content line. Return control.
1941                break;
1942            }
1943        }
1944
1945        // In case a yaml looks like:
1946        // ```yaml
1947        // |
1948        // foo
1949        // bar
1950        // ```
1951        // We need to set the indent to 0 and not 1. In all other cases, the indent must be at
1952        // least 1. When in the above example, `self.indent` will be set to -1.
1953        *indent = max_indent.max((self.indent + 1) as usize);
1954        if self.indent > 0 {
1955            *indent = (*indent).max(1);
1956        }
1957    }
1958
1959    fn fetch_flow_scalar(&mut self, single: bool) -> ScanResult {
1960        self.save_simple_key();
1961        self.disallow_simple_key();
1962
1963        let tok = self.scan_flow_scalar(single)?;
1964
1965        // From spec: To ensure JSON compatibility, if a key inside a flow mapping is JSON-like,
1966        // YAML allows the following value to be specified adjacent to the “:”.
1967        self.skip_to_next_token()?;
1968        self.adjacent_value_allowed_at = self.mark.index;
1969
1970        self.tokens.push_back(tok);
1971        Ok(())
1972    }
1973
1974    #[allow(clippy::too_many_lines)]
1975    fn scan_flow_scalar(&mut self, single: bool) -> Result<Token<'input>, ScanError> {
1976        let start_mark = self.mark;
1977
1978        let mut string = String::new();
1979        let mut leading_break = String::new();
1980        let mut trailing_breaks = String::new();
1981        let mut whitespaces = String::new();
1982        let mut leading_blanks;
1983
1984        /* Eat the left quote. */
1985        self.skip_non_blank();
1986
1987        loop {
1988            /* Check for a document indicator. */
1989            self.input.lookahead(4);
1990
1991            if self.mark.col == 0 && self.input.next_is_document_indicator() {
1992                return Err(ScanError::new_str(
1993                    start_mark,
1994                    "while scanning a quoted scalar, found unexpected document indicator",
1995                ));
1996            }
1997
1998            if self.input.next_is_z() {
1999                return Err(ScanError::new_str(
2000                    start_mark,
2001                    "while scanning a quoted scalar, found unexpected end of stream",
2002                ));
2003            }
2004
2005            if (self.mark.col as isize) < self.indent {
2006                return Err(ScanError::new_str(
2007                    start_mark,
2008                    "invalid indentation in quoted scalar",
2009                ));
2010            }
2011
2012            leading_blanks = false;
2013            self.consume_flow_scalar_non_whitespace_chars(
2014                single,
2015                &mut string,
2016                &mut leading_blanks,
2017                &start_mark,
2018            )?;
2019
2020            match self.input.look_ch() {
2021                '\'' if single => break,
2022                '"' if !single => break,
2023                _ => {}
2024            }
2025
2026            // Consume blank characters.
2027            while self.input.next_is_blank() || self.input.next_is_break() {
2028                if self.input.next_is_blank() {
2029                    // Consume a space or a tab character.
2030                    if leading_blanks {
2031                        if self.input.peek() == '\t' && (self.mark.col as isize) < self.indent {
2032                            return Err(ScanError::new_str(
2033                                self.mark,
2034                                "tab cannot be used as indentation",
2035                            ));
2036                        }
2037                        self.skip_blank();
2038                    } else {
2039                        whitespaces.push(self.input.peek());
2040                        self.skip_blank();
2041                    }
2042                } else {
2043                    self.input.lookahead(2);
2044                    // Check if it is a first line break.
2045                    if leading_blanks {
2046                        self.read_break(&mut trailing_breaks);
2047                    } else {
2048                        whitespaces.clear();
2049                        self.read_break(&mut leading_break);
2050                        leading_blanks = true;
2051                    }
2052                }
2053                self.input.lookahead(1);
2054            }
2055
2056            // Join the whitespaces or fold line breaks.
2057            if leading_blanks {
2058                if leading_break.is_empty() {
2059                    string.push_str(&leading_break);
2060                    string.push_str(&trailing_breaks);
2061                    trailing_breaks.clear();
2062                    leading_break.clear();
2063                } else {
2064                    if trailing_breaks.is_empty() {
2065                        string.push(' ');
2066                    } else {
2067                        string.push_str(&trailing_breaks);
2068                        trailing_breaks.clear();
2069                    }
2070                    leading_break.clear();
2071                }
2072            } else {
2073                string.push_str(&whitespaces);
2074                whitespaces.clear();
2075            }
2076        } // loop
2077
2078        // Eat the right quote.
2079        self.skip_non_blank();
2080        // Ensure there is no invalid trailing content.
2081        self.skip_ws_to_eol(SkipTabs::Yes)?;
2082        match self.input.peek() {
2083            // These can be encountered in flow sequences or mappings.
2084            ',' | '}' | ']' if self.flow_level > 0 => {}
2085            // An end-of-line / end-of-stream is fine. No trailing content.
2086            c if is_breakz(c) => {}
2087            // ':' can be encountered if our scalar is a key.
2088            // Outside of flow contexts, keys cannot span multiple lines
2089            ':' if self.flow_level == 0 && start_mark.line == self.mark.line => {}
2090            // Inside a flow context, this is allowed.
2091            ':' if self.flow_level > 0 => {}
2092            _ => {
2093                return Err(ScanError::new_str(
2094                    self.mark,
2095                    "invalid trailing content after double-quoted scalar",
2096                ));
2097            }
2098        }
2099
2100        let style = if single {
2101            ScalarStyle::SingleQuoted
2102        } else {
2103            ScalarStyle::DoubleQuoted
2104        };
2105        Ok(Token(
2106            Span::new(start_mark, self.mark),
2107            TokenType::Scalar(style, string.into()),
2108        ))
2109    }
2110
2111    /// Consume successive non-whitespace characters from a flow scalar.
2112    ///
2113    /// This function resolves escape sequences and stops upon encountering a whitespace, the end
2114    /// of the stream or the closing character for the scalar (`'` for single quoted scalars, `"`
2115    /// for double quoted scalars).
2116    ///
2117    /// # Errors
2118    /// Return an error if an invalid escape sequence is found.
2119    fn consume_flow_scalar_non_whitespace_chars(
2120        &mut self,
2121        single: bool,
2122        string: &mut String,
2123        leading_blanks: &mut bool,
2124        start_mark: &Marker,
2125    ) -> Result<(), ScanError> {
2126        self.input.lookahead(2);
2127        while !is_blank_or_breakz(self.input.peek()) {
2128            match self.input.peek() {
2129                // Check for an escaped single quote.
2130                '\'' if self.input.peek_nth(1) == '\'' && single => {
2131                    string.push('\'');
2132                    self.skip_n_non_blank(2);
2133                }
2134                // Check for the right quote.
2135                '\'' if single => break,
2136                '"' if !single => break,
2137                // Check for an escaped line break.
2138                '\\' if !single && is_break(self.input.peek_nth(1)) => {
2139                    self.input.lookahead(3);
2140                    self.skip_non_blank();
2141                    self.skip_linebreak();
2142                    *leading_blanks = true;
2143                    break;
2144                }
2145                // Check for an escape sequence.
2146                '\\' if !single => {
2147                    string.push(self.resolve_flow_scalar_escape_sequence(start_mark)?);
2148                }
2149                c => {
2150                    string.push(c);
2151                    self.skip_non_blank();
2152                }
2153            }
2154            self.input.lookahead(2);
2155        }
2156        Ok(())
2157    }
2158
2159    /// Escape the sequence we encounter in a flow scalar.
2160    ///
2161    /// `self.input.peek()` must point to the `\` starting the escape sequence.
2162    ///
2163    /// # Errors
2164    /// Return an error if an invalid escape sequence is found.
2165    fn resolve_flow_scalar_escape_sequence(
2166        &mut self,
2167        start_mark: &Marker,
2168    ) -> Result<char, ScanError> {
2169        let mut code_length = 0usize;
2170        let mut ret = '\0';
2171
2172        match self.input.peek_nth(1) {
2173            '0' => ret = '\0',
2174            'a' => ret = '\x07',
2175            'b' => ret = '\x08',
2176            't' | '\t' => ret = '\t',
2177            'n' => ret = '\n',
2178            'v' => ret = '\x0b',
2179            'f' => ret = '\x0c',
2180            'r' => ret = '\x0d',
2181            'e' => ret = '\x1b',
2182            ' ' => ret = '\x20',
2183            '"' => ret = '"',
2184            '/' => ret = '/',
2185            '\\' => ret = '\\',
2186            // Unicode next line (#x85)
2187            'N' => ret = char::from_u32(0x85).unwrap(),
2188            // Unicode non-breaking space (#xA0)
2189            '_' => ret = char::from_u32(0xA0).unwrap(),
2190            // Unicode line separator (#x2028)
2191            'L' => ret = char::from_u32(0x2028).unwrap(),
2192            // Unicode paragraph separator (#x2029)
2193            'P' => ret = char::from_u32(0x2029).unwrap(),
2194            'x' => code_length = 2,
2195            'u' => code_length = 4,
2196            'U' => code_length = 8,
2197            _ => {
2198                return Err(ScanError::new_str(
2199                    *start_mark,
2200                    "while parsing a quoted scalar, found unknown escape character",
2201                ));
2202            }
2203        }
2204        self.skip_n_non_blank(2);
2205
2206        // Consume an arbitrary escape code.
2207        if code_length > 0 {
2208            self.input.lookahead(code_length);
2209            let mut value = 0u32;
2210            for i in 0..code_length {
2211                let c = self.input.peek_nth(i);
2212                if !is_hex(c) {
2213                    return Err(ScanError::new_str(
2214                        *start_mark,
2215                        "while parsing a quoted scalar, did not find expected hexadecimal number",
2216                    ));
2217                }
2218                value = (value << 4) + as_hex(c);
2219            }
2220
2221            let Some(ch) = char::from_u32(value) else {
2222                return Err(ScanError::new_str(
2223                    *start_mark,
2224                    "while parsing a quoted scalar, found invalid Unicode character escape code",
2225                ));
2226            };
2227            ret = ch;
2228
2229            self.skip_n_non_blank(code_length);
2230        }
2231        Ok(ret)
2232    }
2233
2234    fn fetch_plain_scalar(&mut self) -> ScanResult {
2235        self.save_simple_key();
2236        self.disallow_simple_key();
2237
2238        let tok = self.scan_plain_scalar()?;
2239
2240        self.tokens.push_back(tok);
2241        Ok(())
2242    }
2243
2244    /// Scan for a plain scalar.
2245    ///
2246    /// Plain scalars are the most readable but restricted style. They may span multiple lines in
2247    /// some contexts.
2248    #[allow(clippy::too_many_lines)]
2249    fn scan_plain_scalar(&mut self) -> Result<Token<'input>, ScanError> {
2250        self.unroll_non_block_indents();
2251        let indent = self.indent + 1;
2252        let start_mark = self.mark;
2253
2254        if self.flow_level > 0 && (start_mark.col as isize) < indent {
2255            return Err(ScanError::new_str(
2256                start_mark,
2257                "invalid indentation in flow construct",
2258            ));
2259        }
2260
2261        let mut string = String::with_capacity(32);
2262        self.buf_whitespaces.clear();
2263        self.buf_leading_break.clear();
2264        self.buf_trailing_breaks.clear();
2265        let mut end_mark = self.mark;
2266
2267        loop {
2268            self.input.lookahead(4);
2269            if (self.mark.col == 0 && self.input.next_is_document_indicator())
2270                || self.input.peek() == '#'
2271            {
2272                // BS4K: If a `#` starts a comment after some separation spaces following content
2273                // of a plain scalar in block context, and there is potential continuation on the
2274                // next line, this is invalid. We cannot decide yet if there will be continuation,
2275                // so record that a comment interrupted a plain scalar.
2276                if self.input.peek() == '#'
2277                    && !string.is_empty()
2278                    && !self.buf_whitespaces.is_empty()
2279                    && self.flow_level == 0
2280                {
2281                    self.interrupted_plain_by_comment = Some(self.mark);
2282                }
2283                break;
2284            }
2285
2286            if self.flow_level > 0 && self.input.peek() == '-' && is_flow(self.input.peek_nth(1)) {
2287                return Err(ScanError::new_str(
2288                    self.mark,
2289                    "plain scalar cannot start with '-' followed by ,[]{}",
2290                ));
2291            }
2292
2293            if !self.input.next_is_blank_or_breakz()
2294                && self.input.next_can_be_plain_scalar(self.flow_level > 0)
2295            {
2296                if self.leading_whitespace {
2297                    if self.buf_leading_break.is_empty() {
2298                        string.push_str(&self.buf_leading_break);
2299                        string.push_str(&self.buf_trailing_breaks);
2300                        self.buf_trailing_breaks.clear();
2301                        self.buf_leading_break.clear();
2302                    } else {
2303                        if self.buf_trailing_breaks.is_empty() {
2304                            string.push(' ');
2305                        } else {
2306                            string.push_str(&self.buf_trailing_breaks);
2307                            self.buf_trailing_breaks.clear();
2308                        }
2309                        self.buf_leading_break.clear();
2310                    }
2311                    self.leading_whitespace = false;
2312                } else if !self.buf_whitespaces.is_empty() {
2313                    string.push_str(&self.buf_whitespaces);
2314                    self.buf_whitespaces.clear();
2315                }
2316
2317                // We can unroll the first iteration of the loop.
2318                string.push(self.input.peek());
2319                self.skip_non_blank();
2320                string.reserve(self.input.bufmaxlen());
2321
2322                // Add content non-blank characters to the scalar.
2323                let mut end = false;
2324                while !end {
2325                    // Fill the buffer once and process all characters in the buffer until the next
2326                    // fetch. Note that `next_can_be_plain_scalar` needs 2 lookahead characters,
2327                    // hence the `for` loop looping `self.input.bufmaxlen() - 1` times.
2328                    self.input.lookahead(self.input.bufmaxlen());
2329                    for _ in 0..self.input.bufmaxlen() - 1 {
2330                        if self.input.next_is_blank_or_breakz()
2331                            || !self.input.next_can_be_plain_scalar(self.flow_level > 0)
2332                        {
2333                            end = true;
2334                            break;
2335                        }
2336                        string.push(self.input.peek());
2337                        self.skip_non_blank();
2338                    }
2339                }
2340                end_mark = self.mark;
2341            }
2342
2343            // We may reach the end of a plain scalar if:
2344            //  - We reach eof
2345            //  - We reach ": "
2346            //  - We find a flow character in a flow context
2347            if !(self.input.next_is_blank() || self.input.next_is_break()) {
2348                break;
2349            }
2350
2351            // Process blank characters.
2352            self.input.lookahead(2);
2353            while self.input.next_is_blank_or_break() {
2354                if self.input.next_is_blank() {
2355                    if !self.leading_whitespace {
2356                        self.buf_whitespaces.push(self.input.peek());
2357                        self.skip_blank();
2358                    } else if (self.mark.col as isize) < indent && self.input.peek() == '\t' {
2359                        // Tabs in an indentation columns are allowed if and only if the line is
2360                        // empty. Skip to the end of the line.
2361                        self.skip_ws_to_eol(SkipTabs::Yes)?;
2362                        if !self.input.next_is_breakz() {
2363                            return Err(ScanError::new_str(
2364                                start_mark,
2365                                "while scanning a plain scalar, found a tab",
2366                            ));
2367                        }
2368                    } else {
2369                        self.skip_blank();
2370                    }
2371                } else {
2372                    // Check if it is a first line break
2373                    if self.leading_whitespace {
2374                        self.skip_break();
2375                        self.buf_trailing_breaks.push('\n');
2376                    } else {
2377                        self.buf_whitespaces.clear();
2378                        self.skip_break();
2379                        self.buf_leading_break.push('\n');
2380                        self.leading_whitespace = true;
2381                    }
2382                }
2383                self.input.lookahead(2);
2384            }
2385
2386            // check indentation level
2387            if self.flow_level == 0 && (self.mark.col as isize) < indent {
2388                break;
2389            }
2390        }
2391
2392        if self.leading_whitespace {
2393            self.allow_simple_key();
2394        }
2395
2396        if string.is_empty() {
2397            // `fetch_plain_scalar` must absolutely consume at least one byte. Otherwise,
2398            // `fetch_next_token` will never stop calling it. An empty plain scalar may happen with
2399            // erroneous inputs such as "{...".
2400            Err(ScanError::new_str(
2401                start_mark,
2402                "unexpected end of plain scalar",
2403            ))
2404        } else {
2405            Ok(Token(
2406                Span::new(start_mark, end_mark),
2407                TokenType::Scalar(ScalarStyle::Plain, string.into()),
2408            ))
2409        }
2410    }
2411
2412    fn fetch_key(&mut self) -> ScanResult {
2413        let start_mark = self.mark;
2414        if self.flow_level == 0 {
2415            // Check if we are allowed to start a new key (not necessarily simple).
2416            if !self.simple_key_allowed {
2417                return Err(ScanError::new_str(
2418                    self.mark,
2419                    "mapping keys are not allowed in this context",
2420                ));
2421            }
2422            self.roll_indent(
2423                start_mark.col,
2424                None,
2425                TokenType::BlockMappingStart,
2426                start_mark,
2427            );
2428        } else {
2429            // The scanner, upon emitting a `Key`, will prepend a `MappingStart` event.
2430            self.flow_mapping_started = true;
2431        }
2432
2433        self.remove_simple_key()?;
2434
2435        if self.flow_level == 0 {
2436            self.allow_simple_key();
2437        } else {
2438            self.disallow_simple_key();
2439        }
2440
2441        self.skip_non_blank();
2442        self.skip_yaml_whitespace()?;
2443        if self.input.peek() == '\t' {
2444            return Err(ScanError::new_str(
2445                self.mark(),
2446                "tabs disallowed in this context",
2447            ));
2448        }
2449        self.tokens
2450            .push_back(Token(Span::new(start_mark, self.mark), TokenType::Key));
2451        Ok(())
2452    }
2453
2454    /// Fetch a value in a mapping inside of a flow collection.
2455    ///
2456    /// This must not be called if [`self.flow_level`] is 0. This ensures the rules surrounding
2457    /// values in flow collections are respected prior to calling [`fetch_value`].
2458    ///
2459    /// [`self.flow_level`]: Self::flow_level
2460    /// [`fetch_value`]: Self::fetch_value
2461    fn fetch_flow_value(&mut self) -> ScanResult {
2462        let nc = self.input.peek_nth(1);
2463
2464        // If we encounter a ':' inside a flow collection and it is not immediately
2465        // followed by a blank or breakz:
2466        //   - We must check whether an adjacent value is allowed
2467        //     `["a":[]]` is valid. If the key is double-quoted, no need for a space. This
2468        //     is needed for JSON compatibility.
2469        //   - If not, we must ensure there is a space after the ':' and before its value.
2470        //     `[a: []]` is valid while `[a:[]]` isn't. `[a:b]` is treated as `["a:b"]`.
2471        //   - But if the value is empty (null), then it's okay.
2472        // The last line is for YAMLs like `[a:]`. The ':' is followed by a ']' (which is a
2473        // flow character), but the ']' is not the value. The value is an invisible empty
2474        // space which is represented as null ('~').
2475        if self.mark.index != self.adjacent_value_allowed_at && (nc == '[' || nc == '{') {
2476            return Err(ScanError::new_str(
2477                self.mark,
2478                "':' may not precede any of `[{` in flow mapping",
2479            ));
2480        }
2481
2482        self.fetch_value()
2483    }
2484
2485    /// Fetch a value from a mapping (after a `:`).
2486    fn fetch_value(&mut self) -> ScanResult {
2487        let sk = self.simple_keys.last().unwrap().clone();
2488        let start_mark = self.mark;
2489        let is_implicit_flow_mapping =
2490            !self.implicit_flow_mapping_states.is_empty() && !self.flow_mapping_started;
2491        if is_implicit_flow_mapping {
2492            *self.implicit_flow_mapping_states.last_mut().unwrap() = ImplicitMappingState::Inside;
2493        }
2494
2495        // Skip over ':'.
2496        self.skip_non_blank();
2497        if self.input.look_ch() == '\t'
2498            && !self.skip_ws_to_eol(SkipTabs::Yes)?.has_valid_yaml_ws()
2499            && (self.input.peek() == '-' || self.input.next_is_alpha())
2500        {
2501            return Err(ScanError::new_str(
2502                self.mark,
2503                "':' must be followed by a valid YAML whitespace",
2504            ));
2505        }
2506
2507        if sk.possible {
2508            // insert simple key
2509            let tok = Token(Span::empty(sk.mark), TokenType::Key);
2510            self.insert_token(sk.token_number - self.tokens_parsed, tok);
2511            if is_implicit_flow_mapping {
2512                if sk.mark.line < start_mark.line {
2513                    return Err(ScanError::new_str(
2514                        start_mark,
2515                        "illegal placement of ':' indicator",
2516                    ));
2517                }
2518                self.insert_token(
2519                    sk.token_number - self.tokens_parsed,
2520                    Token(Span::empty(sk.mark), TokenType::FlowMappingStart),
2521                );
2522            }
2523
2524            // Add the BLOCK-MAPPING-START token if needed.
2525            self.roll_indent(
2526                sk.mark.col,
2527                Some(sk.token_number),
2528                TokenType::BlockMappingStart,
2529                sk.mark,
2530            );
2531            self.roll_one_col_indent();
2532
2533            self.simple_keys.last_mut().unwrap().possible = false;
2534            self.disallow_simple_key();
2535        } else {
2536            if is_implicit_flow_mapping {
2537                self.tokens
2538                    .push_back(Token(Span::empty(start_mark), TokenType::FlowMappingStart));
2539            }
2540            // The ':' indicator follows a complex key.
2541            if self.flow_level == 0 {
2542                if !self.simple_key_allowed {
2543                    return Err(ScanError::new_str(
2544                        start_mark,
2545                        "mapping values are not allowed in this context",
2546                    ));
2547                }
2548
2549                self.roll_indent(
2550                    start_mark.col,
2551                    None,
2552                    TokenType::BlockMappingStart,
2553                    start_mark,
2554                );
2555            }
2556            self.roll_one_col_indent();
2557
2558            if self.flow_level == 0 {
2559                self.allow_simple_key();
2560            } else {
2561                self.disallow_simple_key();
2562            }
2563        }
2564        self.tokens
2565            .push_back(Token(Span::empty(start_mark), TokenType::Value));
2566
2567        Ok(())
2568    }
2569
2570    /// Add an indentation level to the stack with the given block token, if needed.
2571    ///
2572    /// An indentation level is added only if:
2573    ///   - We are not in a flow-style construct (which don't have indentation per-se).
2574    ///   - The current column is further indented than the last indent we have registered.
2575    fn roll_indent(
2576        &mut self,
2577        col: usize,
2578        number: Option<usize>,
2579        tok: TokenType<'input>,
2580        mark: Marker,
2581    ) {
2582        if self.flow_level > 0 {
2583            return;
2584        }
2585
2586        // If the last indent was a non-block indent, remove it.
2587        // This means that we prepared an indent that we thought we wouldn't use, but realized just
2588        // now that it is a block indent.
2589        if self.indent <= col as isize {
2590            if let Some(indent) = self.indents.last() {
2591                if !indent.needs_block_end {
2592                    self.indent = indent.indent;
2593                    self.indents.pop();
2594                }
2595            }
2596        }
2597
2598        if self.indent < col as isize {
2599            self.indents.push(Indent {
2600                indent: self.indent,
2601                needs_block_end: true,
2602            });
2603            self.indent = col as isize;
2604            let tokens_parsed = self.tokens_parsed;
2605            match number {
2606                Some(n) => self.insert_token(n - tokens_parsed, Token(Span::empty(mark), tok)),
2607                None => self.tokens.push_back(Token(Span::empty(mark), tok)),
2608            }
2609        }
2610    }
2611
2612    /// Pop indentation levels from the stack as much as needed.
2613    ///
2614    /// Indentation levels are popped from the stack while they are further indented than `col`.
2615    /// If we are in a flow-style construct (which don't have indentation per-se), this function
2616    /// does nothing.
2617    fn unroll_indent(&mut self, col: isize) {
2618        if self.flow_level > 0 {
2619            return;
2620        }
2621        while self.indent > col {
2622            let indent = self.indents.pop().unwrap();
2623            self.indent = indent.indent;
2624            if indent.needs_block_end {
2625                self.tokens
2626                    .push_back(Token(Span::empty(self.mark), TokenType::BlockEnd));
2627            }
2628        }
2629    }
2630
2631    /// Add an indentation level of 1 column that does not start a block.
2632    ///
2633    /// See the documentation of [`Indent::needs_block_end`] for more details.
2634    /// An indentation is not added if we are inside a flow level or if the last indent is already
2635    /// a non-block indent.
2636    fn roll_one_col_indent(&mut self) {
2637        if self.flow_level == 0 && self.indents.last().is_some_and(|x| x.needs_block_end) {
2638            self.indents.push(Indent {
2639                indent: self.indent,
2640                needs_block_end: false,
2641            });
2642            self.indent += 1;
2643        }
2644    }
2645
2646    /// Unroll all last indents created with [`Self::roll_one_col_indent`].
2647    fn unroll_non_block_indents(&mut self) {
2648        while let Some(indent) = self.indents.last() {
2649            if indent.needs_block_end {
2650                break;
2651            }
2652            self.indent = indent.indent;
2653            self.indents.pop();
2654        }
2655    }
2656
2657    /// Mark the next token to be inserted as a potential simple key.
2658    fn save_simple_key(&mut self) {
2659        if self.simple_key_allowed {
2660            let required = self.flow_level == 0
2661                && self.indent == (self.mark.col as isize)
2662                && self.indents.last().unwrap().needs_block_end;
2663            let mut sk = SimpleKey::new(self.mark);
2664            sk.possible = true;
2665            sk.required = required;
2666            sk.token_number = self.tokens_parsed + self.tokens.len();
2667
2668            self.simple_keys.pop();
2669            self.simple_keys.push(sk);
2670        }
2671    }
2672
2673    fn remove_simple_key(&mut self) -> ScanResult {
2674        let last = self.simple_keys.last_mut().unwrap();
2675        if last.possible && last.required {
2676            return Err(ScanError::new_str(self.mark, "simple key expected"));
2677        }
2678
2679        last.possible = false;
2680        Ok(())
2681    }
2682
2683    /// Return whether the scanner is inside a block but outside of a flow sequence.
2684    fn is_within_block(&self) -> bool {
2685        !self.indents.is_empty()
2686    }
2687
2688    /// If an implicit mapping had started, end it.
2689    ///
2690    /// This function does not pop the state in [`implicit_flow_mapping_states`].
2691    ///
2692    /// [`implicit_flow_mapping_states`]: Self::implicit_flow_mapping_states
2693    fn end_implicit_mapping(&mut self, mark: Marker) {
2694        if let Some(implicit_mapping) = self.implicit_flow_mapping_states.last_mut() {
2695            if *implicit_mapping == ImplicitMappingState::Inside {
2696                self.flow_mapping_started = false;
2697                *implicit_mapping = ImplicitMappingState::Possible;
2698                self.tokens
2699                    .push_back(Token(Span::empty(mark), TokenType::FlowMappingEnd));
2700            }
2701        }
2702    }
2703}
2704
2705/// Chomping, how final line breaks and trailing empty lines are interpreted.
2706///
2707/// See YAML spec 8.1.1.2.
2708#[derive(PartialEq, Eq)]
2709pub enum Chomping {
2710    /// The final line break and any trailing empty lines are excluded.
2711    Strip,
2712    /// The final line break is preserved, but trailing empty lines are excluded.
2713    Clip,
2714    /// The final line break and trailing empty lines are included.
2715    Keep,
2716}
2717
2718#[cfg(test)]
2719mod test {
2720    #[test]
2721    fn test_is_anchor_char() {
2722        use super::is_anchor_char;
2723        assert!(is_anchor_char('x'));
2724    }
2725}