Skip to main content

saphyr_parser/
scanner.rs

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