1#![allow(clippy::cast_possible_wrap)]
10#![allow(clippy::cast_sign_loss)]
11
12use alloc::{
13 borrow::{Cow, ToOwned},
14 collections::VecDeque,
15 string::String,
16 vec::Vec,
17};
18use core::char;
19
20use thiserror::Error;
21
22use crate::{
23 char_traits::{
24 as_hex, is_anchor_char, is_blank_or_breakz, is_break, is_breakz, is_flow, is_hex,
25 is_tag_char, is_uri_char, is_yaml_non_break,
26 },
27 input::{Input, SkipTabs},
28};
29
30#[derive(Clone, Copy, PartialEq, Debug, Eq)]
32pub enum TEncoding {
33 Utf8,
35}
36
37#[derive(Clone, Copy, PartialEq, Debug, Eq, Hash, PartialOrd, Ord)]
39pub enum ScalarStyle {
40 Plain,
42 SingleQuoted,
44 DoubleQuoted,
46
47 Literal,
53 Folded,
60}
61
62#[derive(Clone, Copy, PartialEq, Debug, Eq, Default)]
64pub struct Marker {
65 index: usize,
67 line: usize,
69 col: usize,
71}
72
73impl Marker {
74 #[must_use]
76 pub fn new(index: usize, line: usize, col: usize) -> Marker {
77 Marker { index, line, col }
78 }
79
80 #[must_use]
82 pub fn index(&self) -> usize {
83 self.index
84 }
85
86 #[must_use]
88 pub fn line(&self) -> usize {
89 self.line
90 }
91
92 #[must_use]
94 pub fn col(&self) -> usize {
95 self.col
96 }
97}
98
99#[derive(Clone, Copy, PartialEq, Debug, Eq, Default)]
101pub struct Span {
102 pub start: Marker,
104 pub end: Marker,
106}
107
108impl Span {
109 #[must_use]
111 pub fn new(start: Marker, end: Marker) -> Span {
112 Span { start, end }
113 }
114
115 #[must_use]
122 pub fn empty(mark: Marker) -> Span {
123 Span {
124 start: mark,
125 end: mark,
126 }
127 }
128
129 #[must_use]
131 pub fn len(&self) -> usize {
132 self.end.index - self.start.index
133 }
134
135 #[must_use]
137 pub fn is_empty(&self) -> bool {
138 self.len() == 0
139 }
140}
141
142#[derive(Clone, PartialEq, Debug, Eq, Error)]
144#[error("{} at byte {} line {} column {}", .info, .mark.index, .mark.line, .mark.col + 1,)]
145pub struct ScanError {
146 mark: Marker,
148 info: String,
150}
151
152impl ScanError {
153 #[must_use]
155 pub fn new(loc: Marker, info: String) -> ScanError {
156 ScanError { mark: loc, info }
157 }
158
159 #[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 #[must_use]
170 pub fn marker(&self) -> &Marker {
171 &self.mark
172 }
173
174 #[must_use]
176 pub fn info(&self) -> &str {
177 self.info.as_ref()
178 }
179}
180
181#[derive(Clone, PartialEq, Debug, Eq)]
183pub enum TokenType<'input> {
184 StreamStart(TEncoding),
186 StreamEnd,
188 VersionDirective(
190 u32,
192 u32,
194 ),
195 TagDirective(
197 Cow<'input, str>,
199 Cow<'input, str>,
201 ),
202 DocumentStart,
204 DocumentEnd,
206 ByteOrderMark,
208 BlockSequenceStart,
212 BlockMappingStart,
216 BlockEnd,
218 FlowSequenceStart,
220 FlowSequenceEnd,
222 FlowMappingStart,
224 FlowMappingEnd,
226 BlockEntry,
228 FlowEntry,
230 Key,
232 Value,
234 Alias(Cow<'input, str>),
236 Anchor(Cow<'input, str>),
238 Tag(
240 String,
242 String,
244 ),
245 Scalar(ScalarStyle, Cow<'input, str>),
247 ReservedDirective(
249 String,
251 Vec<String>,
253 ),
254}
255
256#[derive(Clone, PartialEq, Debug, Eq)]
258pub struct Token<'input>(pub Span, pub TokenType<'input>);
259
260#[derive(Clone, PartialEq, Debug, Eq)]
295struct SimpleKey {
296 possible: bool,
309 required: bool,
317 token_number: usize,
323 mark: Marker,
325}
326
327impl SimpleKey {
328 fn new(mark: Marker) -> SimpleKey {
330 SimpleKey {
331 possible: false,
332 required: false,
333 token_number: 0,
334 mark,
335 }
336 }
337}
338
339#[derive(Clone, Debug, Default)]
341struct Indent {
342 indent: isize,
344 needs_block_end: bool,
362}
363
364#[derive(Debug, Clone, PartialEq)]
386enum ImplicitMappingState {
387 Possible,
392 Inside,
396}
397
398#[derive(Debug)]
408#[allow(clippy::struct_excessive_bools)]
409pub struct Scanner<'input, T> {
410 input: T,
414 mark: Marker,
416 tokens: VecDeque<Token<'input>>,
423 error: Option<ScanError>,
425
426 stream_start_produced: bool,
428 stream_end_produced: bool,
430 adjacent_value_allowed_at: usize,
433 simple_key_allowed: bool,
437 simple_keys: Vec<SimpleKey>,
442 indent: isize,
444 indents: Vec<Indent>,
446 flow_level: u8,
448 tokens_parsed: usize,
452 token_available: bool,
454 leading_whitespace: bool,
456 flow_mapping_started: Vec<bool>,
463 implicit_flow_mapping_states: Vec<Option<ImplicitMappingState>>,
477 interrupted_plain_by_comment: Option<Marker>,
480 buf_leading_break: String,
481 buf_trailing_breaks: String,
482 buf_whitespaces: String,
483}
484
485impl<T: Input + Clone> Clone for Scanner<'_, T> {
486 fn clone(&self) -> Self {
487 Self {
488 input: self.input.clone(),
489 mark: self.mark,
490 tokens: self.tokens.clone(),
491 error: self.error.clone(),
492 stream_start_produced: self.stream_start_produced,
493 stream_end_produced: self.stream_end_produced,
494 adjacent_value_allowed_at: self.adjacent_value_allowed_at,
495 simple_key_allowed: self.simple_key_allowed,
496 simple_keys: self.simple_keys.clone(),
497 indent: self.indent,
498 indents: self.indents.clone(),
499 flow_level: self.flow_level,
500 tokens_parsed: self.tokens_parsed,
501 token_available: self.token_available,
502 leading_whitespace: self.leading_whitespace,
503 flow_mapping_started: self.flow_mapping_started.clone(),
504 implicit_flow_mapping_states: self.implicit_flow_mapping_states.clone(),
505 interrupted_plain_by_comment: self.interrupted_plain_by_comment,
506 buf_leading_break: self.buf_leading_break.clone(),
507 buf_trailing_breaks: self.buf_trailing_breaks.clone(),
508 buf_whitespaces: self.buf_whitespaces.clone(),
509 }
510 }
511}
512
513impl<'input, T: Input> Iterator for Scanner<'input, T> {
514 type Item = Token<'input>;
515
516 fn next(&mut self) -> Option<Self::Item> {
517 if self.error.is_some() {
518 return None;
519 }
520 match self.next_token() {
521 Ok(Some(tok)) => {
522 debug_print!(
523 " \x1B[;32m\u{21B3} {:?} \x1B[;36m{:?}\x1B[;m",
524 tok.1,
525 tok.0
526 );
527 Some(tok)
528 }
529 Ok(tok) => tok,
530 Err(e) => {
531 self.error = Some(e);
532 None
533 }
534 }
535 }
536}
537
538pub type ScanResult = Result<(), ScanError>;
540
541impl<'input, T: Input> Scanner<'input, T> {
542 pub fn new(input: T) -> Self {
544 Scanner {
545 input,
546 mark: Marker::new(0, 1, 0),
547 tokens: VecDeque::new(),
548 error: None,
549
550 stream_start_produced: false,
551 stream_end_produced: false,
552 adjacent_value_allowed_at: 0,
553 simple_key_allowed: true,
554 simple_keys: Vec::new(),
555 indent: -1,
556 indents: Vec::new(),
557 flow_level: 0,
558 tokens_parsed: 0,
559 token_available: false,
560 leading_whitespace: true,
561 flow_mapping_started: vec![],
562 implicit_flow_mapping_states: vec![],
563 interrupted_plain_by_comment: None,
564
565 buf_leading_break: String::new(),
566 buf_trailing_breaks: String::new(),
567 buf_whitespaces: String::new(),
568 }
569 }
570
571 #[inline]
576 pub fn get_error(&self) -> Option<ScanError> {
577 self.error.clone()
578 }
579
580 #[inline]
582 fn skip_blank(&mut self) {
583 self.input.skip();
584
585 self.mark.index += 1;
586 self.mark.col += 1;
587 }
588
589 #[inline]
591 fn skip_non_blank(&mut self) {
592 self.input.skip();
593
594 self.mark.index += 1;
595 self.mark.col += 1;
596 self.leading_whitespace = false;
597 }
598
599 #[inline]
601 fn skip_n_non_blank(&mut self, count: usize) {
602 self.input.skip_n(count);
603
604 self.mark.index += count;
605 self.mark.col += count;
606 self.leading_whitespace = false;
607 }
608
609 #[inline]
611 fn skip_nl(&mut self) {
612 self.input.skip();
613
614 self.mark.index += 1;
615 self.mark.col = 0;
616 self.mark.line += 1;
617 self.leading_whitespace = true;
618 }
619
620 #[inline]
622 fn skip_linebreak(&mut self) {
623 if self.input.next_2_are('\r', '\n') {
624 self.skip_blank();
627 self.skip_nl();
628 } else if self.input.next_is_break() {
629 self.skip_nl();
630 }
631 }
632
633 #[inline]
635 pub fn stream_started(&self) -> bool {
636 self.stream_start_produced
637 }
638
639 #[inline]
641 pub fn stream_ended(&self) -> bool {
642 self.stream_end_produced
643 }
644
645 #[inline]
647 pub fn mark(&self) -> Marker {
648 self.mark
649 }
650
651 #[inline]
658 fn read_break(&mut self, s: &mut String) {
659 self.skip_break();
660 s.push('\n');
661 }
662
663 #[inline]
668 fn skip_break(&mut self) {
669 let c = self.input.peek();
670 let nc = self.input.peek_nth(1);
671 debug_assert!(is_break(c));
672 if c == '\r' && nc == '\n' {
673 self.skip_blank();
674 }
675 self.skip_nl();
676 }
677
678 fn insert_token(&mut self, pos: usize, tok: Token<'input>) {
680 let old_len = self.tokens.len();
681 assert!(pos <= old_len);
682 self.tokens.insert(pos, tok);
683 }
684
685 fn allow_simple_key(&mut self) {
686 self.simple_key_allowed = true;
687 }
688
689 fn disallow_simple_key(&mut self) {
690 self.simple_key_allowed = false;
691 }
692
693 pub fn fetch_next_token(&mut self) -> ScanResult {
698 self.input.lookahead(1);
699
700 if !self.stream_start_produced {
701 self.fetch_stream_start();
702 return Ok(());
703 }
704 self.skip_to_next_token()?;
705
706 debug_print!(
707 " \x1B[38;5;244m\u{2192} fetch_next_token after whitespace {:?} {:?}\x1B[m",
708 self.mark,
709 self.input.peek()
710 );
711
712 self.stale_simple_keys()?;
713
714 let mark = self.mark;
715 self.unroll_indent(mark.col as isize);
716
717 self.input.lookahead(4);
718
719 if self.input.next_is_z() {
720 if self.input.peek_opt() == Some('\0') {
721 return Err(ScanError::new_str(self.mark, "found unprintable character"));
722 }
723 self.fetch_stream_end()?;
724 return Ok(());
725 }
726
727 if self.input.next_char_is('\u{FEFF}') {
730 if self.mark.col == 0 && self.flow_level == 0 {
731 return self.fetch_byte_order_mark();
732 }
733
734 return Err(ScanError::new_str(
735 self.mark,
736 "a byte order mark must not appear inside a document",
737 ));
738 }
739
740 if self.mark.col == 0 {
741 if self.input.next_char_is('%') {
742 return self.fetch_directive();
743 } else if self.input.next_is_document_start() {
744 return self.fetch_document_indicator(TokenType::DocumentStart);
745 } else if self.input.next_is_document_end() {
746 self.fetch_document_indicator(TokenType::DocumentEnd)?;
747 self.skip_ws_to_eol(SkipTabs::Yes)?;
748 if !self.input.next_is_breakz() {
749 return Err(ScanError::new_str(
750 self.mark,
751 "invalid content after document end marker",
752 ));
753 }
754 return Ok(());
755 }
756 }
757
758 if (self.mark.col as isize) < self.indent {
759 return Err(ScanError::new_str(self.mark, "invalid indentation"));
760 }
761
762 let c = self.input.peek();
763 let nc = self.input.peek_nth(1);
764 match c {
765 '[' => self.fetch_flow_collection_start(TokenType::FlowSequenceStart),
766 '{' => self.fetch_flow_collection_start(TokenType::FlowMappingStart),
767 ']' => self.fetch_flow_collection_end(TokenType::FlowSequenceEnd),
768 '}' => self.fetch_flow_collection_end(TokenType::FlowMappingEnd),
769 ',' => self.fetch_flow_entry(),
770 '-' if is_blank_or_breakz(nc) => self.fetch_block_entry(),
771 '?' if is_blank_or_breakz(nc) => self.fetch_key(),
772 ':' if is_blank_or_breakz(nc) => self.fetch_value(),
773 ':' if self.flow_level > 0
774 && (is_flow(nc) || self.mark.index == self.adjacent_value_allowed_at) =>
775 {
776 self.fetch_flow_value()
777 }
778 '*' => self.fetch_anchor(true),
780 '&' => self.fetch_anchor(false),
782 '!' => self.fetch_tag(),
783 '|' if self.flow_level == 0 => self.fetch_block_scalar(true),
785 '>' if self.flow_level == 0 => self.fetch_block_scalar(false),
787 '\'' => self.fetch_flow_scalar(true),
788 '"' => self.fetch_flow_scalar(false),
789 '-' if !is_blank_or_breakz(nc) => self.fetch_plain_scalar(),
791 ':' | '?' if !is_blank_or_breakz(nc) && self.flow_level == 0 => {
792 self.fetch_plain_scalar()
793 }
794 '%' | '@' | '`' => Err(ScanError::new(
795 self.mark,
796 format!("unexpected character: `{c}'"),
797 )),
798 _ => self.fetch_plain_scalar(),
799 }
800 }
801
802 pub fn next_token(&mut self) -> Result<Option<Token<'input>>, ScanError> {
806 if self.stream_end_produced {
807 return Ok(None);
808 }
809
810 if !self.token_available {
811 self.fetch_more_tokens()?;
812 }
813 let Some(t) = self.tokens.pop_front() else {
814 return Err(ScanError::new_str(
815 self.mark,
816 "did not find expected next token",
817 ));
818 };
819 self.token_available = false;
820 self.tokens_parsed += 1;
821
822 if let TokenType::StreamEnd = t.1 {
823 self.stream_end_produced = true;
824 }
825 Ok(Some(t))
826 }
827
828 pub fn fetch_more_tokens(&mut self) -> ScanResult {
832 let mut need_more;
833 loop {
834 if self.tokens.is_empty() {
835 need_more = true;
836 } else {
837 need_more = false;
838 self.stale_simple_keys()?;
840 for sk in &self.simple_keys {
842 if sk.possible && sk.token_number == self.tokens_parsed {
843 need_more = true;
844 break;
845 }
846 }
847 }
848
849 if !need_more {
850 break;
851 }
852 self.fetch_next_token()?;
853 }
854 self.token_available = true;
855
856 Ok(())
857 }
858
859 fn stale_simple_keys(&mut self) -> ScanResult {
867 for sk in &mut self.simple_keys {
868 if sk.possible
869 && self.flow_level == 0
871 && (sk.mark.line < self.mark.line || sk.mark.index + 1024 < self.mark.index)
872 {
873 if sk.required {
874 return Err(ScanError::new_str(self.mark, "simple key expect ':'"));
875 }
876 sk.possible = false;
877 }
878 }
879 Ok(())
880 }
881
882 fn skip_to_next_token(&mut self) -> ScanResult {
888 loop {
889 match self.input.look_ch() {
890 '\t' if self.is_within_block()
897 && self.leading_whitespace
898 && (self.mark.col as isize) < self.indent =>
899 {
900 self.skip_ws_to_eol(SkipTabs::Yes)?;
901 if !self.input.next_is_breakz() {
903 return Err(ScanError::new_str(
904 self.mark,
905 "tabs disallowed within this context (block indentation)",
906 ));
907 }
908 }
909 '\t' | ' ' => self.skip_blank(),
910 '\n' | '\r' => {
911 self.input.lookahead(2);
912 self.skip_linebreak();
913 if self.flow_level == 0 {
914 self.allow_simple_key();
915 }
916 }
917 '#' => {
918 let comment_length = self.input.skip_while_non_breakz();
919 self.mark.index += comment_length;
920 self.mark.col += comment_length;
921 }
922 _ => break,
923 }
924 }
925 if let Some(err_mark) = self.interrupted_plain_by_comment.take() {
928 self.input.lookahead(4);
931 let is_immediate_next_line = self.mark.line == err_mark.line + 1;
935 if self.flow_level == 0
936 && is_immediate_next_line
937 && self.mark.col as isize > self.indent
938 && !self.input.next_is_z()
939 && !self.input.next_is_document_indicator()
940 && self.input.next_can_be_plain_scalar(false)
941 {
942 return Err(ScanError::new_str(
943 err_mark,
944 "comment intercepting the multiline text",
945 ));
946 }
947 }
948 Ok(())
949 }
950
951 fn skip_yaml_whitespace(&mut self) -> ScanResult {
956 let mut need_whitespace = true;
957 loop {
958 match self.input.look_ch() {
959 ' ' => {
960 self.skip_blank();
961
962 need_whitespace = false;
963 }
964 '\n' | '\r' => {
965 self.input.lookahead(2);
966 self.skip_linebreak();
967 if self.flow_level == 0 {
968 self.allow_simple_key();
969 }
970 need_whitespace = false;
971 }
972 '#' => {
973 let comment_length = self.input.skip_while_non_breakz();
974 self.mark.index += comment_length;
975 self.mark.col += comment_length;
976 }
977 _ => break,
978 }
979 }
980
981 if need_whitespace {
982 Err(ScanError::new_str(self.mark(), "expected whitespace"))
983 } else {
984 Ok(())
985 }
986 }
987
988 fn skip_ws_to_eol(&mut self, skip_tabs: SkipTabs) -> Result<SkipTabs, ScanError> {
989 let (n_bytes, result) = self.input.skip_ws_to_eol(skip_tabs);
990 self.mark.col += n_bytes;
991 self.mark.index += n_bytes;
992 if self.mark.col > 0 && self.input.look_ch() == '\u{FEFF}' {
994 return Err(ScanError::new_str(
995 self.mark,
996 "a byte order mark must not appear inside a document",
997 ));
998 }
999
1000 result.map_err(|msg| ScanError::new_str(self.mark, msg))
1001 }
1002
1003 fn fetch_stream_start(&mut self) {
1004 let mark = self.mark;
1005 self.indent = -1;
1006 self.stream_start_produced = true;
1007 self.allow_simple_key();
1008 self.tokens.push_back(Token(
1009 Span::empty(mark),
1010 TokenType::StreamStart(TEncoding::Utf8),
1011 ));
1012 self.simple_keys.push(SimpleKey::new(Marker::new(0, 0, 0)));
1013 }
1014
1015 fn fetch_stream_end(&mut self) -> ScanResult {
1016 if self.mark.col != 0 {
1018 self.mark.col = 0;
1019 self.mark.line += 1;
1020 }
1021
1022 for sk in &mut self.simple_keys {
1025 if sk.required && sk.possible {
1026 return Err(ScanError::new_str(self.mark, "simple key expected"));
1027 }
1028 sk.possible = false;
1029 }
1030
1031 self.unroll_indent(-1);
1032 self.remove_simple_key()?;
1033 self.disallow_simple_key();
1034
1035 self.tokens
1036 .push_back(Token(Span::empty(self.mark), TokenType::StreamEnd));
1037 Ok(())
1038 }
1039
1040 fn fetch_directive(&mut self) -> ScanResult {
1041 self.unroll_indent(-1);
1042 self.remove_simple_key()?;
1043
1044 self.disallow_simple_key();
1045
1046 let tok = self.scan_directive()?;
1047 self.tokens.push_back(tok);
1048
1049 Ok(())
1050 }
1051
1052 fn scan_directive(&mut self) -> Result<Token<'input>, ScanError> {
1053 let start_mark = self.mark;
1054 self.skip_non_blank();
1055
1056 let name = self.scan_directive_name()?;
1057 let tok = match name.as_ref() {
1058 "YAML" => self.scan_version_directive_value(&start_mark)?,
1059 "TAG" => self.scan_tag_directive_value(&start_mark)?,
1060 _ => {
1061 let mut params = Vec::new();
1062 while self.input.next_is_blank() {
1063 let n_blanks = self.input.skip_while_blank();
1064 self.mark.index += n_blanks;
1065 self.mark.col += n_blanks;
1066
1067 if !is_blank_or_breakz(self.input.peek()) {
1068 let mut param = String::new();
1069 let n_chars = self.input.fetch_while_is_yaml_non_space(&mut param);
1070 self.mark.index += n_chars;
1071 self.mark.col += n_chars;
1072 params.push(param);
1073 }
1074 }
1075
1076 Token(
1077 Span::new(start_mark, self.mark),
1078 TokenType::ReservedDirective(name, params),
1079 )
1080 }
1081 };
1082
1083 self.skip_ws_to_eol(SkipTabs::Yes)?;
1084
1085 if self.input.next_is_breakz() {
1086 self.input.lookahead(2);
1087 self.skip_linebreak();
1088 Ok(tok)
1089 } else {
1090 Err(ScanError::new_str(
1091 start_mark,
1092 "while scanning a directive, did not find expected comment or line break",
1093 ))
1094 }
1095 }
1096
1097 fn scan_version_directive_value(&mut self, mark: &Marker) -> Result<Token<'input>, ScanError> {
1098 let n_blanks = self.input.skip_while_blank();
1099 self.mark.index += n_blanks;
1100 self.mark.col += n_blanks;
1101
1102 let major = self.scan_version_directive_number(mark)?;
1103
1104 if self.input.peek() != '.' {
1105 return Err(ScanError::new_str(
1106 *mark,
1107 "while scanning a YAML directive, did not find expected digit or '.' character",
1108 ));
1109 }
1110 self.skip_non_blank();
1111
1112 let minor = self.scan_version_directive_number(mark)?;
1113
1114 Ok(Token(
1115 Span::new(*mark, self.mark),
1116 TokenType::VersionDirective(major, minor),
1117 ))
1118 }
1119
1120 fn scan_directive_name(&mut self) -> Result<String, ScanError> {
1121 let start_mark = self.mark;
1122 let mut string = String::new();
1123
1124 let n_chars = self.input.fetch_while_is_yaml_non_space(&mut string);
1125 self.mark.index += n_chars;
1126 self.mark.col += n_chars;
1127
1128 if string.is_empty() {
1129 return Err(ScanError::new_str(
1130 start_mark,
1131 "while scanning a directive, could not find expected directive name",
1132 ));
1133 }
1134
1135 if !is_blank_or_breakz(self.input.peek()) {
1136 return Err(ScanError::new_str(
1137 start_mark,
1138 "while scanning a directive, found unexpected non-alphabetical character",
1139 ));
1140 }
1141
1142 Ok(string)
1143 }
1144
1145 fn scan_version_directive_number(&mut self, mark: &Marker) -> Result<u32, ScanError> {
1146 let mut val = 0u32;
1147 let mut length = 0usize;
1148 while let Some(digit) = self.input.look_ch().to_digit(10) {
1149 if length + 1 > 9 {
1150 return Err(ScanError::new_str(
1151 *mark,
1152 "while scanning a YAML directive, found extremely long version number",
1153 ));
1154 }
1155 length += 1;
1156 val = val * 10 + digit;
1157 self.skip_non_blank();
1158 }
1159
1160 if length == 0 {
1161 return Err(ScanError::new_str(
1162 *mark,
1163 "while scanning a YAML directive, did not find expected version number",
1164 ));
1165 }
1166
1167 Ok(val)
1168 }
1169
1170 fn scan_tag_directive_value(&mut self, mark: &Marker) -> Result<Token<'input>, ScanError> {
1171 let n_blanks = self.input.skip_while_blank();
1172 self.mark.index += n_blanks;
1173 self.mark.col += n_blanks;
1174
1175 let handle = self.scan_tag_handle(true, mark)?;
1176
1177 let n_blanks = self.input.skip_while_blank();
1178 self.mark.index += n_blanks;
1179 self.mark.col += n_blanks;
1180
1181 let prefix = self.scan_tag_prefix(mark)?;
1182
1183 self.input.lookahead(1);
1184
1185 if self.input.next_is_blank_or_breakz() {
1186 Ok(Token(
1187 Span::new(*mark, self.mark),
1188 TokenType::TagDirective(handle.into(), prefix.into()),
1189 ))
1190 } else {
1191 Err(ScanError::new_str(
1192 *mark,
1193 "while scanning TAG, did not find expected whitespace or line break",
1194 ))
1195 }
1196 }
1197
1198 fn fetch_tag(&mut self) -> ScanResult {
1199 self.save_simple_key();
1200 self.disallow_simple_key();
1201
1202 let tok = self.scan_tag()?;
1203 self.tokens.push_back(tok);
1204 Ok(())
1205 }
1206
1207 fn scan_tag(&mut self) -> Result<Token<'input>, ScanError> {
1208 let start_mark = self.mark;
1209 let mut handle = String::new();
1210 let mut suffix;
1211
1212 self.input.lookahead(2);
1214
1215 if self.input.nth_char_is(1, '<') {
1216 suffix = self.scan_verbatim_tag(&start_mark)?;
1217 } else {
1218 handle = self.scan_tag_handle(false, &start_mark)?;
1220 if handle.len() >= 2 && handle.starts_with('!') && handle.ends_with('!') {
1222 let is_secondary_handle = handle == "!!";
1224 suffix =
1225 self.scan_tag_shorthand_suffix(false, is_secondary_handle, "", &start_mark)?;
1226 } else {
1227 suffix = self.scan_tag_shorthand_suffix(false, false, &handle, &start_mark)?;
1228 "!".clone_into(&mut handle);
1229 if suffix.is_empty() {
1232 handle.clear();
1233 "!".clone_into(&mut suffix);
1234 }
1235 }
1236 }
1237
1238 if is_blank_or_breakz(self.input.look_ch())
1239 || (self.flow_level > 0 && self.input.next_is_flow())
1240 {
1241 Ok(Token(
1243 Span::new(start_mark, self.mark),
1244 TokenType::Tag(handle, suffix),
1245 ))
1246 } else {
1247 Err(ScanError::new_str(
1248 start_mark,
1249 "while scanning a tag, did not find expected whitespace or line break",
1250 ))
1251 }
1252 }
1253
1254 fn scan_tag_handle(&mut self, directive: bool, mark: &Marker) -> Result<String, ScanError> {
1255 let mut string = String::new();
1256 if self.input.look_ch() != '!' {
1257 return Err(ScanError::new_str(
1258 *mark,
1259 "while scanning a tag, did not find expected '!'",
1260 ));
1261 }
1262
1263 string.push(self.input.peek());
1264 self.skip_non_blank();
1265
1266 let n_chars = self.input.fetch_while_is_alpha(&mut string);
1267 self.mark.index += n_chars;
1268 self.mark.col += n_chars;
1269
1270 if self.input.peek() == '!' {
1272 string.push(self.input.peek());
1273 self.skip_non_blank();
1274 } else if directive && string != "!" {
1275 return Err(ScanError::new_str(
1279 *mark,
1280 "while parsing a tag directive, did not find expected '!'",
1281 ));
1282 }
1283 Ok(string)
1284 }
1285
1286 fn scan_tag_prefix(&mut self, start_mark: &Marker) -> Result<String, ScanError> {
1292 let mut string = String::new();
1293
1294 if self.input.look_ch() == '!' {
1295 string.push(self.input.peek());
1297 self.skip_non_blank();
1298 } else if !is_tag_char(self.input.peek()) {
1299 return Err(ScanError::new_str(
1301 *start_mark,
1302 "invalid global tag character",
1303 ));
1304 } else if self.input.peek() == '%' {
1305 string.push(self.scan_uri_escapes(start_mark)?);
1307 } else {
1308 string.push(self.input.peek());
1310 self.skip_non_blank();
1311 }
1312
1313 while is_uri_char(self.input.look_ch()) {
1314 if self.input.peek() == '%' {
1315 string.push(self.scan_uri_escapes(start_mark)?);
1316 } else {
1317 string.push(self.input.peek());
1318 self.skip_non_blank();
1319 }
1320 }
1321
1322 Ok(string)
1323 }
1324
1325 fn scan_verbatim_tag(&mut self, start_mark: &Marker) -> Result<String, ScanError> {
1329 self.skip_non_blank();
1331 self.skip_non_blank();
1332
1333 let mut string = String::new();
1334 while is_uri_char(self.input.look_ch()) {
1335 if self.input.peek() == '%' {
1336 string.push(self.scan_uri_escapes(start_mark)?);
1337 } else {
1338 string.push(self.input.peek());
1339 self.skip_non_blank();
1340 }
1341 }
1342
1343 if self.input.peek() != '>' {
1344 return Err(ScanError::new_str(
1345 *start_mark,
1346 "while scanning a verbatim tag, did not find the expected '>'",
1347 ));
1348 }
1349 self.skip_non_blank();
1350
1351 Ok(string)
1352 }
1353
1354 fn scan_tag_shorthand_suffix(
1355 &mut self,
1356 _directive: bool,
1357 _is_secondary: bool,
1358 head: &str,
1359 mark: &Marker,
1360 ) -> Result<String, ScanError> {
1361 let mut length = head.len();
1362 let mut string = String::new();
1363
1364 if length > 1 {
1367 string.extend(head.chars().skip(1));
1368 }
1369
1370 while is_tag_char(self.input.look_ch()) {
1371 if self.input.peek() == '%' {
1373 string.push(self.scan_uri_escapes(mark)?);
1374 } else {
1375 string.push(self.input.peek());
1376 self.skip_non_blank();
1377 }
1378
1379 length += 1;
1380 }
1381
1382 if length == 0 {
1383 return Err(ScanError::new_str(
1384 *mark,
1385 "while parsing a tag, did not find expected tag URI",
1386 ));
1387 }
1388
1389 Ok(string)
1390 }
1391
1392 fn scan_uri_escapes(&mut self, mark: &Marker) -> Result<char, ScanError> {
1393 let mut width = 0usize;
1394 let mut code = 0u32;
1395 loop {
1396 self.input.lookahead(3);
1397
1398 let c = self.input.peek_nth(1);
1399 let nc = self.input.peek_nth(2);
1400
1401 if !(self.input.peek() == '%' && is_hex(c) && is_hex(nc)) {
1402 return Err(ScanError::new_str(
1403 *mark,
1404 "while parsing a tag, found an invalid escape sequence",
1405 ));
1406 }
1407
1408 let byte = (as_hex(c) << 4) + as_hex(nc);
1409 if width == 0 {
1410 width = match byte {
1411 _ if byte & 0x80 == 0x00 => 1,
1412 _ if byte & 0xE0 == 0xC0 => 2,
1413 _ if byte & 0xF0 == 0xE0 => 3,
1414 _ if byte & 0xF8 == 0xF0 => 4,
1415 _ => {
1416 return Err(ScanError::new_str(
1417 *mark,
1418 "while parsing a tag, found an incorrect leading UTF-8 byte",
1419 ));
1420 }
1421 };
1422 code = byte;
1423 } else {
1424 if byte & 0xc0 != 0x80 {
1425 return Err(ScanError::new_str(
1426 *mark,
1427 "while parsing a tag, found an incorrect trailing UTF-8 byte",
1428 ));
1429 }
1430 code = (code << 8) + byte;
1431 }
1432
1433 self.skip_n_non_blank(3);
1434
1435 width -= 1;
1436 if width == 0 {
1437 break;
1438 }
1439 }
1440
1441 match char::from_u32(code) {
1442 Some(ch) => Ok(ch),
1443 None => Err(ScanError::new_str(
1444 *mark,
1445 "while parsing a tag, found an invalid UTF-8 codepoint",
1446 )),
1447 }
1448 }
1449
1450 fn fetch_anchor(&mut self, alias: bool) -> ScanResult {
1451 self.save_simple_key();
1452 self.disallow_simple_key();
1453
1454 let tok = self.scan_anchor(alias)?;
1455
1456 self.tokens.push_back(tok);
1457
1458 Ok(())
1459 }
1460
1461 fn scan_anchor(&mut self, alias: bool) -> Result<Token<'input>, ScanError> {
1462 let mut string = String::new();
1463 let start_mark = self.mark;
1464
1465 self.skip_non_blank();
1466 while is_anchor_char(self.input.look_ch()) {
1467 string.push(self.input.peek());
1468 self.skip_non_blank();
1469 }
1470
1471 if string.is_empty() {
1472 return Err(ScanError::new_str(
1473 start_mark,
1474 "while scanning an anchor or alias, did not find expected alphabetic or numeric character",
1475 ));
1476 }
1477
1478 let tok = if alias {
1479 TokenType::Alias(string.into())
1480 } else {
1481 TokenType::Anchor(string.into())
1482 };
1483 Ok(Token(Span::new(start_mark, self.mark), tok))
1484 }
1485
1486 fn fetch_flow_collection_start(&mut self, tok: TokenType<'input>) -> ScanResult {
1487 self.save_simple_key();
1489
1490 self.roll_one_col_indent();
1491 self.increase_flow_level()?;
1492
1493 self.allow_simple_key();
1494
1495 let start_mark = self.mark;
1496 self.skip_non_blank();
1497
1498 let mapping = tok == TokenType::FlowMappingStart;
1499 self.flow_mapping_started.push(mapping);
1500 self.implicit_flow_mapping_states.push(if mapping {
1501 None
1502 } else {
1503 Some(ImplicitMappingState::Possible)
1504 });
1505
1506 self.skip_ws_to_eol(SkipTabs::Yes)?;
1507
1508 self.tokens
1509 .push_back(Token(Span::new(start_mark, self.mark), tok));
1510 Ok(())
1511 }
1512
1513 fn fetch_flow_collection_end(&mut self, tok: TokenType<'input>) -> ScanResult {
1514 if self.flow_level == 0 {
1516 return Err(ScanError::new_str(self.mark, "misplaced bracket"));
1517 }
1518
1519 self.remove_simple_key()?;
1520 self.decrease_flow_level();
1521
1522 self.disallow_simple_key();
1523
1524 if matches!(tok, TokenType::FlowSequenceEnd) {
1525 self.end_implicit_mapping(self.mark);
1526 }
1527 self.implicit_flow_mapping_states.pop();
1530 self.flow_mapping_started.pop();
1531
1532 let start_mark = self.mark;
1533 self.skip_non_blank();
1534 self.skip_ws_to_eol(SkipTabs::Yes)?;
1535
1536 if self.flow_level > 0 {
1542 self.adjacent_value_allowed_at = self.mark.index;
1543 }
1544
1545 self.tokens
1546 .push_back(Token(Span::new(start_mark, self.mark), tok));
1547 Ok(())
1548 }
1549
1550 fn fetch_flow_entry(&mut self) -> ScanResult {
1552 self.remove_simple_key()?;
1553 self.allow_simple_key();
1554
1555 self.end_implicit_mapping(self.mark);
1556
1557 let start_mark = self.mark;
1558 self.skip_non_blank();
1559 self.skip_ws_to_eol(SkipTabs::Yes)?;
1560
1561 self.tokens.push_back(Token(
1562 Span::new(start_mark, self.mark),
1563 TokenType::FlowEntry,
1564 ));
1565 Ok(())
1566 }
1567
1568 fn increase_flow_level(&mut self) -> ScanResult {
1569 self.simple_keys.push(SimpleKey::new(Marker::new(0, 0, 0)));
1570 self.flow_level = self
1571 .flow_level
1572 .checked_add(1)
1573 .ok_or_else(|| ScanError::new_str(self.mark, "recursion limit exceeded"))?;
1574 Ok(())
1575 }
1576
1577 fn decrease_flow_level(&mut self) {
1578 if self.flow_level > 0 {
1579 self.flow_level -= 1;
1580 self.simple_keys.pop();
1581 }
1582 }
1583
1584 fn fetch_block_entry(&mut self) -> ScanResult {
1590 if self.flow_level > 0 {
1591 return Err(ScanError::new_str(
1593 self.mark,
1594 r#""-" is only valid inside a block"#,
1595 ));
1596 }
1597 if !self.simple_key_allowed {
1599 return Err(ScanError::new_str(
1600 self.mark,
1601 "block sequence entries are not allowed in this context",
1602 ));
1603 }
1604
1605 if let Some(Token(span, TokenType::Anchor(..) | TokenType::Tag(..))) = self.tokens.back() {
1607 if self.mark.col == 0 && span.start.col == 0 && self.indent > -1 {
1608 return Err(ScanError::new_str(
1609 span.start,
1610 "invalid indentation for anchor",
1611 ));
1612 }
1613 }
1614
1615 let mark = self.mark;
1617 self.skip_non_blank();
1618
1619 self.roll_indent(mark.col, None, TokenType::BlockSequenceStart, mark);
1621 let found_tabs = self.skip_ws_to_eol(SkipTabs::Yes)?.found_tabs();
1622 self.input.lookahead(2);
1623 if found_tabs && self.input.next_char_is('-') && is_blank_or_breakz(self.input.peek_nth(1))
1624 {
1625 return Err(ScanError::new_str(
1626 self.mark,
1627 "'-' must be followed by a valid YAML whitespace",
1628 ));
1629 }
1630
1631 self.skip_ws_to_eol(SkipTabs::No)?;
1632 self.input.lookahead(1);
1633 if self.input.next_is_break() || self.input.next_is_flow() {
1634 self.roll_one_col_indent();
1635 }
1636
1637 self.remove_simple_key()?;
1638 self.allow_simple_key();
1639
1640 self.tokens
1641 .push_back(Token(Span::empty(self.mark), TokenType::BlockEntry));
1642
1643 Ok(())
1644 }
1645
1646 fn fetch_byte_order_mark(&mut self) -> ScanResult {
1647 self.unroll_indent(-1);
1648 self.remove_simple_key()?;
1649
1650 let mark = self.mark;
1652 self.input.skip();
1653 self.mark.index += 1;
1654 self.allow_simple_key();
1655
1656 self.tokens
1657 .push_back(Token(Span::new(mark, self.mark), TokenType::ByteOrderMark));
1658 Ok(())
1659 }
1660
1661 fn fetch_document_indicator(&mut self, t: TokenType<'input>) -> ScanResult {
1662 self.unroll_indent(-1);
1663 self.remove_simple_key()?;
1664 self.disallow_simple_key();
1665
1666 let mark = self.mark;
1667
1668 self.skip_n_non_blank(3);
1669
1670 self.tokens.push_back(Token(Span::new(mark, self.mark), t));
1671 Ok(())
1672 }
1673
1674 fn fetch_block_scalar(&mut self, literal: bool) -> ScanResult {
1675 self.save_simple_key();
1676 self.allow_simple_key();
1677 let tok = self.scan_block_scalar(literal)?;
1678
1679 self.tokens.push_back(tok);
1680 Ok(())
1681 }
1682
1683 #[allow(clippy::too_many_lines)]
1684 fn scan_block_scalar(&mut self, literal: bool) -> Result<Token<'input>, ScanError> {
1685 let start_mark = self.mark;
1686 let mut chomping = Chomping::Clip;
1687 let mut increment: usize = 0;
1688 let mut indent: usize = 0;
1689 let mut trailing_blank: bool;
1690 let mut leading_blank: bool = false;
1691 let style = if literal {
1692 ScalarStyle::Literal
1693 } else {
1694 ScalarStyle::Folded
1695 };
1696
1697 let mut string = String::new();
1698 let mut leading_break = String::new();
1699 let mut trailing_breaks = String::new();
1700
1701 self.skip_non_blank();
1703 self.unroll_non_block_indents();
1704
1705 if self.input.look_ch() == '+' || self.input.peek() == '-' {
1706 if self.input.peek() == '+' {
1707 chomping = Chomping::Keep;
1708 } else {
1709 chomping = Chomping::Strip;
1710 }
1711 self.skip_non_blank();
1712 self.input.lookahead(1);
1713 if self.input.next_is_digit() {
1714 if self.input.peek() == '0' {
1715 return Err(ScanError::new_str(
1716 start_mark,
1717 "while scanning a block scalar, found an indentation indicator equal to 0",
1718 ));
1719 }
1720 increment = (self.input.peek() as usize) - ('0' as usize);
1721 self.skip_non_blank();
1722 }
1723 } else if self.input.next_is_digit() {
1724 if self.input.peek() == '0' {
1725 return Err(ScanError::new_str(
1726 start_mark,
1727 "while scanning a block scalar, found an indentation indicator equal to 0",
1728 ));
1729 }
1730
1731 increment = (self.input.peek() as usize) - ('0' as usize);
1732 self.skip_non_blank();
1733 self.input.lookahead(1);
1734 if self.input.peek() == '+' || self.input.peek() == '-' {
1735 if self.input.peek() == '+' {
1736 chomping = Chomping::Keep;
1737 } else {
1738 chomping = Chomping::Strip;
1739 }
1740 self.skip_non_blank();
1741 }
1742 }
1743
1744 self.skip_ws_to_eol(SkipTabs::Yes)?;
1745
1746 self.input.lookahead(1);
1748 if !self.input.next_is_breakz() {
1749 return Err(ScanError::new_str(
1750 start_mark,
1751 "while scanning a block scalar, did not find expected comment or line break",
1752 ));
1753 }
1754
1755 if self.input.next_is_break() {
1756 self.input.lookahead(2);
1757 self.skip_break();
1758 }
1759
1760 if self.input.look_ch() == '\t' {
1761 return Err(ScanError::new_str(
1762 start_mark,
1763 "a block scalar content cannot start with a tab",
1764 ));
1765 }
1766
1767 if increment > 0 {
1768 indent = if self.indent >= 0 {
1769 (self.indent + increment as isize) as usize
1770 } else {
1771 increment
1772 }
1773 }
1774
1775 if indent == 0 {
1777 self.skip_block_scalar_first_line_indent(&mut indent, &mut trailing_breaks);
1778 } else {
1779 self.skip_block_scalar_indent(indent, &mut trailing_breaks);
1780 }
1781
1782 if self.input.next_is_z() {
1787 let contents = match chomping {
1788 Chomping::Strip | Chomping::Clip => String::new(),
1791 Chomping::Keep
1794 if trailing_breaks.is_empty()
1795 && self.mark.line > start_mark.line()
1796 && self.mark.col > 0 =>
1797 {
1798 "\n".into()
1799 }
1800 Chomping::Keep => trailing_breaks,
1801 };
1802 return Ok(Token(
1803 Span::new(start_mark, self.mark),
1804 TokenType::Scalar(style, contents.into()),
1805 ));
1806 }
1807
1808 if self.mark.col < indent && (self.mark.col as isize) > self.indent {
1809 return Err(ScanError::new_str(
1810 self.mark,
1811 "wrongly indented line in block scalar",
1812 ));
1813 }
1814
1815 let mut line_buffer = String::with_capacity(100);
1816 let start_mark = self.mark;
1817 while self.mark.col == indent && is_yaml_non_break(self.input.peek()) {
1818 if indent == 0 {
1819 self.input.lookahead(4);
1820 if self.input.next_is_document_end() {
1821 break;
1822 }
1823 }
1824
1825 trailing_blank = self.input.next_is_blank();
1827 if !literal && !leading_break.is_empty() && !leading_blank && !trailing_blank {
1828 string.push_str(&trailing_breaks);
1829 if trailing_breaks.is_empty() {
1830 string.push(' ');
1831 }
1832 } else {
1833 string.push_str(&leading_break);
1834 string.push_str(&trailing_breaks);
1835 }
1836
1837 leading_break.clear();
1838 trailing_breaks.clear();
1839
1840 leading_blank = self.input.next_is_blank();
1841
1842 self.scan_block_scalar_content_line(&mut string, &mut line_buffer);
1843
1844 self.input.lookahead(2);
1846 if !self.input.next_is_break() {
1847 break;
1848 }
1849
1850 self.read_break(&mut leading_break);
1851
1852 self.skip_block_scalar_indent(indent, &mut trailing_breaks);
1854 }
1855
1856 if chomping != Chomping::Strip {
1858 string.push_str(&leading_break);
1859 if self.input.next_is_z() && self.mark.col >= indent.max(1) {
1863 string.push('\n');
1864 }
1865 }
1866
1867 if chomping == Chomping::Keep {
1868 string.push_str(&trailing_breaks);
1869 }
1870
1871 Ok(Token(
1872 Span::new(start_mark, self.mark),
1873 TokenType::Scalar(style, string.into()),
1874 ))
1875 }
1876
1877 fn scan_block_scalar_content_line(&mut self, string: &mut String, line_buffer: &mut String) {
1887 while !self.input.buf_is_empty() && is_yaml_non_break(self.input.peek()) {
1889 string.push(self.input.peek());
1890 self.skip_blank();
1896 }
1897
1898 if self.input.buf_is_empty() {
1901 while let Some(c) = self.input.raw_read_non_breakz_ch() {
1907 line_buffer.push(c);
1908 }
1909
1910 let n_chars = line_buffer.chars().count();
1912 self.mark.col += n_chars;
1913 self.mark.index += n_chars;
1914
1915 string.reserve(line_buffer.len());
1917 string.push_str(line_buffer);
1918 line_buffer.clear();
1920 }
1921 }
1922
1923 fn skip_block_scalar_indent(&mut self, indent: usize, breaks: &mut String) {
1925 loop {
1926 if indent < self.input.bufmaxlen() - 2 {
1928 self.input.lookahead(self.input.bufmaxlen());
1929 while self.mark.col < indent && self.input.peek() == ' ' {
1930 self.skip_blank();
1931 }
1932 } else {
1933 loop {
1934 self.input.lookahead(self.input.bufmaxlen());
1935 while !self.input.buf_is_empty()
1936 && self.mark.col < indent
1937 && self.input.peek() == ' '
1938 {
1939 self.skip_blank();
1940 }
1941 if self.mark.col == indent
1945 || (!self.input.buf_is_empty() && self.input.peek() != ' ')
1946 {
1947 break;
1948 }
1949 }
1950 self.input.lookahead(2);
1951 }
1952
1953 if self.input.next_is_break() {
1955 self.read_break(breaks);
1956 } else {
1957 break;
1959 }
1960 }
1961 }
1962
1963 fn skip_block_scalar_first_line_indent(&mut self, indent: &mut usize, breaks: &mut String) {
1968 let mut max_indent = 0;
1969 loop {
1970 while self.input.look_ch() == ' ' {
1972 self.skip_blank();
1973 }
1974
1975 if self.mark.col > max_indent {
1976 max_indent = self.mark.col;
1977 }
1978
1979 if self.input.next_is_break() {
1980 self.input.lookahead(2);
1982 self.read_break(breaks);
1983 } else {
1984 break;
1986 }
1987 }
1988
1989 *indent = max_indent.max((self.indent + 1) as usize);
1998 if self.indent > 0 {
1999 *indent = (*indent).max(1);
2000 }
2001 }
2002
2003 fn fetch_flow_scalar(&mut self, single: bool) -> ScanResult {
2004 self.save_simple_key();
2005 self.disallow_simple_key();
2006
2007 let tok = self.scan_flow_scalar(single)?;
2008
2009 self.skip_to_next_token()?;
2012 self.adjacent_value_allowed_at = self.mark.index;
2013
2014 self.tokens.push_back(tok);
2015 Ok(())
2016 }
2017
2018 #[allow(clippy::too_many_lines)]
2019 fn scan_flow_scalar(&mut self, single: bool) -> Result<Token<'input>, ScanError> {
2020 let start_mark = self.mark;
2021
2022 let mut string = String::new();
2023 let mut leading_break = String::new();
2024 let mut trailing_breaks = String::new();
2025 let mut whitespaces = String::new();
2026 let mut leading_blanks;
2027
2028 self.skip_non_blank();
2030
2031 loop {
2032 self.input.lookahead(4);
2034
2035 if self.mark.col == 0 && self.input.next_is_document_indicator() {
2036 return Err(ScanError::new_str(
2037 start_mark,
2038 "while scanning a quoted scalar, found unexpected document indicator",
2039 ));
2040 }
2041
2042 if self.input.next_is_z() {
2043 return Err(ScanError::new_str(
2044 start_mark,
2045 "while scanning a quoted scalar, found unexpected end of stream",
2046 ));
2047 }
2048
2049 if (self.mark.col as isize) < self.indent {
2050 return Err(ScanError::new_str(
2051 start_mark,
2052 "invalid indentation in quoted scalar",
2053 ));
2054 }
2055
2056 leading_blanks = false;
2057 self.consume_flow_scalar_non_whitespace_chars(
2058 single,
2059 &mut string,
2060 &mut leading_blanks,
2061 &start_mark,
2062 )?;
2063
2064 match self.input.look_ch() {
2065 '\'' if single => break,
2066 '"' if !single => break,
2067 _ => {}
2068 }
2069
2070 while self.input.next_is_blank() || self.input.next_is_break() {
2072 if self.input.next_is_blank() {
2073 if leading_blanks {
2075 if self.input.peek() == '\t' && (self.mark.col as isize) < self.indent {
2076 return Err(ScanError::new_str(
2077 self.mark,
2078 "tab cannot be used as indentation",
2079 ));
2080 }
2081 self.skip_blank();
2082 } else {
2083 whitespaces.push(self.input.peek());
2084 self.skip_blank();
2085 }
2086 } else {
2087 self.input.lookahead(2);
2088 if leading_blanks {
2090 self.read_break(&mut trailing_breaks);
2091 } else {
2092 whitespaces.clear();
2093 self.read_break(&mut leading_break);
2094 leading_blanks = true;
2095 }
2096 }
2097 self.input.lookahead(1);
2098 }
2099
2100 if leading_blanks {
2102 if leading_break.is_empty() {
2103 string.push_str(&leading_break);
2104 string.push_str(&trailing_breaks);
2105 trailing_breaks.clear();
2106 leading_break.clear();
2107 } else {
2108 if trailing_breaks.is_empty() {
2109 string.push(' ');
2110 } else {
2111 string.push_str(&trailing_breaks);
2112 trailing_breaks.clear();
2113 }
2114 leading_break.clear();
2115 }
2116 } else {
2117 string.push_str(&whitespaces);
2118 whitespaces.clear();
2119 }
2120 } self.skip_non_blank();
2124 self.skip_ws_to_eol(SkipTabs::Yes)?;
2126 match self.input.peek() {
2127 ',' | '}' | ']' if self.flow_level > 0 => {}
2129 c if is_breakz(c) => {}
2131 ':' if self.flow_level == 0 && start_mark.line == self.mark.line => {}
2134 ':' if self.flow_level > 0 => {}
2136 _ => {
2137 return Err(ScanError::new_str(
2138 self.mark,
2139 "invalid trailing content after double-quoted scalar",
2140 ));
2141 }
2142 }
2143
2144 let style = if single {
2145 ScalarStyle::SingleQuoted
2146 } else {
2147 ScalarStyle::DoubleQuoted
2148 };
2149 Ok(Token(
2150 Span::new(start_mark, self.mark),
2151 TokenType::Scalar(style, string.into()),
2152 ))
2153 }
2154
2155 fn consume_flow_scalar_non_whitespace_chars(
2164 &mut self,
2165 single: bool,
2166 string: &mut String,
2167 leading_blanks: &mut bool,
2168 start_mark: &Marker,
2169 ) -> Result<(), ScanError> {
2170 self.input.lookahead(2);
2171 while !is_blank_or_breakz(self.input.peek()) {
2172 match self.input.peek() {
2173 '\'' if self.input.peek_nth(1) == '\'' && single => {
2175 string.push('\'');
2176 self.skip_n_non_blank(2);
2177 }
2178 '\'' if single => break,
2180 '"' if !single => break,
2181 '\\' if !single && is_break(self.input.peek_nth(1)) => {
2183 self.input.lookahead(3);
2184 self.skip_non_blank();
2185 self.skip_linebreak();
2186 *leading_blanks = true;
2187 break;
2188 }
2189 '\\' if !single => {
2191 string.push(self.resolve_flow_scalar_escape_sequence(start_mark)?);
2192 }
2193 c => {
2194 string.push(c);
2195 self.skip_non_blank();
2196 }
2197 }
2198 self.input.lookahead(2);
2199 }
2200 Ok(())
2201 }
2202
2203 fn resolve_flow_scalar_escape_sequence(
2210 &mut self,
2211 start_mark: &Marker,
2212 ) -> Result<char, ScanError> {
2213 let mut code_length = 0usize;
2214 let mut ret = '\0';
2215
2216 match self.input.peek_nth(1) {
2217 '0' => ret = '\0',
2218 'a' => ret = '\x07',
2219 'b' => ret = '\x08',
2220 't' | '\t' => ret = '\t',
2221 'n' => ret = '\n',
2222 'v' => ret = '\x0b',
2223 'f' => ret = '\x0c',
2224 'r' => ret = '\x0d',
2225 'e' => ret = '\x1b',
2226 ' ' => ret = '\x20',
2227 '"' => ret = '"',
2228 '/' => ret = '/',
2229 '\\' => ret = '\\',
2230 'N' => ret = char::from_u32(0x85).unwrap(),
2232 '_' => ret = char::from_u32(0xA0).unwrap(),
2234 'L' => ret = char::from_u32(0x2028).unwrap(),
2236 'P' => ret = char::from_u32(0x2029).unwrap(),
2238 'x' => code_length = 2,
2239 'u' => code_length = 4,
2240 'U' => code_length = 8,
2241 _ => {
2242 return Err(ScanError::new_str(
2243 *start_mark,
2244 "while parsing a quoted scalar, found unknown escape character",
2245 ));
2246 }
2247 }
2248 self.skip_n_non_blank(2);
2249
2250 if code_length > 0 {
2252 self.input.lookahead(code_length);
2253 let mut value = 0u32;
2254 for i in 0..code_length {
2255 let c = self.input.peek_nth(i);
2256 if !is_hex(c) {
2257 return Err(ScanError::new_str(
2258 *start_mark,
2259 "while parsing a quoted scalar, did not find expected hexadecimal number",
2260 ));
2261 }
2262 value = (value << 4) + as_hex(c);
2263 }
2264
2265 let Some(ch) = char::from_u32(value) else {
2266 return Err(ScanError::new_str(
2267 *start_mark,
2268 "while parsing a quoted scalar, found invalid Unicode character escape code",
2269 ));
2270 };
2271 ret = ch;
2272
2273 self.skip_n_non_blank(code_length);
2274 }
2275 Ok(ret)
2276 }
2277
2278 fn fetch_plain_scalar(&mut self) -> ScanResult {
2279 self.save_simple_key();
2280 self.disallow_simple_key();
2281
2282 let tok = self.scan_plain_scalar()?;
2283
2284 self.tokens.push_back(tok);
2285 Ok(())
2286 }
2287
2288 #[allow(clippy::too_many_lines)]
2293 fn scan_plain_scalar(&mut self) -> Result<Token<'input>, ScanError> {
2294 self.unroll_non_block_indents();
2295 let indent = self.indent + 1;
2296 let start_mark = self.mark;
2297
2298 if self.flow_level > 0 && (start_mark.col as isize) < indent {
2299 return Err(ScanError::new_str(
2300 start_mark,
2301 "invalid indentation in flow construct",
2302 ));
2303 }
2304
2305 let mut string = String::with_capacity(32);
2306 self.buf_whitespaces.clear();
2307 self.buf_leading_break.clear();
2308 self.buf_trailing_breaks.clear();
2309 let mut end_mark = self.mark;
2310
2311 loop {
2312 self.input.lookahead(4);
2313 if (self.mark.col == 0 && self.input.next_is_document_indicator())
2314 || self.input.peek() == '#'
2315 {
2316 if self.input.peek() == '#'
2321 && !string.is_empty()
2322 && !self.buf_whitespaces.is_empty()
2323 && self.flow_level == 0
2324 {
2325 self.interrupted_plain_by_comment = Some(self.mark);
2326 }
2327 break;
2328 }
2329
2330 if self.flow_level > 0 && self.input.peek() == '-' && is_flow(self.input.peek_nth(1)) {
2331 return Err(ScanError::new_str(
2332 self.mark,
2333 "plain scalar cannot start with '-' followed by ,[]{}",
2334 ));
2335 }
2336
2337 if !self.input.next_is_blank_or_breakz()
2338 && self.input.next_can_be_plain_scalar(self.flow_level > 0)
2339 {
2340 if self.leading_whitespace {
2341 if self.buf_leading_break.is_empty() {
2342 string.push_str(&self.buf_leading_break);
2343 string.push_str(&self.buf_trailing_breaks);
2344 self.buf_trailing_breaks.clear();
2345 self.buf_leading_break.clear();
2346 } else {
2347 if self.buf_trailing_breaks.is_empty() {
2348 string.push(' ');
2349 } else {
2350 string.push_str(&self.buf_trailing_breaks);
2351 self.buf_trailing_breaks.clear();
2352 }
2353 self.buf_leading_break.clear();
2354 }
2355 self.leading_whitespace = false;
2356 } else if !self.buf_whitespaces.is_empty() {
2357 string.push_str(&self.buf_whitespaces);
2358 self.buf_whitespaces.clear();
2359 }
2360
2361 string.push(self.input.peek());
2363 self.skip_non_blank();
2364 string.reserve(self.input.bufmaxlen());
2365
2366 let mut end = false;
2368 while !end {
2369 self.input.lookahead(self.input.bufmaxlen());
2373 for _ in 0..self.input.bufmaxlen() - 1 {
2374 if self.input.next_is_blank_or_breakz()
2375 || !self.input.next_can_be_plain_scalar(self.flow_level > 0)
2376 {
2377 end = true;
2378 break;
2379 }
2380 string.push(self.input.peek());
2381 self.skip_non_blank();
2382 }
2383 }
2384 end_mark = self.mark;
2385 }
2386
2387 if !(self.input.next_is_blank() || self.input.next_is_break()) {
2392 break;
2393 }
2394
2395 self.input.lookahead(2);
2397 while self.input.next_is_blank_or_break() {
2398 if self.input.next_is_blank() {
2399 if !self.leading_whitespace {
2400 self.buf_whitespaces.push(self.input.peek());
2401 self.skip_blank();
2402 } else if (self.mark.col as isize) < indent && self.input.peek() == '\t' {
2403 self.skip_ws_to_eol(SkipTabs::Yes)?;
2406 if !self.input.next_is_breakz() {
2407 return Err(ScanError::new_str(
2408 start_mark,
2409 "while scanning a plain scalar, found a tab",
2410 ));
2411 }
2412 } else {
2413 self.skip_blank();
2414 }
2415 } else {
2416 if self.leading_whitespace {
2418 self.skip_break();
2419 self.buf_trailing_breaks.push('\n');
2420 } else {
2421 self.buf_whitespaces.clear();
2422 self.skip_break();
2423 self.buf_leading_break.push('\n');
2424 self.leading_whitespace = true;
2425 }
2426 }
2427 self.input.lookahead(2);
2428 }
2429
2430 if self.flow_level == 0 && (self.mark.col as isize) < indent {
2432 break;
2433 }
2434 }
2435
2436 if self.leading_whitespace {
2437 self.allow_simple_key();
2438 }
2439
2440 if string.is_empty() {
2441 Err(ScanError::new_str(
2445 start_mark,
2446 "unexpected end of plain scalar",
2447 ))
2448 } else {
2449 Ok(Token(
2450 Span::new(start_mark, end_mark),
2451 TokenType::Scalar(ScalarStyle::Plain, string.into()),
2452 ))
2453 }
2454 }
2455
2456 fn fetch_key(&mut self) -> ScanResult {
2457 let start_mark = self.mark;
2458 if self.flow_level == 0 {
2459 if !self.simple_key_allowed {
2461 return Err(ScanError::new_str(
2462 self.mark,
2463 "mapping keys are not allowed in this context",
2464 ));
2465 }
2466 self.roll_indent(
2467 start_mark.col,
2468 None,
2469 TokenType::BlockMappingStart,
2470 start_mark,
2471 );
2472 } else if let Some(mapping_started) = self.flow_mapping_started.last_mut() {
2473 *mapping_started = true;
2475 }
2476
2477 self.remove_simple_key()?;
2478
2479 if self.flow_level == 0 {
2480 self.allow_simple_key();
2481 } else {
2482 self.disallow_simple_key();
2483 }
2484
2485 self.skip_non_blank();
2486 self.skip_yaml_whitespace()?;
2487 if self.input.peek() == '\t' {
2488 return Err(ScanError::new_str(
2489 self.mark(),
2490 "tabs disallowed in this context",
2491 ));
2492 }
2493 self.tokens
2494 .push_back(Token(Span::new(start_mark, self.mark), TokenType::Key));
2495 Ok(())
2496 }
2497
2498 fn fetch_flow_value(&mut self) -> ScanResult {
2506 let nc = self.input.peek_nth(1);
2507
2508 if self.mark.index != self.adjacent_value_allowed_at && (nc == '[' || nc == '{') {
2520 return Err(ScanError::new_str(
2521 self.mark,
2522 "':' may not precede any of `[{` in flow mapping",
2523 ));
2524 }
2525
2526 self.fetch_value()
2527 }
2528
2529 fn fetch_value(&mut self) -> ScanResult {
2531 let sk = self
2532 .simple_keys
2533 .last()
2534 .cloned()
2535 .ok_or_else(|| ScanError::new_str(self.mark, "simple key expected"))?;
2536 let start_mark = self.mark;
2537 let is_implicit_flow_mapping = if let (Some(Some(implicit_mapping)), Some(false)) = (
2538 self.implicit_flow_mapping_states.last_mut(),
2539 self.flow_mapping_started.last(),
2540 ) {
2541 *implicit_mapping = ImplicitMappingState::Inside;
2542 true
2543 } else {
2544 false
2545 };
2546
2547 self.skip_non_blank();
2549 if self.input.look_ch() == '\t'
2550 && !self.skip_ws_to_eol(SkipTabs::Yes)?.has_valid_yaml_ws()
2551 && (self.input.peek() == '-' || self.input.next_is_alpha())
2552 {
2553 return Err(ScanError::new_str(
2554 self.mark,
2555 "':' must be followed by a valid YAML whitespace",
2556 ));
2557 }
2558
2559 if sk.possible {
2560 let tok = Token(Span::empty(sk.mark), TokenType::Key);
2562 self.insert_token(sk.token_number - self.tokens_parsed, tok);
2563 if is_implicit_flow_mapping {
2564 if sk.mark.line < start_mark.line {
2565 return Err(ScanError::new_str(
2566 start_mark,
2567 "illegal placement of ':' indicator",
2568 ));
2569 }
2570 self.insert_token(
2571 sk.token_number - self.tokens_parsed,
2572 Token(Span::empty(sk.mark), TokenType::FlowMappingStart),
2573 );
2574 }
2575
2576 self.roll_indent(
2578 sk.mark.col,
2579 Some(sk.token_number),
2580 TokenType::BlockMappingStart,
2581 sk.mark,
2582 );
2583 self.roll_one_col_indent();
2584
2585 self.simple_keys
2586 .last_mut()
2587 .ok_or_else(|| ScanError::new_str(self.mark, "simple key expected"))?
2588 .possible = false;
2589 self.disallow_simple_key();
2590 } else {
2591 if is_implicit_flow_mapping {
2592 self.tokens
2593 .push_back(Token(Span::empty(start_mark), TokenType::FlowMappingStart));
2594 }
2595 if self.flow_level == 0 {
2597 if !self.simple_key_allowed {
2598 return Err(ScanError::new_str(
2599 start_mark,
2600 "mapping values are not allowed in this context",
2601 ));
2602 }
2603
2604 self.roll_indent(
2605 start_mark.col,
2606 None,
2607 TokenType::BlockMappingStart,
2608 start_mark,
2609 );
2610 }
2611 self.roll_one_col_indent();
2612
2613 if self.flow_level == 0 {
2614 self.allow_simple_key();
2615 } else {
2616 self.disallow_simple_key();
2617 }
2618 }
2619 self.tokens
2620 .push_back(Token(Span::empty(start_mark), TokenType::Value));
2621
2622 Ok(())
2623 }
2624
2625 fn roll_indent(
2631 &mut self,
2632 col: usize,
2633 number: Option<usize>,
2634 tok: TokenType<'input>,
2635 mark: Marker,
2636 ) {
2637 if self.flow_level > 0 {
2638 return;
2639 }
2640
2641 if self.indent <= col as isize {
2645 if let Some(indent) = self.indents.last() {
2646 if !indent.needs_block_end {
2647 self.indent = indent.indent;
2648 self.indents.pop();
2649 }
2650 }
2651 }
2652
2653 if self.indent < col as isize {
2654 self.indents.push(Indent {
2655 indent: self.indent,
2656 needs_block_end: true,
2657 });
2658 self.indent = col as isize;
2659 let tokens_parsed = self.tokens_parsed;
2660 match number {
2661 Some(n) => self.insert_token(n - tokens_parsed, Token(Span::empty(mark), tok)),
2662 None => self.tokens.push_back(Token(Span::empty(mark), tok)),
2663 }
2664 }
2665 }
2666
2667 fn unroll_indent(&mut self, col: isize) {
2673 if self.flow_level > 0 {
2674 return;
2675 }
2676 while self.indent > col {
2677 let indent = self.indents.pop().unwrap();
2678 self.indent = indent.indent;
2679 if indent.needs_block_end {
2680 self.tokens
2681 .push_back(Token(Span::empty(self.mark), TokenType::BlockEnd));
2682 }
2683 }
2684 }
2685
2686 fn roll_one_col_indent(&mut self) {
2692 if self.flow_level == 0 && self.indents.last().is_some_and(|x| x.needs_block_end) {
2693 self.indents.push(Indent {
2694 indent: self.indent,
2695 needs_block_end: false,
2696 });
2697 self.indent += 1;
2698 }
2699 }
2700
2701 fn unroll_non_block_indents(&mut self) {
2703 while let Some(indent) = self.indents.last() {
2704 if indent.needs_block_end {
2705 break;
2706 }
2707 self.indent = indent.indent;
2708 self.indents.pop();
2709 }
2710 }
2711
2712 fn save_simple_key(&mut self) {
2714 if self.simple_key_allowed {
2715 let required = self.flow_level == 0
2716 && self.indent == (self.mark.col as isize)
2717 && self.indents.last().unwrap().needs_block_end;
2718 let mut sk = SimpleKey::new(self.mark);
2719 sk.possible = true;
2720 sk.required = required;
2721 sk.token_number = self.tokens_parsed + self.tokens.len();
2722
2723 self.simple_keys.pop();
2724 self.simple_keys.push(sk);
2725 }
2726 }
2727
2728 fn remove_simple_key(&mut self) -> ScanResult {
2729 let last = self
2730 .simple_keys
2731 .last_mut()
2732 .ok_or_else(|| ScanError::new_str(self.mark, "simple key expected"))?;
2733 if last.possible && last.required {
2734 return Err(ScanError::new_str(self.mark, "simple key expected"));
2735 }
2736
2737 last.possible = false;
2738 Ok(())
2739 }
2740
2741 fn is_within_block(&self) -> bool {
2743 !self.indents.is_empty()
2744 }
2745
2746 fn end_implicit_mapping(&mut self, mark: Marker) {
2752 if let (Some(Some(implicit_mapping)), Some(mapping_started)) = (
2753 self.implicit_flow_mapping_states.last_mut(),
2754 self.flow_mapping_started.last_mut(),
2755 ) {
2756 if *implicit_mapping == ImplicitMappingState::Inside {
2757 *mapping_started = false;
2758 *implicit_mapping = ImplicitMappingState::Possible;
2759 self.tokens
2760 .push_back(Token(Span::empty(mark), TokenType::FlowMappingEnd));
2761 }
2762 }
2763 }
2764}
2765
2766#[derive(PartialEq, Eq)]
2770pub enum Chomping {
2771 Strip,
2773 Clip,
2775 Keep,
2777}
2778
2779#[cfg(test)]
2780mod test {
2781 #[test]
2782 fn test_is_anchor_char() {
2783 use super::is_anchor_char;
2784 assert!(is_anchor_char('x'));
2785 }
2786}