Skip to main content

saphyr_parser/
scanner.rs

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