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