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