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: bool,
463 implicit_flow_mapping_states: Vec<ImplicitMappingState>,
476 interrupted_plain_by_comment: Option<Marker>,
479 buf_leading_break: String,
480 buf_trailing_breaks: String,
481 buf_whitespaces: String,
482}
483
484impl<T: Input + Clone> Clone for Scanner<'_, T> {
485 fn clone(&self) -> Self {
486 Self {
487 input: self.input.clone(),
488 mark: self.mark,
489 tokens: self.tokens.clone(),
490 error: self.error.clone(),
491 stream_start_produced: self.stream_start_produced,
492 stream_end_produced: self.stream_end_produced,
493 adjacent_value_allowed_at: self.adjacent_value_allowed_at,
494 simple_key_allowed: self.simple_key_allowed,
495 simple_keys: self.simple_keys.clone(),
496 indent: self.indent,
497 indents: self.indents.clone(),
498 flow_level: self.flow_level,
499 tokens_parsed: self.tokens_parsed,
500 token_available: self.token_available,
501 leading_whitespace: self.leading_whitespace,
502 flow_mapping_started: self.flow_mapping_started,
503 implicit_flow_mapping_states: self.implicit_flow_mapping_states.clone(),
504 interrupted_plain_by_comment: self.interrupted_plain_by_comment,
505 buf_leading_break: self.buf_leading_break.clone(),
506 buf_trailing_breaks: self.buf_trailing_breaks.clone(),
507 buf_whitespaces: self.buf_whitespaces.clone(),
508 }
509 }
510}
511
512impl<'input, T: Input> Iterator for Scanner<'input, T> {
513 type Item = Token<'input>;
514
515 fn next(&mut self) -> Option<Self::Item> {
516 if self.error.is_some() {
517 return None;
518 }
519 match self.next_token() {
520 Ok(Some(tok)) => {
521 debug_print!(
522 " \x1B[;32m\u{21B3} {:?} \x1B[;36m{:?}\x1B[;m",
523 tok.1,
524 tok.0
525 );
526 Some(tok)
527 }
528 Ok(tok) => tok,
529 Err(e) => {
530 self.error = Some(e);
531 None
532 }
533 }
534 }
535}
536
537pub type ScanResult = Result<(), ScanError>;
539
540impl<'input, T: Input> Scanner<'input, T> {
541 pub fn new(input: T) -> Self {
543 Scanner {
544 input,
545 mark: Marker::new(0, 1, 0),
546 tokens: VecDeque::new(),
547 error: None,
548
549 stream_start_produced: false,
550 stream_end_produced: false,
551 adjacent_value_allowed_at: 0,
552 simple_key_allowed: true,
553 simple_keys: Vec::new(),
554 indent: -1,
555 indents: Vec::new(),
556 flow_level: 0,
557 tokens_parsed: 0,
558 token_available: false,
559 leading_whitespace: true,
560 flow_mapping_started: false,
561 implicit_flow_mapping_states: vec![],
562 interrupted_plain_by_comment: None,
563
564 buf_leading_break: String::new(),
565 buf_trailing_breaks: String::new(),
566 buf_whitespaces: String::new(),
567 }
568 }
569
570 #[inline]
575 pub fn get_error(&self) -> Option<ScanError> {
576 self.error.clone()
577 }
578
579 #[inline]
581 fn skip_blank(&mut self) {
582 self.input.skip();
583
584 self.mark.index += 1;
585 self.mark.col += 1;
586 }
587
588 #[inline]
590 fn skip_non_blank(&mut self) {
591 self.input.skip();
592
593 self.mark.index += 1;
594 self.mark.col += 1;
595 self.leading_whitespace = false;
596 }
597
598 #[inline]
600 fn skip_n_non_blank(&mut self, count: usize) {
601 self.input.skip_n(count);
602
603 self.mark.index += count;
604 self.mark.col += count;
605 self.leading_whitespace = false;
606 }
607
608 #[inline]
610 fn skip_nl(&mut self) {
611 self.input.skip();
612
613 self.mark.index += 1;
614 self.mark.col = 0;
615 self.mark.line += 1;
616 self.leading_whitespace = true;
617 }
618
619 #[inline]
621 fn skip_linebreak(&mut self) {
622 if self.input.next_2_are('\r', '\n') {
623 self.skip_blank();
626 self.skip_nl();
627 } else if self.input.next_is_break() {
628 self.skip_nl();
629 }
630 }
631
632 #[inline]
634 pub fn stream_started(&self) -> bool {
635 self.stream_start_produced
636 }
637
638 #[inline]
640 pub fn stream_ended(&self) -> bool {
641 self.stream_end_produced
642 }
643
644 #[inline]
646 pub fn mark(&self) -> Marker {
647 self.mark
648 }
649
650 #[inline]
657 fn read_break(&mut self, s: &mut String) {
658 self.skip_break();
659 s.push('\n');
660 }
661
662 #[inline]
667 fn skip_break(&mut self) {
668 let c = self.input.peek();
669 let nc = self.input.peek_nth(1);
670 debug_assert!(is_break(c));
671 if c == '\r' && nc == '\n' {
672 self.skip_blank();
673 }
674 self.skip_nl();
675 }
676
677 fn insert_token(&mut self, pos: usize, tok: Token<'input>) {
679 let old_len = self.tokens.len();
680 assert!(pos <= old_len);
681 self.tokens.insert(pos, tok);
682 }
683
684 fn allow_simple_key(&mut self) {
685 self.simple_key_allowed = true;
686 }
687
688 fn disallow_simple_key(&mut self) {
689 self.simple_key_allowed = false;
690 }
691
692 pub fn fetch_next_token(&mut self) -> ScanResult {
697 self.input.lookahead(1);
698
699 if !self.stream_start_produced {
700 self.fetch_stream_start();
701 return Ok(());
702 }
703 self.skip_to_next_token()?;
704
705 debug_print!(
706 " \x1B[38;5;244m\u{2192} fetch_next_token after whitespace {:?} {:?}\x1B[m",
707 self.mark,
708 self.input.peek()
709 );
710
711 self.stale_simple_keys()?;
712
713 let mark = self.mark;
714 self.unroll_indent(mark.col as isize);
715
716 self.input.lookahead(4);
717
718 if self.input.next_is_z() {
719 if self.input.peek_opt() == Some('\0') {
720 return Err(ScanError::new_str(self.mark, "found unprintable character"));
721 }
722 self.fetch_stream_end()?;
723 return Ok(());
724 }
725
726 if self.input.next_char_is('\u{FEFF}') {
729 if self.mark.col == 0 && self.flow_level == 0 {
730 return self.fetch_byte_order_mark();
731 }
732
733 return Err(ScanError::new_str(
734 self.mark,
735 "a byte order mark must not appear inside a document",
736 ));
737 }
738
739 if self.mark.col == 0 {
740 if self.input.next_char_is('%') {
741 return self.fetch_directive();
742 } else if self.input.next_is_document_start() {
743 return self.fetch_document_indicator(TokenType::DocumentStart);
744 } else if self.input.next_is_document_end() {
745 self.fetch_document_indicator(TokenType::DocumentEnd)?;
746 self.skip_ws_to_eol(SkipTabs::Yes)?;
747 if !self.input.next_is_breakz() {
748 return Err(ScanError::new_str(
749 self.mark,
750 "invalid content after document end marker",
751 ));
752 }
753 return Ok(());
754 }
755 }
756
757 if (self.mark.col as isize) < self.indent {
758 return Err(ScanError::new_str(self.mark, "invalid indentation"));
759 }
760
761 let c = self.input.peek();
762 let nc = self.input.peek_nth(1);
763 match c {
764 '[' => self.fetch_flow_collection_start(TokenType::FlowSequenceStart),
765 '{' => self.fetch_flow_collection_start(TokenType::FlowMappingStart),
766 ']' => self.fetch_flow_collection_end(TokenType::FlowSequenceEnd),
767 '}' => self.fetch_flow_collection_end(TokenType::FlowMappingEnd),
768 ',' => self.fetch_flow_entry(),
769 '-' if is_blank_or_breakz(nc) => self.fetch_block_entry(),
770 '?' if is_blank_or_breakz(nc) => self.fetch_key(),
771 ':' if is_blank_or_breakz(nc) => self.fetch_value(),
772 ':' if self.flow_level > 0
773 && (is_flow(nc) || self.mark.index == self.adjacent_value_allowed_at) =>
774 {
775 self.fetch_flow_value()
776 }
777 '*' => self.fetch_anchor(true),
779 '&' => self.fetch_anchor(false),
781 '!' => self.fetch_tag(),
782 '|' if self.flow_level == 0 => self.fetch_block_scalar(true),
784 '>' if self.flow_level == 0 => self.fetch_block_scalar(false),
786 '\'' => self.fetch_flow_scalar(true),
787 '"' => self.fetch_flow_scalar(false),
788 '-' if !is_blank_or_breakz(nc) => self.fetch_plain_scalar(),
790 ':' | '?' if !is_blank_or_breakz(nc) && self.flow_level == 0 => {
791 self.fetch_plain_scalar()
792 }
793 '%' | '@' | '`' => Err(ScanError::new(
794 self.mark,
795 format!("unexpected character: `{c}'"),
796 )),
797 _ => self.fetch_plain_scalar(),
798 }
799 }
800
801 pub fn next_token(&mut self) -> Result<Option<Token<'input>>, ScanError> {
805 if self.stream_end_produced {
806 return Ok(None);
807 }
808
809 if !self.token_available {
810 self.fetch_more_tokens()?;
811 }
812 let Some(t) = self.tokens.pop_front() else {
813 return Err(ScanError::new_str(
814 self.mark,
815 "did not find expected next token",
816 ));
817 };
818 self.token_available = false;
819 self.tokens_parsed += 1;
820
821 if let TokenType::StreamEnd = t.1 {
822 self.stream_end_produced = true;
823 }
824 Ok(Some(t))
825 }
826
827 pub fn fetch_more_tokens(&mut self) -> ScanResult {
831 let mut need_more;
832 loop {
833 if self.tokens.is_empty() {
834 need_more = true;
835 } else {
836 need_more = false;
837 self.stale_simple_keys()?;
839 for sk in &self.simple_keys {
841 if sk.possible && sk.token_number == self.tokens_parsed {
842 need_more = true;
843 break;
844 }
845 }
846 }
847
848 if !need_more {
849 break;
850 }
851 self.fetch_next_token()?;
852 }
853 self.token_available = true;
854
855 Ok(())
856 }
857
858 fn stale_simple_keys(&mut self) -> ScanResult {
866 for sk in &mut self.simple_keys {
867 if sk.possible
868 && self.flow_level == 0
870 && (sk.mark.line < self.mark.line || sk.mark.index + 1024 < self.mark.index)
871 {
872 if sk.required {
873 return Err(ScanError::new_str(self.mark, "simple key expect ':'"));
874 }
875 sk.possible = false;
876 }
877 }
878 Ok(())
879 }
880
881 fn skip_to_next_token(&mut self) -> ScanResult {
887 loop {
888 match self.input.look_ch() {
889 '\t' if self.is_within_block()
896 && self.leading_whitespace
897 && (self.mark.col as isize) < self.indent =>
898 {
899 self.skip_ws_to_eol(SkipTabs::Yes)?;
900 if !self.input.next_is_breakz() {
902 return Err(ScanError::new_str(
903 self.mark,
904 "tabs disallowed within this context (block indentation)",
905 ));
906 }
907 }
908 '\t' | ' ' => self.skip_blank(),
909 '\n' | '\r' => {
910 self.input.lookahead(2);
911 self.skip_linebreak();
912 if self.flow_level == 0 {
913 self.allow_simple_key();
914 }
915 }
916 '#' => {
917 let comment_length = self.input.skip_while_non_breakz();
918 self.mark.index += comment_length;
919 self.mark.col += comment_length;
920 }
921 _ => break,
922 }
923 }
924 if let Some(err_mark) = self.interrupted_plain_by_comment.take() {
927 self.input.lookahead(4);
930 let is_immediate_next_line = self.mark.line == err_mark.line + 1;
934 if self.flow_level == 0
935 && is_immediate_next_line
936 && self.mark.col as isize > self.indent
937 && !self.input.next_is_z()
938 && !self.input.next_is_document_indicator()
939 && self.input.next_can_be_plain_scalar(false)
940 {
941 return Err(ScanError::new_str(
942 err_mark,
943 "comment intercepting the multiline text",
944 ));
945 }
946 }
947 Ok(())
948 }
949
950 fn skip_yaml_whitespace(&mut self) -> ScanResult {
955 let mut need_whitespace = true;
956 loop {
957 match self.input.look_ch() {
958 ' ' => {
959 self.skip_blank();
960
961 need_whitespace = false;
962 }
963 '\n' | '\r' => {
964 self.input.lookahead(2);
965 self.skip_linebreak();
966 if self.flow_level == 0 {
967 self.allow_simple_key();
968 }
969 need_whitespace = false;
970 }
971 '#' => {
972 let comment_length = self.input.skip_while_non_breakz();
973 self.mark.index += comment_length;
974 self.mark.col += comment_length;
975 }
976 _ => break,
977 }
978 }
979
980 if need_whitespace {
981 Err(ScanError::new_str(self.mark(), "expected whitespace"))
982 } else {
983 Ok(())
984 }
985 }
986
987 fn skip_ws_to_eol(&mut self, skip_tabs: SkipTabs) -> Result<SkipTabs, ScanError> {
988 let (n_bytes, result) = self.input.skip_ws_to_eol(skip_tabs);
989 self.mark.col += n_bytes;
990 self.mark.index += n_bytes;
991 if self.mark.col > 0 && self.input.look_ch() == '\u{FEFF}' {
993 return Err(ScanError::new_str(
994 self.mark,
995 "a byte order mark must not appear inside a document",
996 ));
997 }
998
999 result.map_err(|msg| ScanError::new_str(self.mark, msg))
1000 }
1001
1002 fn fetch_stream_start(&mut self) {
1003 let mark = self.mark;
1004 self.indent = -1;
1005 self.stream_start_produced = true;
1006 self.allow_simple_key();
1007 self.tokens.push_back(Token(
1008 Span::empty(mark),
1009 TokenType::StreamStart(TEncoding::Utf8),
1010 ));
1011 self.simple_keys.push(SimpleKey::new(Marker::new(0, 0, 0)));
1012 }
1013
1014 fn fetch_stream_end(&mut self) -> ScanResult {
1015 if self.mark.col != 0 {
1017 self.mark.col = 0;
1018 self.mark.line += 1;
1019 }
1020
1021 for sk in &mut self.simple_keys {
1024 if sk.required && sk.possible {
1025 return Err(ScanError::new_str(self.mark, "simple key expected"));
1026 }
1027 sk.possible = false;
1028 }
1029
1030 self.unroll_indent(-1);
1031 self.remove_simple_key()?;
1032 self.disallow_simple_key();
1033
1034 self.tokens
1035 .push_back(Token(Span::empty(self.mark), TokenType::StreamEnd));
1036 Ok(())
1037 }
1038
1039 fn fetch_directive(&mut self) -> ScanResult {
1040 self.unroll_indent(-1);
1041 self.remove_simple_key()?;
1042
1043 self.disallow_simple_key();
1044
1045 let tok = self.scan_directive()?;
1046 self.tokens.push_back(tok);
1047
1048 Ok(())
1049 }
1050
1051 fn scan_directive(&mut self) -> Result<Token<'input>, ScanError> {
1052 let start_mark = self.mark;
1053 self.skip_non_blank();
1054
1055 let name = self.scan_directive_name()?;
1056 let tok = match name.as_ref() {
1057 "YAML" => self.scan_version_directive_value(&start_mark)?,
1058 "TAG" => self.scan_tag_directive_value(&start_mark)?,
1059 _ => {
1060 let mut params = Vec::new();
1061 while self.input.next_is_blank() {
1062 let n_blanks = self.input.skip_while_blank();
1063 self.mark.index += n_blanks;
1064 self.mark.col += n_blanks;
1065
1066 if !is_blank_or_breakz(self.input.peek()) {
1067 let mut param = String::new();
1068 let n_chars = self.input.fetch_while_is_yaml_non_space(&mut param);
1069 self.mark.index += n_chars;
1070 self.mark.col += n_chars;
1071 params.push(param);
1072 }
1073 }
1074
1075 Token(
1076 Span::new(start_mark, self.mark),
1077 TokenType::ReservedDirective(name, params),
1078 )
1079 }
1080 };
1081
1082 self.skip_ws_to_eol(SkipTabs::Yes)?;
1083
1084 if self.input.next_is_breakz() {
1085 self.input.lookahead(2);
1086 self.skip_linebreak();
1087 Ok(tok)
1088 } else {
1089 Err(ScanError::new_str(
1090 start_mark,
1091 "while scanning a directive, did not find expected comment or line break",
1092 ))
1093 }
1094 }
1095
1096 fn scan_version_directive_value(&mut self, mark: &Marker) -> Result<Token<'input>, ScanError> {
1097 let n_blanks = self.input.skip_while_blank();
1098 self.mark.index += n_blanks;
1099 self.mark.col += n_blanks;
1100
1101 let major = self.scan_version_directive_number(mark)?;
1102
1103 if self.input.peek() != '.' {
1104 return Err(ScanError::new_str(
1105 *mark,
1106 "while scanning a YAML directive, did not find expected digit or '.' character",
1107 ));
1108 }
1109 self.skip_non_blank();
1110
1111 let minor = self.scan_version_directive_number(mark)?;
1112
1113 Ok(Token(
1114 Span::new(*mark, self.mark),
1115 TokenType::VersionDirective(major, minor),
1116 ))
1117 }
1118
1119 fn scan_directive_name(&mut self) -> Result<String, ScanError> {
1120 let start_mark = self.mark;
1121 let mut string = String::new();
1122
1123 let n_chars = self.input.fetch_while_is_yaml_non_space(&mut string);
1124 self.mark.index += n_chars;
1125 self.mark.col += n_chars;
1126
1127 if string.is_empty() {
1128 return Err(ScanError::new_str(
1129 start_mark,
1130 "while scanning a directive, could not find expected directive name",
1131 ));
1132 }
1133
1134 if !is_blank_or_breakz(self.input.peek()) {
1135 return Err(ScanError::new_str(
1136 start_mark,
1137 "while scanning a directive, found unexpected non-alphabetical character",
1138 ));
1139 }
1140
1141 Ok(string)
1142 }
1143
1144 fn scan_version_directive_number(&mut self, mark: &Marker) -> Result<u32, ScanError> {
1145 let mut val = 0u32;
1146 let mut length = 0usize;
1147 while let Some(digit) = self.input.look_ch().to_digit(10) {
1148 if length + 1 > 9 {
1149 return Err(ScanError::new_str(
1150 *mark,
1151 "while scanning a YAML directive, found extremely long version number",
1152 ));
1153 }
1154 length += 1;
1155 val = val * 10 + digit;
1156 self.skip_non_blank();
1157 }
1158
1159 if length == 0 {
1160 return Err(ScanError::new_str(
1161 *mark,
1162 "while scanning a YAML directive, did not find expected version number",
1163 ));
1164 }
1165
1166 Ok(val)
1167 }
1168
1169 fn scan_tag_directive_value(&mut self, mark: &Marker) -> Result<Token<'input>, ScanError> {
1170 let n_blanks = self.input.skip_while_blank();
1171 self.mark.index += n_blanks;
1172 self.mark.col += n_blanks;
1173
1174 let handle = self.scan_tag_handle(true, mark)?;
1175
1176 let n_blanks = self.input.skip_while_blank();
1177 self.mark.index += n_blanks;
1178 self.mark.col += n_blanks;
1179
1180 let prefix = self.scan_tag_prefix(mark)?;
1181
1182 self.input.lookahead(1);
1183
1184 if self.input.next_is_blank_or_breakz() {
1185 Ok(Token(
1186 Span::new(*mark, self.mark),
1187 TokenType::TagDirective(handle.into(), prefix.into()),
1188 ))
1189 } else {
1190 Err(ScanError::new_str(
1191 *mark,
1192 "while scanning TAG, did not find expected whitespace or line break",
1193 ))
1194 }
1195 }
1196
1197 fn fetch_tag(&mut self) -> ScanResult {
1198 self.save_simple_key();
1199 self.disallow_simple_key();
1200
1201 let tok = self.scan_tag()?;
1202 self.tokens.push_back(tok);
1203 Ok(())
1204 }
1205
1206 fn scan_tag(&mut self) -> Result<Token<'input>, ScanError> {
1207 let start_mark = self.mark;
1208 let mut handle = String::new();
1209 let mut suffix;
1210
1211 self.input.lookahead(2);
1213
1214 if self.input.nth_char_is(1, '<') {
1215 suffix = self.scan_verbatim_tag(&start_mark)?;
1216 } else {
1217 handle = self.scan_tag_handle(false, &start_mark)?;
1219 if handle.len() >= 2 && handle.starts_with('!') && handle.ends_with('!') {
1221 let is_secondary_handle = handle == "!!";
1223 suffix =
1224 self.scan_tag_shorthand_suffix(false, is_secondary_handle, "", &start_mark)?;
1225 } else {
1226 suffix = self.scan_tag_shorthand_suffix(false, false, &handle, &start_mark)?;
1227 "!".clone_into(&mut handle);
1228 if suffix.is_empty() {
1231 handle.clear();
1232 "!".clone_into(&mut suffix);
1233 }
1234 }
1235 }
1236
1237 if is_blank_or_breakz(self.input.look_ch())
1238 || (self.flow_level > 0 && self.input.next_is_flow())
1239 {
1240 Ok(Token(
1242 Span::new(start_mark, self.mark),
1243 TokenType::Tag(handle, suffix),
1244 ))
1245 } else {
1246 Err(ScanError::new_str(
1247 start_mark,
1248 "while scanning a tag, did not find expected whitespace or line break",
1249 ))
1250 }
1251 }
1252
1253 fn scan_tag_handle(&mut self, directive: bool, mark: &Marker) -> Result<String, ScanError> {
1254 let mut string = String::new();
1255 if self.input.look_ch() != '!' {
1256 return Err(ScanError::new_str(
1257 *mark,
1258 "while scanning a tag, did not find expected '!'",
1259 ));
1260 }
1261
1262 string.push(self.input.peek());
1263 self.skip_non_blank();
1264
1265 let n_chars = self.input.fetch_while_is_alpha(&mut string);
1266 self.mark.index += n_chars;
1267 self.mark.col += n_chars;
1268
1269 if self.input.peek() == '!' {
1271 string.push(self.input.peek());
1272 self.skip_non_blank();
1273 } else if directive && string != "!" {
1274 return Err(ScanError::new_str(
1278 *mark,
1279 "while parsing a tag directive, did not find expected '!'",
1280 ));
1281 }
1282 Ok(string)
1283 }
1284
1285 fn scan_tag_prefix(&mut self, start_mark: &Marker) -> Result<String, ScanError> {
1291 let mut string = String::new();
1292
1293 if self.input.look_ch() == '!' {
1294 string.push(self.input.peek());
1296 self.skip_non_blank();
1297 } else if !is_tag_char(self.input.peek()) {
1298 return Err(ScanError::new_str(
1300 *start_mark,
1301 "invalid global tag character",
1302 ));
1303 } else if self.input.peek() == '%' {
1304 string.push(self.scan_uri_escapes(start_mark)?);
1306 } else {
1307 string.push(self.input.peek());
1309 self.skip_non_blank();
1310 }
1311
1312 while is_uri_char(self.input.look_ch()) {
1313 if self.input.peek() == '%' {
1314 string.push(self.scan_uri_escapes(start_mark)?);
1315 } else {
1316 string.push(self.input.peek());
1317 self.skip_non_blank();
1318 }
1319 }
1320
1321 Ok(string)
1322 }
1323
1324 fn scan_verbatim_tag(&mut self, start_mark: &Marker) -> Result<String, ScanError> {
1328 self.skip_non_blank();
1330 self.skip_non_blank();
1331
1332 let mut string = String::new();
1333 while is_uri_char(self.input.look_ch()) {
1334 if self.input.peek() == '%' {
1335 string.push(self.scan_uri_escapes(start_mark)?);
1336 } else {
1337 string.push(self.input.peek());
1338 self.skip_non_blank();
1339 }
1340 }
1341
1342 if self.input.peek() != '>' {
1343 return Err(ScanError::new_str(
1344 *start_mark,
1345 "while scanning a verbatim tag, did not find the expected '>'",
1346 ));
1347 }
1348 self.skip_non_blank();
1349
1350 Ok(string)
1351 }
1352
1353 fn scan_tag_shorthand_suffix(
1354 &mut self,
1355 _directive: bool,
1356 _is_secondary: bool,
1357 head: &str,
1358 mark: &Marker,
1359 ) -> Result<String, ScanError> {
1360 let mut length = head.len();
1361 let mut string = String::new();
1362
1363 if length > 1 {
1366 string.extend(head.chars().skip(1));
1367 }
1368
1369 while is_tag_char(self.input.look_ch()) {
1370 if self.input.peek() == '%' {
1372 string.push(self.scan_uri_escapes(mark)?);
1373 } else {
1374 string.push(self.input.peek());
1375 self.skip_non_blank();
1376 }
1377
1378 length += 1;
1379 }
1380
1381 if length == 0 {
1382 return Err(ScanError::new_str(
1383 *mark,
1384 "while parsing a tag, did not find expected tag URI",
1385 ));
1386 }
1387
1388 Ok(string)
1389 }
1390
1391 fn scan_uri_escapes(&mut self, mark: &Marker) -> Result<char, ScanError> {
1392 let mut width = 0usize;
1393 let mut code = 0u32;
1394 loop {
1395 self.input.lookahead(3);
1396
1397 let c = self.input.peek_nth(1);
1398 let nc = self.input.peek_nth(2);
1399
1400 if !(self.input.peek() == '%' && is_hex(c) && is_hex(nc)) {
1401 return Err(ScanError::new_str(
1402 *mark,
1403 "while parsing a tag, found an invalid escape sequence",
1404 ));
1405 }
1406
1407 let byte = (as_hex(c) << 4) + as_hex(nc);
1408 if width == 0 {
1409 width = match byte {
1410 _ if byte & 0x80 == 0x00 => 1,
1411 _ if byte & 0xE0 == 0xC0 => 2,
1412 _ if byte & 0xF0 == 0xE0 => 3,
1413 _ if byte & 0xF8 == 0xF0 => 4,
1414 _ => {
1415 return Err(ScanError::new_str(
1416 *mark,
1417 "while parsing a tag, found an incorrect leading UTF-8 byte",
1418 ));
1419 }
1420 };
1421 code = byte;
1422 } else {
1423 if byte & 0xc0 != 0x80 {
1424 return Err(ScanError::new_str(
1425 *mark,
1426 "while parsing a tag, found an incorrect trailing UTF-8 byte",
1427 ));
1428 }
1429 code = (code << 8) + byte;
1430 }
1431
1432 self.skip_n_non_blank(3);
1433
1434 width -= 1;
1435 if width == 0 {
1436 break;
1437 }
1438 }
1439
1440 match char::from_u32(code) {
1441 Some(ch) => Ok(ch),
1442 None => Err(ScanError::new_str(
1443 *mark,
1444 "while parsing a tag, found an invalid UTF-8 codepoint",
1445 )),
1446 }
1447 }
1448
1449 fn fetch_anchor(&mut self, alias: bool) -> ScanResult {
1450 self.save_simple_key();
1451 self.disallow_simple_key();
1452
1453 let tok = self.scan_anchor(alias)?;
1454
1455 self.tokens.push_back(tok);
1456
1457 Ok(())
1458 }
1459
1460 fn scan_anchor(&mut self, alias: bool) -> Result<Token<'input>, ScanError> {
1461 let mut string = String::new();
1462 let start_mark = self.mark;
1463
1464 self.skip_non_blank();
1465 while is_anchor_char(self.input.look_ch()) {
1466 string.push(self.input.peek());
1467 self.skip_non_blank();
1468 }
1469
1470 if string.is_empty() {
1471 return Err(ScanError::new_str(
1472 start_mark,
1473 "while scanning an anchor or alias, did not find expected alphabetic or numeric character",
1474 ));
1475 }
1476
1477 let tok = if alias {
1478 TokenType::Alias(string.into())
1479 } else {
1480 TokenType::Anchor(string.into())
1481 };
1482 Ok(Token(Span::new(start_mark, self.mark), tok))
1483 }
1484
1485 fn fetch_flow_collection_start(&mut self, tok: TokenType<'input>) -> ScanResult {
1486 self.save_simple_key();
1488
1489 self.roll_one_col_indent();
1490 self.increase_flow_level()?;
1491
1492 self.allow_simple_key();
1493
1494 let start_mark = self.mark;
1495 self.skip_non_blank();
1496
1497 if tok == TokenType::FlowMappingStart {
1498 self.flow_mapping_started = true;
1499 } else {
1500 self.implicit_flow_mapping_states
1501 .push(ImplicitMappingState::Possible);
1502 }
1503
1504 self.skip_ws_to_eol(SkipTabs::Yes)?;
1505
1506 self.tokens
1507 .push_back(Token(Span::new(start_mark, self.mark), tok));
1508 Ok(())
1509 }
1510
1511 fn fetch_flow_collection_end(&mut self, tok: TokenType<'input>) -> ScanResult {
1512 if self.flow_level == 0 {
1514 return Err(ScanError::new_str(self.mark, "misplaced bracket"));
1515 }
1516
1517 self.remove_simple_key()?;
1518 self.decrease_flow_level();
1519
1520 self.disallow_simple_key();
1521
1522 if matches!(tok, TokenType::FlowSequenceEnd) {
1523 self.end_implicit_mapping(self.mark);
1524 self.implicit_flow_mapping_states.pop();
1526 }
1527
1528 let start_mark = self.mark;
1529 self.skip_non_blank();
1530 self.skip_ws_to_eol(SkipTabs::Yes)?;
1531
1532 if self.flow_level > 0 {
1538 self.adjacent_value_allowed_at = self.mark.index;
1539 }
1540
1541 self.tokens
1542 .push_back(Token(Span::new(start_mark, self.mark), tok));
1543 Ok(())
1544 }
1545
1546 fn fetch_flow_entry(&mut self) -> ScanResult {
1548 self.remove_simple_key()?;
1549 self.allow_simple_key();
1550
1551 self.end_implicit_mapping(self.mark);
1552
1553 let start_mark = self.mark;
1554 self.skip_non_blank();
1555 self.skip_ws_to_eol(SkipTabs::Yes)?;
1556
1557 self.tokens.push_back(Token(
1558 Span::new(start_mark, self.mark),
1559 TokenType::FlowEntry,
1560 ));
1561 Ok(())
1562 }
1563
1564 fn increase_flow_level(&mut self) -> ScanResult {
1565 self.simple_keys.push(SimpleKey::new(Marker::new(0, 0, 0)));
1566 self.flow_level = self
1567 .flow_level
1568 .checked_add(1)
1569 .ok_or_else(|| ScanError::new_str(self.mark, "recursion limit exceeded"))?;
1570 Ok(())
1571 }
1572
1573 fn decrease_flow_level(&mut self) {
1574 if self.flow_level > 0 {
1575 self.flow_level -= 1;
1576 self.simple_keys.pop().unwrap();
1577 }
1578 }
1579
1580 fn fetch_block_entry(&mut self) -> ScanResult {
1586 if self.flow_level > 0 {
1587 return Err(ScanError::new_str(
1589 self.mark,
1590 r#""-" is only valid inside a block"#,
1591 ));
1592 }
1593 if !self.simple_key_allowed {
1595 return Err(ScanError::new_str(
1596 self.mark,
1597 "block sequence entries are not allowed in this context",
1598 ));
1599 }
1600
1601 if let Some(Token(span, TokenType::Anchor(..) | TokenType::Tag(..))) = self.tokens.back() {
1603 if self.mark.col == 0 && span.start.col == 0 && self.indent > -1 {
1604 return Err(ScanError::new_str(
1605 span.start,
1606 "invalid indentation for anchor",
1607 ));
1608 }
1609 }
1610
1611 let mark = self.mark;
1613 self.skip_non_blank();
1614
1615 self.roll_indent(mark.col, None, TokenType::BlockSequenceStart, mark);
1617 let found_tabs = self.skip_ws_to_eol(SkipTabs::Yes)?.found_tabs();
1618 self.input.lookahead(2);
1619 if found_tabs && self.input.next_char_is('-') && is_blank_or_breakz(self.input.peek_nth(1))
1620 {
1621 return Err(ScanError::new_str(
1622 self.mark,
1623 "'-' must be followed by a valid YAML whitespace",
1624 ));
1625 }
1626
1627 self.skip_ws_to_eol(SkipTabs::No)?;
1628 self.input.lookahead(1);
1629 if self.input.next_is_break() || self.input.next_is_flow() {
1630 self.roll_one_col_indent();
1631 }
1632
1633 self.remove_simple_key()?;
1634 self.allow_simple_key();
1635
1636 self.tokens
1637 .push_back(Token(Span::empty(self.mark), TokenType::BlockEntry));
1638
1639 Ok(())
1640 }
1641
1642 fn fetch_byte_order_mark(&mut self) -> ScanResult {
1643 self.unroll_indent(-1);
1644 self.remove_simple_key()?;
1645
1646 let mark = self.mark;
1648 self.input.skip();
1649 self.mark.index += 1;
1650 self.allow_simple_key();
1651
1652 self.tokens
1653 .push_back(Token(Span::new(mark, self.mark), TokenType::ByteOrderMark));
1654 Ok(())
1655 }
1656
1657 fn fetch_document_indicator(&mut self, t: TokenType<'input>) -> ScanResult {
1658 self.unroll_indent(-1);
1659 self.remove_simple_key()?;
1660 self.disallow_simple_key();
1661
1662 let mark = self.mark;
1663
1664 self.skip_n_non_blank(3);
1665
1666 self.tokens.push_back(Token(Span::new(mark, self.mark), t));
1667 Ok(())
1668 }
1669
1670 fn fetch_block_scalar(&mut self, literal: bool) -> ScanResult {
1671 self.save_simple_key();
1672 self.allow_simple_key();
1673 let tok = self.scan_block_scalar(literal)?;
1674
1675 self.tokens.push_back(tok);
1676 Ok(())
1677 }
1678
1679 #[allow(clippy::too_many_lines)]
1680 fn scan_block_scalar(&mut self, literal: bool) -> Result<Token<'input>, ScanError> {
1681 let start_mark = self.mark;
1682 let mut chomping = Chomping::Clip;
1683 let mut increment: usize = 0;
1684 let mut indent: usize = 0;
1685 let mut trailing_blank: bool;
1686 let mut leading_blank: bool = false;
1687 let style = if literal {
1688 ScalarStyle::Literal
1689 } else {
1690 ScalarStyle::Folded
1691 };
1692
1693 let mut string = String::new();
1694 let mut leading_break = String::new();
1695 let mut trailing_breaks = String::new();
1696
1697 self.skip_non_blank();
1699 self.unroll_non_block_indents();
1700
1701 if self.input.look_ch() == '+' || self.input.peek() == '-' {
1702 if self.input.peek() == '+' {
1703 chomping = Chomping::Keep;
1704 } else {
1705 chomping = Chomping::Strip;
1706 }
1707 self.skip_non_blank();
1708 self.input.lookahead(1);
1709 if self.input.next_is_digit() {
1710 if self.input.peek() == '0' {
1711 return Err(ScanError::new_str(
1712 start_mark,
1713 "while scanning a block scalar, found an indentation indicator equal to 0",
1714 ));
1715 }
1716 increment = (self.input.peek() as usize) - ('0' as usize);
1717 self.skip_non_blank();
1718 }
1719 } else if self.input.next_is_digit() {
1720 if self.input.peek() == '0' {
1721 return Err(ScanError::new_str(
1722 start_mark,
1723 "while scanning a block scalar, found an indentation indicator equal to 0",
1724 ));
1725 }
1726
1727 increment = (self.input.peek() as usize) - ('0' as usize);
1728 self.skip_non_blank();
1729 self.input.lookahead(1);
1730 if self.input.peek() == '+' || self.input.peek() == '-' {
1731 if self.input.peek() == '+' {
1732 chomping = Chomping::Keep;
1733 } else {
1734 chomping = Chomping::Strip;
1735 }
1736 self.skip_non_blank();
1737 }
1738 }
1739
1740 self.skip_ws_to_eol(SkipTabs::Yes)?;
1741
1742 self.input.lookahead(1);
1744 if !self.input.next_is_breakz() {
1745 return Err(ScanError::new_str(
1746 start_mark,
1747 "while scanning a block scalar, did not find expected comment or line break",
1748 ));
1749 }
1750
1751 if self.input.next_is_break() {
1752 self.input.lookahead(2);
1753 self.skip_break();
1754 }
1755
1756 if self.input.look_ch() == '\t' {
1757 return Err(ScanError::new_str(
1758 start_mark,
1759 "a block scalar content cannot start with a tab",
1760 ));
1761 }
1762
1763 if increment > 0 {
1764 indent = if self.indent >= 0 {
1765 (self.indent + increment as isize) as usize
1766 } else {
1767 increment
1768 }
1769 }
1770
1771 if indent == 0 {
1773 self.skip_block_scalar_first_line_indent(&mut indent, &mut trailing_breaks);
1774 } else {
1775 self.skip_block_scalar_indent(indent, &mut trailing_breaks);
1776 }
1777
1778 if self.input.next_is_z() {
1783 let contents = match chomping {
1784 Chomping::Strip | Chomping::Clip => String::new(),
1787 Chomping::Keep
1790 if trailing_breaks.is_empty()
1791 && self.mark.line > start_mark.line()
1792 && self.mark.col > 0 =>
1793 {
1794 "\n".into()
1795 }
1796 Chomping::Keep => trailing_breaks,
1797 };
1798 return Ok(Token(
1799 Span::new(start_mark, self.mark),
1800 TokenType::Scalar(style, contents.into()),
1801 ));
1802 }
1803
1804 if self.mark.col < indent && (self.mark.col as isize) > self.indent {
1805 return Err(ScanError::new_str(
1806 self.mark,
1807 "wrongly indented line in block scalar",
1808 ));
1809 }
1810
1811 let mut line_buffer = String::with_capacity(100);
1812 let start_mark = self.mark;
1813 while self.mark.col == indent && is_yaml_non_break(self.input.peek()) {
1814 if indent == 0 {
1815 self.input.lookahead(4);
1816 if self.input.next_is_document_end() {
1817 break;
1818 }
1819 }
1820
1821 trailing_blank = self.input.next_is_blank();
1823 if !literal && !leading_break.is_empty() && !leading_blank && !trailing_blank {
1824 string.push_str(&trailing_breaks);
1825 if trailing_breaks.is_empty() {
1826 string.push(' ');
1827 }
1828 } else {
1829 string.push_str(&leading_break);
1830 string.push_str(&trailing_breaks);
1831 }
1832
1833 leading_break.clear();
1834 trailing_breaks.clear();
1835
1836 leading_blank = self.input.next_is_blank();
1837
1838 self.scan_block_scalar_content_line(&mut string, &mut line_buffer);
1839
1840 self.input.lookahead(2);
1842 if !self.input.next_is_break() {
1843 break;
1844 }
1845
1846 self.read_break(&mut leading_break);
1847
1848 self.skip_block_scalar_indent(indent, &mut trailing_breaks);
1850 }
1851
1852 if chomping != Chomping::Strip {
1854 string.push_str(&leading_break);
1855 if self.input.next_is_z() && self.mark.col >= indent.max(1) {
1859 string.push('\n');
1860 }
1861 }
1862
1863 if chomping == Chomping::Keep {
1864 string.push_str(&trailing_breaks);
1865 }
1866
1867 Ok(Token(
1868 Span::new(start_mark, self.mark),
1869 TokenType::Scalar(style, string.into()),
1870 ))
1871 }
1872
1873 fn scan_block_scalar_content_line(&mut self, string: &mut String, line_buffer: &mut String) {
1883 while !self.input.buf_is_empty() && is_yaml_non_break(self.input.peek()) {
1885 string.push(self.input.peek());
1886 self.skip_blank();
1892 }
1893
1894 if self.input.buf_is_empty() {
1897 while let Some(c) = self.input.raw_read_non_breakz_ch() {
1903 line_buffer.push(c);
1904 }
1905
1906 let n_chars = line_buffer.chars().count();
1908 self.mark.col += n_chars;
1909 self.mark.index += n_chars;
1910
1911 string.reserve(line_buffer.len());
1913 string.push_str(line_buffer);
1914 line_buffer.clear();
1916 }
1917 }
1918
1919 fn skip_block_scalar_indent(&mut self, indent: usize, breaks: &mut String) {
1921 loop {
1922 if indent < self.input.bufmaxlen() - 2 {
1924 self.input.lookahead(self.input.bufmaxlen());
1925 while self.mark.col < indent && self.input.peek() == ' ' {
1926 self.skip_blank();
1927 }
1928 } else {
1929 loop {
1930 self.input.lookahead(self.input.bufmaxlen());
1931 while !self.input.buf_is_empty()
1932 && self.mark.col < indent
1933 && self.input.peek() == ' '
1934 {
1935 self.skip_blank();
1936 }
1937 if self.mark.col == indent
1941 || (!self.input.buf_is_empty() && self.input.peek() != ' ')
1942 {
1943 break;
1944 }
1945 }
1946 self.input.lookahead(2);
1947 }
1948
1949 if self.input.next_is_break() {
1951 self.read_break(breaks);
1952 } else {
1953 break;
1955 }
1956 }
1957 }
1958
1959 fn skip_block_scalar_first_line_indent(&mut self, indent: &mut usize, breaks: &mut String) {
1964 let mut max_indent = 0;
1965 loop {
1966 while self.input.look_ch() == ' ' {
1968 self.skip_blank();
1969 }
1970
1971 if self.mark.col > max_indent {
1972 max_indent = self.mark.col;
1973 }
1974
1975 if self.input.next_is_break() {
1976 self.input.lookahead(2);
1978 self.read_break(breaks);
1979 } else {
1980 break;
1982 }
1983 }
1984
1985 *indent = max_indent.max((self.indent + 1) as usize);
1994 if self.indent > 0 {
1995 *indent = (*indent).max(1);
1996 }
1997 }
1998
1999 fn fetch_flow_scalar(&mut self, single: bool) -> ScanResult {
2000 self.save_simple_key();
2001 self.disallow_simple_key();
2002
2003 let tok = self.scan_flow_scalar(single)?;
2004
2005 self.skip_to_next_token()?;
2008 self.adjacent_value_allowed_at = self.mark.index;
2009
2010 self.tokens.push_back(tok);
2011 Ok(())
2012 }
2013
2014 #[allow(clippy::too_many_lines)]
2015 fn scan_flow_scalar(&mut self, single: bool) -> Result<Token<'input>, ScanError> {
2016 let start_mark = self.mark;
2017
2018 let mut string = String::new();
2019 let mut leading_break = String::new();
2020 let mut trailing_breaks = String::new();
2021 let mut whitespaces = String::new();
2022 let mut leading_blanks;
2023
2024 self.skip_non_blank();
2026
2027 loop {
2028 self.input.lookahead(4);
2030
2031 if self.mark.col == 0 && self.input.next_is_document_indicator() {
2032 return Err(ScanError::new_str(
2033 start_mark,
2034 "while scanning a quoted scalar, found unexpected document indicator",
2035 ));
2036 }
2037
2038 if self.input.next_is_z() {
2039 return Err(ScanError::new_str(
2040 start_mark,
2041 "while scanning a quoted scalar, found unexpected end of stream",
2042 ));
2043 }
2044
2045 if (self.mark.col as isize) < self.indent {
2046 return Err(ScanError::new_str(
2047 start_mark,
2048 "invalid indentation in quoted scalar",
2049 ));
2050 }
2051
2052 leading_blanks = false;
2053 self.consume_flow_scalar_non_whitespace_chars(
2054 single,
2055 &mut string,
2056 &mut leading_blanks,
2057 &start_mark,
2058 )?;
2059
2060 match self.input.look_ch() {
2061 '\'' if single => break,
2062 '"' if !single => break,
2063 _ => {}
2064 }
2065
2066 while self.input.next_is_blank() || self.input.next_is_break() {
2068 if self.input.next_is_blank() {
2069 if leading_blanks {
2071 if self.input.peek() == '\t' && (self.mark.col as isize) < self.indent {
2072 return Err(ScanError::new_str(
2073 self.mark,
2074 "tab cannot be used as indentation",
2075 ));
2076 }
2077 self.skip_blank();
2078 } else {
2079 whitespaces.push(self.input.peek());
2080 self.skip_blank();
2081 }
2082 } else {
2083 self.input.lookahead(2);
2084 if leading_blanks {
2086 self.read_break(&mut trailing_breaks);
2087 } else {
2088 whitespaces.clear();
2089 self.read_break(&mut leading_break);
2090 leading_blanks = true;
2091 }
2092 }
2093 self.input.lookahead(1);
2094 }
2095
2096 if leading_blanks {
2098 if leading_break.is_empty() {
2099 string.push_str(&leading_break);
2100 string.push_str(&trailing_breaks);
2101 trailing_breaks.clear();
2102 leading_break.clear();
2103 } else {
2104 if trailing_breaks.is_empty() {
2105 string.push(' ');
2106 } else {
2107 string.push_str(&trailing_breaks);
2108 trailing_breaks.clear();
2109 }
2110 leading_break.clear();
2111 }
2112 } else {
2113 string.push_str(&whitespaces);
2114 whitespaces.clear();
2115 }
2116 } self.skip_non_blank();
2120 self.skip_ws_to_eol(SkipTabs::Yes)?;
2122 match self.input.peek() {
2123 ',' | '}' | ']' if self.flow_level > 0 => {}
2125 c if is_breakz(c) => {}
2127 ':' if self.flow_level == 0 && start_mark.line == self.mark.line => {}
2130 ':' if self.flow_level > 0 => {}
2132 _ => {
2133 return Err(ScanError::new_str(
2134 self.mark,
2135 "invalid trailing content after double-quoted scalar",
2136 ));
2137 }
2138 }
2139
2140 let style = if single {
2141 ScalarStyle::SingleQuoted
2142 } else {
2143 ScalarStyle::DoubleQuoted
2144 };
2145 Ok(Token(
2146 Span::new(start_mark, self.mark),
2147 TokenType::Scalar(style, string.into()),
2148 ))
2149 }
2150
2151 fn consume_flow_scalar_non_whitespace_chars(
2160 &mut self,
2161 single: bool,
2162 string: &mut String,
2163 leading_blanks: &mut bool,
2164 start_mark: &Marker,
2165 ) -> Result<(), ScanError> {
2166 self.input.lookahead(2);
2167 while !is_blank_or_breakz(self.input.peek()) {
2168 match self.input.peek() {
2169 '\'' if self.input.peek_nth(1) == '\'' && single => {
2171 string.push('\'');
2172 self.skip_n_non_blank(2);
2173 }
2174 '\'' if single => break,
2176 '"' if !single => break,
2177 '\\' if !single && is_break(self.input.peek_nth(1)) => {
2179 self.input.lookahead(3);
2180 self.skip_non_blank();
2181 self.skip_linebreak();
2182 *leading_blanks = true;
2183 break;
2184 }
2185 '\\' if !single => {
2187 string.push(self.resolve_flow_scalar_escape_sequence(start_mark)?);
2188 }
2189 c => {
2190 string.push(c);
2191 self.skip_non_blank();
2192 }
2193 }
2194 self.input.lookahead(2);
2195 }
2196 Ok(())
2197 }
2198
2199 fn resolve_flow_scalar_escape_sequence(
2206 &mut self,
2207 start_mark: &Marker,
2208 ) -> Result<char, ScanError> {
2209 let mut code_length = 0usize;
2210 let mut ret = '\0';
2211
2212 match self.input.peek_nth(1) {
2213 '0' => ret = '\0',
2214 'a' => ret = '\x07',
2215 'b' => ret = '\x08',
2216 't' | '\t' => ret = '\t',
2217 'n' => ret = '\n',
2218 'v' => ret = '\x0b',
2219 'f' => ret = '\x0c',
2220 'r' => ret = '\x0d',
2221 'e' => ret = '\x1b',
2222 ' ' => ret = '\x20',
2223 '"' => ret = '"',
2224 '/' => ret = '/',
2225 '\\' => ret = '\\',
2226 'N' => ret = char::from_u32(0x85).unwrap(),
2228 '_' => ret = char::from_u32(0xA0).unwrap(),
2230 'L' => ret = char::from_u32(0x2028).unwrap(),
2232 'P' => ret = char::from_u32(0x2029).unwrap(),
2234 'x' => code_length = 2,
2235 'u' => code_length = 4,
2236 'U' => code_length = 8,
2237 _ => {
2238 return Err(ScanError::new_str(
2239 *start_mark,
2240 "while parsing a quoted scalar, found unknown escape character",
2241 ));
2242 }
2243 }
2244 self.skip_n_non_blank(2);
2245
2246 if code_length > 0 {
2248 self.input.lookahead(code_length);
2249 let mut value = 0u32;
2250 for i in 0..code_length {
2251 let c = self.input.peek_nth(i);
2252 if !is_hex(c) {
2253 return Err(ScanError::new_str(
2254 *start_mark,
2255 "while parsing a quoted scalar, did not find expected hexadecimal number",
2256 ));
2257 }
2258 value = (value << 4) + as_hex(c);
2259 }
2260
2261 let Some(ch) = char::from_u32(value) else {
2262 return Err(ScanError::new_str(
2263 *start_mark,
2264 "while parsing a quoted scalar, found invalid Unicode character escape code",
2265 ));
2266 };
2267 ret = ch;
2268
2269 self.skip_n_non_blank(code_length);
2270 }
2271 Ok(ret)
2272 }
2273
2274 fn fetch_plain_scalar(&mut self) -> ScanResult {
2275 self.save_simple_key();
2276 self.disallow_simple_key();
2277
2278 let tok = self.scan_plain_scalar()?;
2279
2280 self.tokens.push_back(tok);
2281 Ok(())
2282 }
2283
2284 #[allow(clippy::too_many_lines)]
2289 fn scan_plain_scalar(&mut self) -> Result<Token<'input>, ScanError> {
2290 self.unroll_non_block_indents();
2291 let indent = self.indent + 1;
2292 let start_mark = self.mark;
2293
2294 if self.flow_level > 0 && (start_mark.col as isize) < indent {
2295 return Err(ScanError::new_str(
2296 start_mark,
2297 "invalid indentation in flow construct",
2298 ));
2299 }
2300
2301 let mut string = String::with_capacity(32);
2302 self.buf_whitespaces.clear();
2303 self.buf_leading_break.clear();
2304 self.buf_trailing_breaks.clear();
2305 let mut end_mark = self.mark;
2306
2307 loop {
2308 self.input.lookahead(4);
2309 if (self.mark.col == 0 && self.input.next_is_document_indicator())
2310 || self.input.peek() == '#'
2311 {
2312 if self.input.peek() == '#'
2317 && !string.is_empty()
2318 && !self.buf_whitespaces.is_empty()
2319 && self.flow_level == 0
2320 {
2321 self.interrupted_plain_by_comment = Some(self.mark);
2322 }
2323 break;
2324 }
2325
2326 if self.flow_level > 0 && self.input.peek() == '-' && is_flow(self.input.peek_nth(1)) {
2327 return Err(ScanError::new_str(
2328 self.mark,
2329 "plain scalar cannot start with '-' followed by ,[]{}",
2330 ));
2331 }
2332
2333 if !self.input.next_is_blank_or_breakz()
2334 && self.input.next_can_be_plain_scalar(self.flow_level > 0)
2335 {
2336 if self.leading_whitespace {
2337 if self.buf_leading_break.is_empty() {
2338 string.push_str(&self.buf_leading_break);
2339 string.push_str(&self.buf_trailing_breaks);
2340 self.buf_trailing_breaks.clear();
2341 self.buf_leading_break.clear();
2342 } else {
2343 if self.buf_trailing_breaks.is_empty() {
2344 string.push(' ');
2345 } else {
2346 string.push_str(&self.buf_trailing_breaks);
2347 self.buf_trailing_breaks.clear();
2348 }
2349 self.buf_leading_break.clear();
2350 }
2351 self.leading_whitespace = false;
2352 } else if !self.buf_whitespaces.is_empty() {
2353 string.push_str(&self.buf_whitespaces);
2354 self.buf_whitespaces.clear();
2355 }
2356
2357 string.push(self.input.peek());
2359 self.skip_non_blank();
2360 string.reserve(self.input.bufmaxlen());
2361
2362 let mut end = false;
2364 while !end {
2365 self.input.lookahead(self.input.bufmaxlen());
2369 for _ in 0..self.input.bufmaxlen() - 1 {
2370 if self.input.next_is_blank_or_breakz()
2371 || !self.input.next_can_be_plain_scalar(self.flow_level > 0)
2372 {
2373 end = true;
2374 break;
2375 }
2376 string.push(self.input.peek());
2377 self.skip_non_blank();
2378 }
2379 }
2380 end_mark = self.mark;
2381 }
2382
2383 if !(self.input.next_is_blank() || self.input.next_is_break()) {
2388 break;
2389 }
2390
2391 self.input.lookahead(2);
2393 while self.input.next_is_blank_or_break() {
2394 if self.input.next_is_blank() {
2395 if !self.leading_whitespace {
2396 self.buf_whitespaces.push(self.input.peek());
2397 self.skip_blank();
2398 } else if (self.mark.col as isize) < indent && self.input.peek() == '\t' {
2399 self.skip_ws_to_eol(SkipTabs::Yes)?;
2402 if !self.input.next_is_breakz() {
2403 return Err(ScanError::new_str(
2404 start_mark,
2405 "while scanning a plain scalar, found a tab",
2406 ));
2407 }
2408 } else {
2409 self.skip_blank();
2410 }
2411 } else {
2412 if self.leading_whitespace {
2414 self.skip_break();
2415 self.buf_trailing_breaks.push('\n');
2416 } else {
2417 self.buf_whitespaces.clear();
2418 self.skip_break();
2419 self.buf_leading_break.push('\n');
2420 self.leading_whitespace = true;
2421 }
2422 }
2423 self.input.lookahead(2);
2424 }
2425
2426 if self.flow_level == 0 && (self.mark.col as isize) < indent {
2428 break;
2429 }
2430 }
2431
2432 if self.leading_whitespace {
2433 self.allow_simple_key();
2434 }
2435
2436 if string.is_empty() {
2437 Err(ScanError::new_str(
2441 start_mark,
2442 "unexpected end of plain scalar",
2443 ))
2444 } else {
2445 Ok(Token(
2446 Span::new(start_mark, end_mark),
2447 TokenType::Scalar(ScalarStyle::Plain, string.into()),
2448 ))
2449 }
2450 }
2451
2452 fn fetch_key(&mut self) -> ScanResult {
2453 let start_mark = self.mark;
2454 if self.flow_level == 0 {
2455 if !self.simple_key_allowed {
2457 return Err(ScanError::new_str(
2458 self.mark,
2459 "mapping keys are not allowed in this context",
2460 ));
2461 }
2462 self.roll_indent(
2463 start_mark.col,
2464 None,
2465 TokenType::BlockMappingStart,
2466 start_mark,
2467 );
2468 } else {
2469 self.flow_mapping_started = true;
2471 }
2472
2473 self.remove_simple_key()?;
2474
2475 if self.flow_level == 0 {
2476 self.allow_simple_key();
2477 } else {
2478 self.disallow_simple_key();
2479 }
2480
2481 self.skip_non_blank();
2482 self.skip_yaml_whitespace()?;
2483 if self.input.peek() == '\t' {
2484 return Err(ScanError::new_str(
2485 self.mark(),
2486 "tabs disallowed in this context",
2487 ));
2488 }
2489 self.tokens
2490 .push_back(Token(Span::new(start_mark, self.mark), TokenType::Key));
2491 Ok(())
2492 }
2493
2494 fn fetch_flow_value(&mut self) -> ScanResult {
2502 let nc = self.input.peek_nth(1);
2503
2504 if self.mark.index != self.adjacent_value_allowed_at && (nc == '[' || nc == '{') {
2516 return Err(ScanError::new_str(
2517 self.mark,
2518 "':' may not precede any of `[{` in flow mapping",
2519 ));
2520 }
2521
2522 self.fetch_value()
2523 }
2524
2525 fn fetch_value(&mut self) -> ScanResult {
2527 let sk = self.simple_keys.last().unwrap().clone();
2528 let start_mark = self.mark;
2529 let is_implicit_flow_mapping =
2530 !self.implicit_flow_mapping_states.is_empty() && !self.flow_mapping_started;
2531 if is_implicit_flow_mapping {
2532 *self.implicit_flow_mapping_states.last_mut().unwrap() = ImplicitMappingState::Inside;
2533 }
2534
2535 self.skip_non_blank();
2537 if self.input.look_ch() == '\t'
2538 && !self.skip_ws_to_eol(SkipTabs::Yes)?.has_valid_yaml_ws()
2539 && (self.input.peek() == '-' || self.input.next_is_alpha())
2540 {
2541 return Err(ScanError::new_str(
2542 self.mark,
2543 "':' must be followed by a valid YAML whitespace",
2544 ));
2545 }
2546
2547 if sk.possible {
2548 let tok = Token(Span::empty(sk.mark), TokenType::Key);
2550 self.insert_token(sk.token_number - self.tokens_parsed, tok);
2551 if is_implicit_flow_mapping {
2552 if sk.mark.line < start_mark.line {
2553 return Err(ScanError::new_str(
2554 start_mark,
2555 "illegal placement of ':' indicator",
2556 ));
2557 }
2558 self.insert_token(
2559 sk.token_number - self.tokens_parsed,
2560 Token(Span::empty(sk.mark), TokenType::FlowMappingStart),
2561 );
2562 }
2563
2564 self.roll_indent(
2566 sk.mark.col,
2567 Some(sk.token_number),
2568 TokenType::BlockMappingStart,
2569 sk.mark,
2570 );
2571 self.roll_one_col_indent();
2572
2573 self.simple_keys.last_mut().unwrap().possible = false;
2574 self.disallow_simple_key();
2575 } else {
2576 if is_implicit_flow_mapping {
2577 self.tokens
2578 .push_back(Token(Span::empty(start_mark), TokenType::FlowMappingStart));
2579 }
2580 if self.flow_level == 0 {
2582 if !self.simple_key_allowed {
2583 return Err(ScanError::new_str(
2584 start_mark,
2585 "mapping values are not allowed in this context",
2586 ));
2587 }
2588
2589 self.roll_indent(
2590 start_mark.col,
2591 None,
2592 TokenType::BlockMappingStart,
2593 start_mark,
2594 );
2595 }
2596 self.roll_one_col_indent();
2597
2598 if self.flow_level == 0 {
2599 self.allow_simple_key();
2600 } else {
2601 self.disallow_simple_key();
2602 }
2603 }
2604 self.tokens
2605 .push_back(Token(Span::empty(start_mark), TokenType::Value));
2606
2607 Ok(())
2608 }
2609
2610 fn roll_indent(
2616 &mut self,
2617 col: usize,
2618 number: Option<usize>,
2619 tok: TokenType<'input>,
2620 mark: Marker,
2621 ) {
2622 if self.flow_level > 0 {
2623 return;
2624 }
2625
2626 if self.indent <= col as isize {
2630 if let Some(indent) = self.indents.last() {
2631 if !indent.needs_block_end {
2632 self.indent = indent.indent;
2633 self.indents.pop();
2634 }
2635 }
2636 }
2637
2638 if self.indent < col as isize {
2639 self.indents.push(Indent {
2640 indent: self.indent,
2641 needs_block_end: true,
2642 });
2643 self.indent = col as isize;
2644 let tokens_parsed = self.tokens_parsed;
2645 match number {
2646 Some(n) => self.insert_token(n - tokens_parsed, Token(Span::empty(mark), tok)),
2647 None => self.tokens.push_back(Token(Span::empty(mark), tok)),
2648 }
2649 }
2650 }
2651
2652 fn unroll_indent(&mut self, col: isize) {
2658 if self.flow_level > 0 {
2659 return;
2660 }
2661 while self.indent > col {
2662 let indent = self.indents.pop().unwrap();
2663 self.indent = indent.indent;
2664 if indent.needs_block_end {
2665 self.tokens
2666 .push_back(Token(Span::empty(self.mark), TokenType::BlockEnd));
2667 }
2668 }
2669 }
2670
2671 fn roll_one_col_indent(&mut self) {
2677 if self.flow_level == 0 && self.indents.last().is_some_and(|x| x.needs_block_end) {
2678 self.indents.push(Indent {
2679 indent: self.indent,
2680 needs_block_end: false,
2681 });
2682 self.indent += 1;
2683 }
2684 }
2685
2686 fn unroll_non_block_indents(&mut self) {
2688 while let Some(indent) = self.indents.last() {
2689 if indent.needs_block_end {
2690 break;
2691 }
2692 self.indent = indent.indent;
2693 self.indents.pop();
2694 }
2695 }
2696
2697 fn save_simple_key(&mut self) {
2699 if self.simple_key_allowed {
2700 let required = self.flow_level == 0
2701 && self.indent == (self.mark.col as isize)
2702 && self.indents.last().unwrap().needs_block_end;
2703 let mut sk = SimpleKey::new(self.mark);
2704 sk.possible = true;
2705 sk.required = required;
2706 sk.token_number = self.tokens_parsed + self.tokens.len();
2707
2708 self.simple_keys.pop();
2709 self.simple_keys.push(sk);
2710 }
2711 }
2712
2713 fn remove_simple_key(&mut self) -> ScanResult {
2714 let last = self.simple_keys.last_mut().unwrap();
2715 if last.possible && last.required {
2716 return Err(ScanError::new_str(self.mark, "simple key expected"));
2717 }
2718
2719 last.possible = false;
2720 Ok(())
2721 }
2722
2723 fn is_within_block(&self) -> bool {
2725 !self.indents.is_empty()
2726 }
2727
2728 fn end_implicit_mapping(&mut self, mark: Marker) {
2734 if let Some(implicit_mapping) = self.implicit_flow_mapping_states.last_mut() {
2735 if *implicit_mapping == ImplicitMappingState::Inside {
2736 self.flow_mapping_started = false;
2737 *implicit_mapping = ImplicitMappingState::Possible;
2738 self.tokens
2739 .push_back(Token(Span::empty(mark), TokenType::FlowMappingEnd));
2740 }
2741 }
2742 }
2743}
2744
2745#[derive(PartialEq, Eq)]
2749pub enum Chomping {
2750 Strip,
2752 Clip,
2754 Keep,
2756}
2757
2758#[cfg(test)]
2759mod test {
2760 #[test]
2761 fn test_is_anchor_char() {
2762 use super::is_anchor_char;
2763 assert!(is_anchor_char('x'));
2764 }
2765}