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,
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 BlockSequenceStart,
210 BlockMappingStart,
214 BlockEnd,
216 FlowSequenceStart,
218 FlowSequenceEnd,
220 FlowMappingStart,
222 FlowMappingEnd,
224 BlockEntry,
226 FlowEntry,
228 Key,
230 Value,
232 Alias(Cow<'input, str>),
234 Anchor(Cow<'input, str>),
236 Tag(
238 String,
240 String,
242 ),
243 Scalar(ScalarStyle, Cow<'input, str>),
245}
246
247#[derive(Clone, PartialEq, Debug, Eq)]
249pub struct Token<'input>(pub Span, pub TokenType<'input>);
250
251#[derive(Clone, PartialEq, Debug, Eq)]
286struct SimpleKey {
287 possible: bool,
300 required: bool,
308 token_number: usize,
314 mark: Marker,
316}
317
318impl SimpleKey {
319 fn new(mark: Marker) -> SimpleKey {
321 SimpleKey {
322 possible: false,
323 required: false,
324 token_number: 0,
325 mark,
326 }
327 }
328}
329
330#[derive(Clone, Debug, Default)]
332struct Indent {
333 indent: isize,
335 needs_block_end: bool,
353}
354
355#[derive(Debug, PartialEq)]
377enum ImplicitMappingState {
378 Possible,
383 Inside,
387}
388
389#[derive(Debug)]
399#[allow(clippy::struct_excessive_bools)]
400pub struct Scanner<'input, T> {
401 input: T,
405 mark: Marker,
407 tokens: VecDeque<Token<'input>>,
414 error: Option<ScanError>,
416
417 stream_start_produced: bool,
419 stream_end_produced: bool,
421 adjacent_value_allowed_at: usize,
424 simple_key_allowed: bool,
428 simple_keys: Vec<SimpleKey>,
433 indent: isize,
435 indents: Vec<Indent>,
437 flow_level: u8,
439 tokens_parsed: usize,
443 token_available: bool,
445 leading_whitespace: bool,
447 flow_mapping_started: bool,
454 implicit_flow_mapping_states: Vec<ImplicitMappingState>,
467 buf_leading_break: String,
468 buf_trailing_breaks: String,
469 buf_whitespaces: String,
470}
471
472impl<'input, T: Input> Iterator for Scanner<'input, T> {
473 type Item = Token<'input>;
474
475 fn next(&mut self) -> Option<Self::Item> {
476 if self.error.is_some() {
477 return None;
478 }
479 match self.next_token() {
480 Ok(Some(tok)) => {
481 debug_print!(
482 " \x1B[;32m\u{21B3} {:?} \x1B[;36m{:?}\x1B[;m",
483 tok.1,
484 tok.0
485 );
486 Some(tok)
487 }
488 Ok(tok) => tok,
489 Err(e) => {
490 self.error = Some(e);
491 None
492 }
493 }
494 }
495}
496
497pub type ScanResult = Result<(), ScanError>;
499
500impl<'input, T: Input> Scanner<'input, T> {
501 pub fn new(input: T) -> Self {
503 Scanner {
504 input,
505 mark: Marker::new(0, 1, 0),
506 tokens: VecDeque::new(),
507 error: None,
508
509 stream_start_produced: false,
510 stream_end_produced: false,
511 adjacent_value_allowed_at: 0,
512 simple_key_allowed: true,
513 simple_keys: Vec::new(),
514 indent: -1,
515 indents: Vec::new(),
516 flow_level: 0,
517 tokens_parsed: 0,
518 token_available: false,
519 leading_whitespace: true,
520 flow_mapping_started: false,
521 implicit_flow_mapping_states: vec![],
522
523 buf_leading_break: String::new(),
524 buf_trailing_breaks: String::new(),
525 buf_whitespaces: String::new(),
526 }
527 }
528
529 #[inline]
534 pub fn get_error(&self) -> Option<ScanError> {
535 self.error.clone()
536 }
537
538 #[inline]
540 fn skip_blank(&mut self) {
541 self.input.skip();
542
543 self.mark.index += 1;
544 self.mark.col += 1;
545 }
546
547 #[inline]
549 fn skip_non_blank(&mut self) {
550 self.input.skip();
551
552 self.mark.index += 1;
553 self.mark.col += 1;
554 self.leading_whitespace = false;
555 }
556
557 #[inline]
559 fn skip_n_non_blank(&mut self, count: usize) {
560 self.input.skip_n(count);
561
562 self.mark.index += count;
563 self.mark.col += count;
564 self.leading_whitespace = false;
565 }
566
567 #[inline]
569 fn skip_nl(&mut self) {
570 self.input.skip();
571
572 self.mark.index += 1;
573 self.mark.col = 0;
574 self.mark.line += 1;
575 self.leading_whitespace = true;
576 }
577
578 #[inline]
580 fn skip_linebreak(&mut self) {
581 if self.input.next_2_are('\r', '\n') {
582 self.skip_blank();
585 self.skip_nl();
586 } else if self.input.next_is_break() {
587 self.skip_nl();
588 }
589 }
590
591 #[inline]
593 pub fn stream_started(&self) -> bool {
594 self.stream_start_produced
595 }
596
597 #[inline]
599 pub fn stream_ended(&self) -> bool {
600 self.stream_end_produced
601 }
602
603 #[inline]
605 pub fn mark(&self) -> Marker {
606 self.mark
607 }
608
609 #[inline]
616 fn read_break(&mut self, s: &mut String) {
617 self.skip_break();
618 s.push('\n');
619 }
620
621 #[inline]
626 fn skip_break(&mut self) {
627 let c = self.input.peek();
628 let nc = self.input.peek_nth(1);
629 debug_assert!(is_break(c));
630 if c == '\r' && nc == '\n' {
631 self.skip_blank();
632 }
633 self.skip_nl();
634 }
635
636 fn insert_token(&mut self, pos: usize, tok: Token<'input>) {
638 let old_len = self.tokens.len();
639 assert!(pos <= old_len);
640 self.tokens.insert(pos, tok);
641 }
642
643 fn allow_simple_key(&mut self) {
644 self.simple_key_allowed = true;
645 }
646
647 fn disallow_simple_key(&mut self) {
648 self.simple_key_allowed = false;
649 }
650
651 pub fn fetch_next_token(&mut self) -> ScanResult {
656 self.input.lookahead(1);
657
658 if !self.stream_start_produced {
659 self.fetch_stream_start();
660 return Ok(());
661 }
662 self.skip_to_next_token()?;
663
664 debug_print!(
665 " \x1B[38;5;244m\u{2192} fetch_next_token after whitespace {:?} {:?}\x1B[m",
666 self.mark,
667 self.input.peek()
668 );
669
670 self.stale_simple_keys()?;
671
672 let mark = self.mark;
673 self.unroll_indent(mark.col as isize);
674
675 self.input.lookahead(4);
676
677 if self.input.next_is_z() {
678 self.fetch_stream_end()?;
679 return Ok(());
680 }
681
682 if self.mark.col == 0 {
683 if self.input.next_char_is('%') {
684 return self.fetch_directive();
685 } else if self.input.next_is_document_start() {
686 return self.fetch_document_indicator(TokenType::DocumentStart);
687 } else if self.input.next_is_document_end() {
688 self.fetch_document_indicator(TokenType::DocumentEnd)?;
689 self.skip_ws_to_eol(SkipTabs::Yes)?;
690 if !self.input.next_is_breakz() {
691 return Err(ScanError::new_str(
692 self.mark,
693 "invalid content after document end marker",
694 ));
695 }
696 return Ok(());
697 }
698 }
699
700 if (self.mark.col as isize) < self.indent {
701 return Err(ScanError::new_str(self.mark, "invalid indentation"));
702 }
703
704 let c = self.input.peek();
705 let nc = self.input.peek_nth(1);
706 match c {
707 '[' => self.fetch_flow_collection_start(TokenType::FlowSequenceStart),
708 '{' => self.fetch_flow_collection_start(TokenType::FlowMappingStart),
709 ']' => self.fetch_flow_collection_end(TokenType::FlowSequenceEnd),
710 '}' => self.fetch_flow_collection_end(TokenType::FlowMappingEnd),
711 ',' => self.fetch_flow_entry(),
712 '-' if is_blank_or_breakz(nc) => self.fetch_block_entry(),
713 '?' if is_blank_or_breakz(nc) => self.fetch_key(),
714 ':' if is_blank_or_breakz(nc) => self.fetch_value(),
715 ':' if self.flow_level > 0
716 && (is_flow(nc) || self.mark.index == self.adjacent_value_allowed_at) =>
717 {
718 self.fetch_flow_value()
719 }
720 '*' => self.fetch_anchor(true),
722 '&' => self.fetch_anchor(false),
724 '!' => self.fetch_tag(),
725 '|' if self.flow_level == 0 => self.fetch_block_scalar(true),
727 '>' if self.flow_level == 0 => self.fetch_block_scalar(false),
729 '\'' => self.fetch_flow_scalar(true),
730 '"' => self.fetch_flow_scalar(false),
731 '-' if !is_blank_or_breakz(nc) => self.fetch_plain_scalar(),
733 ':' | '?' if !is_blank_or_breakz(nc) && self.flow_level == 0 => {
734 self.fetch_plain_scalar()
735 }
736 '%' | '@' | '`' => Err(ScanError::new(
737 self.mark,
738 format!("unexpected character: `{c}'"),
739 )),
740 _ => self.fetch_plain_scalar(),
741 }
742 }
743
744 pub fn next_token(&mut self) -> Result<Option<Token<'input>>, ScanError> {
748 if self.stream_end_produced {
749 return Ok(None);
750 }
751
752 if !self.token_available {
753 self.fetch_more_tokens()?;
754 }
755 let Some(t) = self.tokens.pop_front() else {
756 return Err(ScanError::new_str(
757 self.mark,
758 "did not find expected next token",
759 ));
760 };
761 self.token_available = false;
762 self.tokens_parsed += 1;
763
764 if let TokenType::StreamEnd = t.1 {
765 self.stream_end_produced = true;
766 }
767 Ok(Some(t))
768 }
769
770 pub fn fetch_more_tokens(&mut self) -> ScanResult {
774 let mut need_more;
775 loop {
776 if self.tokens.is_empty() {
777 need_more = true;
778 } else {
779 need_more = false;
780 self.stale_simple_keys()?;
782 for sk in &self.simple_keys {
784 if sk.possible && sk.token_number == self.tokens_parsed {
785 need_more = true;
786 break;
787 }
788 }
789 }
790
791 if !need_more {
792 break;
793 }
794 self.fetch_next_token()?;
795 }
796 self.token_available = true;
797
798 Ok(())
799 }
800
801 fn stale_simple_keys(&mut self) -> ScanResult {
809 for sk in &mut self.simple_keys {
810 if sk.possible
811 && self.flow_level == 0
813 && (sk.mark.line < self.mark.line || sk.mark.index + 1024 < self.mark.index)
814 {
815 if sk.required {
816 return Err(ScanError::new_str(self.mark, "simple key expect ':'"));
817 }
818 sk.possible = false;
819 }
820 }
821 Ok(())
822 }
823
824 fn skip_to_next_token(&mut self) -> ScanResult {
830 loop {
831 match self.input.look_ch() {
833 '\t' if self.is_within_block()
840 && self.leading_whitespace
841 && (self.mark.col as isize) < self.indent =>
842 {
843 self.skip_ws_to_eol(SkipTabs::Yes)?;
844 if !self.input.next_is_breakz() {
846 return Err(ScanError::new_str(
847 self.mark,
848 "tabs disallowed within this context (block indentation)",
849 ));
850 }
851 }
852 '\t' | ' ' => self.skip_blank(),
853 '\n' | '\r' => {
854 self.input.lookahead(2);
855 self.skip_linebreak();
856 if self.flow_level == 0 {
857 self.allow_simple_key();
858 }
859 }
860 '#' => {
861 let comment_length = self.input.skip_while_non_breakz();
862 self.mark.index += comment_length;
863 self.mark.col += comment_length;
864 }
865 _ => break,
866 }
867 }
868 Ok(())
869 }
870
871 fn skip_yaml_whitespace(&mut self) -> ScanResult {
876 let mut need_whitespace = true;
877 loop {
878 match self.input.look_ch() {
879 ' ' => {
880 self.skip_blank();
881
882 need_whitespace = false;
883 }
884 '\n' | '\r' => {
885 self.input.lookahead(2);
886 self.skip_linebreak();
887 if self.flow_level == 0 {
888 self.allow_simple_key();
889 }
890 need_whitespace = false;
891 }
892 '#' => {
893 let comment_length = self.input.skip_while_non_breakz();
894 self.mark.index += comment_length;
895 self.mark.col += comment_length;
896 }
897 _ => break,
898 }
899 }
900
901 if need_whitespace {
902 Err(ScanError::new_str(self.mark(), "expected whitespace"))
903 } else {
904 Ok(())
905 }
906 }
907
908 fn skip_ws_to_eol(&mut self, skip_tabs: SkipTabs) -> Result<SkipTabs, ScanError> {
909 let (n_bytes, result) = self.input.skip_ws_to_eol(skip_tabs);
910 self.mark.col += n_bytes;
911 self.mark.index += n_bytes;
912 result.map_err(|msg| ScanError::new_str(self.mark, msg))
913 }
914
915 fn fetch_stream_start(&mut self) {
916 let mark = self.mark;
917 self.indent = -1;
918 self.stream_start_produced = true;
919 self.allow_simple_key();
920 self.tokens.push_back(Token(
921 Span::empty(mark),
922 TokenType::StreamStart(TEncoding::Utf8),
923 ));
924 self.simple_keys.push(SimpleKey::new(Marker::new(0, 0, 0)));
925 }
926
927 fn fetch_stream_end(&mut self) -> ScanResult {
928 if self.mark.col != 0 {
930 self.mark.col = 0;
931 self.mark.line += 1;
932 }
933
934 for sk in &mut self.simple_keys {
937 if sk.required && sk.possible {
938 return Err(ScanError::new_str(self.mark, "simple key expected"));
939 }
940 sk.possible = false;
941 }
942
943 self.unroll_indent(-1);
944 self.remove_simple_key()?;
945 self.disallow_simple_key();
946
947 self.tokens
948 .push_back(Token(Span::empty(self.mark), TokenType::StreamEnd));
949 Ok(())
950 }
951
952 fn fetch_directive(&mut self) -> ScanResult {
953 self.unroll_indent(-1);
954 self.remove_simple_key()?;
955
956 self.disallow_simple_key();
957
958 let tok = self.scan_directive()?;
959 self.tokens.push_back(tok);
960
961 Ok(())
962 }
963
964 fn scan_directive(&mut self) -> Result<Token<'input>, ScanError> {
965 let start_mark = self.mark;
966 self.skip_non_blank();
967
968 let name = self.scan_directive_name()?;
969 let tok = match name.as_ref() {
970 "YAML" => self.scan_version_directive_value(&start_mark)?,
971 "TAG" => self.scan_tag_directive_value(&start_mark)?,
972 _ => {
974 let line_len = self.input.skip_while_non_breakz();
976 self.mark.index += line_len;
977 self.mark.col += line_len;
978 Token(
980 Span::new(start_mark, self.mark),
981 TokenType::TagDirective(Cow::default(), Cow::default()),
982 )
983 }
986 };
987
988 self.skip_ws_to_eol(SkipTabs::Yes)?;
989
990 if self.input.next_is_breakz() {
991 self.input.lookahead(2);
992 self.skip_linebreak();
993 Ok(tok)
994 } else {
995 Err(ScanError::new_str(
996 start_mark,
997 "while scanning a directive, did not find expected comment or line break",
998 ))
999 }
1000 }
1001
1002 fn scan_version_directive_value(&mut self, mark: &Marker) -> Result<Token<'input>, ScanError> {
1003 let n_blanks = self.input.skip_while_blank();
1004 self.mark.index += n_blanks;
1005 self.mark.col += n_blanks;
1006
1007 let major = self.scan_version_directive_number(mark)?;
1008
1009 if self.input.peek() != '.' {
1010 return Err(ScanError::new_str(
1011 *mark,
1012 "while scanning a YAML directive, did not find expected digit or '.' character",
1013 ));
1014 }
1015 self.skip_non_blank();
1016
1017 let minor = self.scan_version_directive_number(mark)?;
1018
1019 Ok(Token(
1020 Span::new(*mark, self.mark),
1021 TokenType::VersionDirective(major, minor),
1022 ))
1023 }
1024
1025 fn scan_directive_name(&mut self) -> Result<String, ScanError> {
1026 let start_mark = self.mark;
1027 let mut string = String::new();
1028
1029 let n_chars = self.input.fetch_while_is_alpha(&mut string);
1030 self.mark.index += n_chars;
1031 self.mark.col += n_chars;
1032
1033 if string.is_empty() {
1034 return Err(ScanError::new_str(
1035 start_mark,
1036 "while scanning a directive, could not find expected directive name",
1037 ));
1038 }
1039
1040 if !is_blank_or_breakz(self.input.peek()) {
1041 return Err(ScanError::new_str(
1042 start_mark,
1043 "while scanning a directive, found unexpected non-alphabetical character",
1044 ));
1045 }
1046
1047 Ok(string)
1048 }
1049
1050 fn scan_version_directive_number(&mut self, mark: &Marker) -> Result<u32, ScanError> {
1051 let mut val = 0u32;
1052 let mut length = 0usize;
1053 while let Some(digit) = self.input.look_ch().to_digit(10) {
1054 if length + 1 > 9 {
1055 return Err(ScanError::new_str(
1056 *mark,
1057 "while scanning a YAML directive, found extremely long version number",
1058 ));
1059 }
1060 length += 1;
1061 val = val * 10 + digit;
1062 self.skip_non_blank();
1063 }
1064
1065 if length == 0 {
1066 return Err(ScanError::new_str(
1067 *mark,
1068 "while scanning a YAML directive, did not find expected version number",
1069 ));
1070 }
1071
1072 Ok(val)
1073 }
1074
1075 fn scan_tag_directive_value(&mut self, mark: &Marker) -> Result<Token<'input>, ScanError> {
1076 let n_blanks = self.input.skip_while_blank();
1077 self.mark.index += n_blanks;
1078 self.mark.col += n_blanks;
1079
1080 let handle = self.scan_tag_handle(true, mark)?;
1081
1082 let n_blanks = self.input.skip_while_blank();
1083 self.mark.index += n_blanks;
1084 self.mark.col += n_blanks;
1085
1086 let prefix = self.scan_tag_prefix(mark)?;
1087
1088 self.input.lookahead(1);
1089
1090 if self.input.next_is_blank_or_breakz() {
1091 Ok(Token(
1092 Span::new(*mark, self.mark),
1093 TokenType::TagDirective(handle.into(), prefix.into()),
1094 ))
1095 } else {
1096 Err(ScanError::new_str(
1097 *mark,
1098 "while scanning TAG, did not find expected whitespace or line break",
1099 ))
1100 }
1101 }
1102
1103 fn fetch_tag(&mut self) -> ScanResult {
1104 self.save_simple_key();
1105 self.disallow_simple_key();
1106
1107 let tok = self.scan_tag()?;
1108 self.tokens.push_back(tok);
1109 Ok(())
1110 }
1111
1112 fn scan_tag(&mut self) -> Result<Token<'input>, ScanError> {
1113 let start_mark = self.mark;
1114 let mut handle = String::new();
1115 let mut suffix;
1116
1117 self.input.lookahead(2);
1119
1120 if self.input.nth_char_is(1, '<') {
1121 suffix = self.scan_verbatim_tag(&start_mark)?;
1122 } else {
1123 handle = self.scan_tag_handle(false, &start_mark)?;
1125 if handle.len() >= 2 && handle.starts_with('!') && handle.ends_with('!') {
1127 let is_secondary_handle = handle == "!!";
1129 suffix =
1130 self.scan_tag_shorthand_suffix(false, is_secondary_handle, "", &start_mark)?;
1131 } else {
1132 suffix = self.scan_tag_shorthand_suffix(false, false, &handle, &start_mark)?;
1133 "!".clone_into(&mut handle);
1134 if suffix.is_empty() {
1137 handle.clear();
1138 "!".clone_into(&mut suffix);
1139 }
1140 }
1141 }
1142
1143 if is_blank_or_breakz(self.input.look_ch())
1144 || (self.flow_level > 0 && self.input.next_is_flow())
1145 {
1146 Ok(Token(
1148 Span::new(start_mark, self.mark),
1149 TokenType::Tag(handle, suffix),
1150 ))
1151 } else {
1152 Err(ScanError::new_str(
1153 start_mark,
1154 "while scanning a tag, did not find expected whitespace or line break",
1155 ))
1156 }
1157 }
1158
1159 fn scan_tag_handle(&mut self, directive: bool, mark: &Marker) -> Result<String, ScanError> {
1160 let mut string = String::new();
1161 if self.input.look_ch() != '!' {
1162 return Err(ScanError::new_str(
1163 *mark,
1164 "while scanning a tag, did not find expected '!'",
1165 ));
1166 }
1167
1168 string.push(self.input.peek());
1169 self.skip_non_blank();
1170
1171 let n_chars = self.input.fetch_while_is_alpha(&mut string);
1172 self.mark.index += n_chars;
1173 self.mark.col += n_chars;
1174
1175 if self.input.peek() == '!' {
1177 string.push(self.input.peek());
1178 self.skip_non_blank();
1179 } else if directive && string != "!" {
1180 return Err(ScanError::new_str(
1184 *mark,
1185 "while parsing a tag directive, did not find expected '!'",
1186 ));
1187 }
1188 Ok(string)
1189 }
1190
1191 fn scan_tag_prefix(&mut self, start_mark: &Marker) -> Result<String, ScanError> {
1197 let mut string = String::new();
1198
1199 if self.input.look_ch() == '!' {
1200 string.push(self.input.peek());
1202 self.skip_non_blank();
1203 } else if !is_tag_char(self.input.peek()) {
1204 return Err(ScanError::new_str(
1206 *start_mark,
1207 "invalid global tag character",
1208 ));
1209 } else if self.input.peek() == '%' {
1210 string.push(self.scan_uri_escapes(start_mark)?);
1212 } else {
1213 string.push(self.input.peek());
1215 self.skip_non_blank();
1216 }
1217
1218 while is_uri_char(self.input.look_ch()) {
1219 if self.input.peek() == '%' {
1220 string.push(self.scan_uri_escapes(start_mark)?);
1221 } else {
1222 string.push(self.input.peek());
1223 self.skip_non_blank();
1224 }
1225 }
1226
1227 Ok(string)
1228 }
1229
1230 fn scan_verbatim_tag(&mut self, start_mark: &Marker) -> Result<String, ScanError> {
1234 self.skip_non_blank();
1236 self.skip_non_blank();
1237
1238 let mut string = String::new();
1239 while is_uri_char(self.input.look_ch()) {
1240 if self.input.peek() == '%' {
1241 string.push(self.scan_uri_escapes(start_mark)?);
1242 } else {
1243 string.push(self.input.peek());
1244 self.skip_non_blank();
1245 }
1246 }
1247
1248 if self.input.peek() != '>' {
1249 return Err(ScanError::new_str(
1250 *start_mark,
1251 "while scanning a verbatim tag, did not find the expected '>'",
1252 ));
1253 }
1254 self.skip_non_blank();
1255
1256 Ok(string)
1257 }
1258
1259 fn scan_tag_shorthand_suffix(
1260 &mut self,
1261 _directive: bool,
1262 _is_secondary: bool,
1263 head: &str,
1264 mark: &Marker,
1265 ) -> Result<String, ScanError> {
1266 let mut length = head.len();
1267 let mut string = String::new();
1268
1269 if length > 1 {
1272 string.extend(head.chars().skip(1));
1273 }
1274
1275 while is_tag_char(self.input.look_ch()) {
1276 if self.input.peek() == '%' {
1278 string.push(self.scan_uri_escapes(mark)?);
1279 } else {
1280 string.push(self.input.peek());
1281 self.skip_non_blank();
1282 }
1283
1284 length += 1;
1285 }
1286
1287 if length == 0 {
1288 return Err(ScanError::new_str(
1289 *mark,
1290 "while parsing a tag, did not find expected tag URI",
1291 ));
1292 }
1293
1294 Ok(string)
1295 }
1296
1297 fn scan_uri_escapes(&mut self, mark: &Marker) -> Result<char, ScanError> {
1298 let mut width = 0usize;
1299 let mut code = 0u32;
1300 loop {
1301 self.input.lookahead(3);
1302
1303 let c = self.input.peek_nth(1);
1304 let nc = self.input.peek_nth(2);
1305
1306 if !(self.input.peek() == '%' && is_hex(c) && is_hex(nc)) {
1307 return Err(ScanError::new_str(
1308 *mark,
1309 "while parsing a tag, found an invalid escape sequence",
1310 ));
1311 }
1312
1313 let byte = (as_hex(c) << 4) + as_hex(nc);
1314 if width == 0 {
1315 width = match byte {
1316 _ if byte & 0x80 == 0x00 => 1,
1317 _ if byte & 0xE0 == 0xC0 => 2,
1318 _ if byte & 0xF0 == 0xE0 => 3,
1319 _ if byte & 0xF8 == 0xF0 => 4,
1320 _ => {
1321 return Err(ScanError::new_str(
1322 *mark,
1323 "while parsing a tag, found an incorrect leading UTF-8 byte",
1324 ));
1325 }
1326 };
1327 code = byte;
1328 } else {
1329 if byte & 0xc0 != 0x80 {
1330 return Err(ScanError::new_str(
1331 *mark,
1332 "while parsing a tag, found an incorrect trailing UTF-8 byte",
1333 ));
1334 }
1335 code = (code << 8) + byte;
1336 }
1337
1338 self.skip_n_non_blank(3);
1339
1340 width -= 1;
1341 if width == 0 {
1342 break;
1343 }
1344 }
1345
1346 match char::from_u32(code) {
1347 Some(ch) => Ok(ch),
1348 None => Err(ScanError::new_str(
1349 *mark,
1350 "while parsing a tag, found an invalid UTF-8 codepoint",
1351 )),
1352 }
1353 }
1354
1355 fn fetch_anchor(&mut self, alias: bool) -> ScanResult {
1356 self.save_simple_key();
1357 self.disallow_simple_key();
1358
1359 let tok = self.scan_anchor(alias)?;
1360
1361 self.tokens.push_back(tok);
1362
1363 Ok(())
1364 }
1365
1366 fn scan_anchor(&mut self, alias: bool) -> Result<Token<'input>, ScanError> {
1367 let mut string = String::new();
1368 let start_mark = self.mark;
1369
1370 self.skip_non_blank();
1371 while is_anchor_char(self.input.look_ch()) {
1372 string.push(self.input.peek());
1373 self.skip_non_blank();
1374 }
1375
1376 if string.is_empty() {
1377 return Err(ScanError::new_str(
1378 start_mark,
1379 "while scanning an anchor or alias, did not find expected alphabetic or numeric character",
1380 ));
1381 }
1382
1383 let tok = if alias {
1384 TokenType::Alias(string.into())
1385 } else {
1386 TokenType::Anchor(string.into())
1387 };
1388 Ok(Token(Span::new(start_mark, self.mark), tok))
1389 }
1390
1391 fn fetch_flow_collection_start(&mut self, tok: TokenType<'input>) -> ScanResult {
1392 self.save_simple_key();
1394
1395 self.roll_one_col_indent();
1396 self.increase_flow_level()?;
1397
1398 self.allow_simple_key();
1399
1400 let start_mark = self.mark;
1401 self.skip_non_blank();
1402
1403 if tok == TokenType::FlowMappingStart {
1404 self.flow_mapping_started = true;
1405 } else {
1406 self.implicit_flow_mapping_states
1407 .push(ImplicitMappingState::Possible);
1408 }
1409
1410 self.skip_ws_to_eol(SkipTabs::Yes)?;
1411
1412 self.tokens
1413 .push_back(Token(Span::new(start_mark, self.mark), tok));
1414 Ok(())
1415 }
1416
1417 fn fetch_flow_collection_end(&mut self, tok: TokenType<'input>) -> ScanResult {
1418 self.remove_simple_key()?;
1419 self.decrease_flow_level();
1420
1421 self.disallow_simple_key();
1422
1423 if matches!(tok, TokenType::FlowSequenceEnd) {
1424 self.end_implicit_mapping(self.mark);
1425 self.implicit_flow_mapping_states.pop();
1427 }
1428
1429 let start_mark = self.mark;
1430 self.skip_non_blank();
1431 self.skip_ws_to_eol(SkipTabs::Yes)?;
1432
1433 if self.flow_level > 0 {
1439 self.adjacent_value_allowed_at = self.mark.index;
1440 }
1441
1442 self.tokens
1443 .push_back(Token(Span::new(start_mark, self.mark), tok));
1444 Ok(())
1445 }
1446
1447 fn fetch_flow_entry(&mut self) -> ScanResult {
1449 self.remove_simple_key()?;
1450 self.allow_simple_key();
1451
1452 self.end_implicit_mapping(self.mark);
1453
1454 let start_mark = self.mark;
1455 self.skip_non_blank();
1456 self.skip_ws_to_eol(SkipTabs::Yes)?;
1457
1458 self.tokens.push_back(Token(
1459 Span::new(start_mark, self.mark),
1460 TokenType::FlowEntry,
1461 ));
1462 Ok(())
1463 }
1464
1465 fn increase_flow_level(&mut self) -> ScanResult {
1466 self.simple_keys.push(SimpleKey::new(Marker::new(0, 0, 0)));
1467 self.flow_level = self
1468 .flow_level
1469 .checked_add(1)
1470 .ok_or_else(|| ScanError::new_str(self.mark, "recursion limit exceeded"))?;
1471 Ok(())
1472 }
1473
1474 fn decrease_flow_level(&mut self) {
1475 if self.flow_level > 0 {
1476 self.flow_level -= 1;
1477 self.simple_keys.pop().unwrap();
1478 }
1479 }
1480
1481 fn fetch_block_entry(&mut self) -> ScanResult {
1487 if self.flow_level > 0 {
1488 return Err(ScanError::new_str(
1490 self.mark,
1491 r#""-" is only valid inside a block"#,
1492 ));
1493 }
1494 if !self.simple_key_allowed {
1496 return Err(ScanError::new_str(
1497 self.mark,
1498 "block sequence entries are not allowed in this context",
1499 ));
1500 }
1501
1502 if let Some(Token(span, TokenType::Anchor(..) | TokenType::Tag(..))) = self.tokens.back() {
1504 if self.mark.col == 0 && span.start.col == 0 && self.indent > -1 {
1505 return Err(ScanError::new_str(
1506 span.start,
1507 "invalid indentation for anchor",
1508 ));
1509 }
1510 }
1511
1512 let mark = self.mark;
1514 self.skip_non_blank();
1515
1516 self.roll_indent(mark.col, None, TokenType::BlockSequenceStart, mark);
1518 let found_tabs = self.skip_ws_to_eol(SkipTabs::Yes)?.found_tabs();
1519 self.input.lookahead(2);
1520 if found_tabs && self.input.next_char_is('-') && is_blank_or_breakz(self.input.peek_nth(1))
1521 {
1522 return Err(ScanError::new_str(
1523 self.mark,
1524 "'-' must be followed by a valid YAML whitespace",
1525 ));
1526 }
1527
1528 self.skip_ws_to_eol(SkipTabs::No)?;
1529 self.input.lookahead(1);
1530 if self.input.next_is_break() || self.input.next_is_flow() {
1531 self.roll_one_col_indent();
1532 }
1533
1534 self.remove_simple_key()?;
1535 self.allow_simple_key();
1536
1537 self.tokens
1538 .push_back(Token(Span::empty(self.mark), TokenType::BlockEntry));
1539
1540 Ok(())
1541 }
1542
1543 fn fetch_document_indicator(&mut self, t: TokenType<'input>) -> ScanResult {
1544 self.unroll_indent(-1);
1545 self.remove_simple_key()?;
1546 self.disallow_simple_key();
1547
1548 let mark = self.mark;
1549
1550 self.skip_n_non_blank(3);
1551
1552 self.tokens.push_back(Token(Span::new(mark, self.mark), t));
1553 Ok(())
1554 }
1555
1556 fn fetch_block_scalar(&mut self, literal: bool) -> ScanResult {
1557 self.save_simple_key();
1558 self.allow_simple_key();
1559 let tok = self.scan_block_scalar(literal)?;
1560
1561 self.tokens.push_back(tok);
1562 Ok(())
1563 }
1564
1565 #[allow(clippy::too_many_lines)]
1566 fn scan_block_scalar(&mut self, literal: bool) -> Result<Token<'input>, ScanError> {
1567 let start_mark = self.mark;
1568 let mut chomping = Chomping::Clip;
1569 let mut increment: usize = 0;
1570 let mut indent: usize = 0;
1571 let mut trailing_blank: bool;
1572 let mut leading_blank: bool = false;
1573 let style = if literal {
1574 ScalarStyle::Literal
1575 } else {
1576 ScalarStyle::Folded
1577 };
1578
1579 let mut string = String::new();
1580 let mut leading_break = String::new();
1581 let mut trailing_breaks = String::new();
1582 let mut chomping_break = String::new();
1583
1584 self.skip_non_blank();
1586 self.unroll_non_block_indents();
1587
1588 if self.input.look_ch() == '+' || self.input.peek() == '-' {
1589 if self.input.peek() == '+' {
1590 chomping = Chomping::Keep;
1591 } else {
1592 chomping = Chomping::Strip;
1593 }
1594 self.skip_non_blank();
1595 self.input.lookahead(1);
1596 if self.input.next_is_digit() {
1597 if self.input.peek() == '0' {
1598 return Err(ScanError::new_str(
1599 start_mark,
1600 "while scanning a block scalar, found an indentation indicator equal to 0",
1601 ));
1602 }
1603 increment = (self.input.peek() as usize) - ('0' as usize);
1604 self.skip_non_blank();
1605 }
1606 } else if self.input.next_is_digit() {
1607 if self.input.peek() == '0' {
1608 return Err(ScanError::new_str(
1609 start_mark,
1610 "while scanning a block scalar, found an indentation indicator equal to 0",
1611 ));
1612 }
1613
1614 increment = (self.input.peek() as usize) - ('0' as usize);
1615 self.skip_non_blank();
1616 self.input.lookahead(1);
1617 if self.input.peek() == '+' || self.input.peek() == '-' {
1618 if self.input.peek() == '+' {
1619 chomping = Chomping::Keep;
1620 } else {
1621 chomping = Chomping::Strip;
1622 }
1623 self.skip_non_blank();
1624 }
1625 }
1626
1627 self.skip_ws_to_eol(SkipTabs::Yes)?;
1628
1629 self.input.lookahead(1);
1631 if !self.input.next_is_breakz() {
1632 return Err(ScanError::new_str(
1633 start_mark,
1634 "while scanning a block scalar, did not find expected comment or line break",
1635 ));
1636 }
1637
1638 if self.input.next_is_break() {
1639 self.input.lookahead(2);
1640 self.read_break(&mut chomping_break);
1641 }
1642
1643 if self.input.look_ch() == '\t' {
1644 return Err(ScanError::new_str(
1645 start_mark,
1646 "a block scalar content cannot start with a tab",
1647 ));
1648 }
1649
1650 if increment > 0 {
1651 indent = if self.indent >= 0 {
1652 (self.indent + increment as isize) as usize
1653 } else {
1654 increment
1655 }
1656 }
1657
1658 if indent == 0 {
1660 self.skip_block_scalar_first_line_indent(&mut indent, &mut trailing_breaks);
1661 } else {
1662 self.skip_block_scalar_indent(indent, &mut trailing_breaks);
1663 }
1664
1665 if self.input.next_is_z() {
1670 let contents = match chomping {
1671 Chomping::Strip => String::new(),
1673 _ if self.mark.line == start_mark.line() => String::new(),
1675 Chomping::Clip => chomping_break,
1678 Chomping::Keep if trailing_breaks.is_empty() => chomping_break,
1681 Chomping::Keep => trailing_breaks,
1683 };
1684 return Ok(Token(
1685 Span::new(start_mark, self.mark),
1686 TokenType::Scalar(style, contents.into()),
1687 ));
1688 }
1689
1690 if self.mark.col < indent && (self.mark.col as isize) > self.indent {
1691 return Err(ScanError::new_str(
1692 self.mark,
1693 "wrongly indented line in block scalar",
1694 ));
1695 }
1696
1697 let mut line_buffer = String::with_capacity(100);
1698 let start_mark = self.mark;
1699 while self.mark.col == indent && !self.input.next_is_z() {
1700 if indent == 0 {
1701 self.input.lookahead(4);
1702 if self.input.next_is_document_end() {
1703 break;
1704 }
1705 }
1706
1707 trailing_blank = self.input.next_is_blank();
1709 if !literal && !leading_break.is_empty() && !leading_blank && !trailing_blank {
1710 string.push_str(&trailing_breaks);
1711 if trailing_breaks.is_empty() {
1712 string.push(' ');
1713 }
1714 } else {
1715 string.push_str(&leading_break);
1716 string.push_str(&trailing_breaks);
1717 }
1718
1719 leading_break.clear();
1720 trailing_breaks.clear();
1721
1722 leading_blank = self.input.next_is_blank();
1723
1724 self.scan_block_scalar_content_line(&mut string, &mut line_buffer);
1725
1726 self.input.lookahead(2);
1728 if self.input.next_is_z() {
1729 break;
1730 }
1731
1732 self.read_break(&mut leading_break);
1733
1734 self.skip_block_scalar_indent(indent, &mut trailing_breaks);
1736 }
1737
1738 if chomping != Chomping::Strip {
1740 string.push_str(&leading_break);
1741 if self.input.next_is_z() && self.mark.col >= indent.max(1) {
1745 string.push('\n');
1746 }
1747 }
1748
1749 if chomping == Chomping::Keep {
1750 string.push_str(&trailing_breaks);
1751 }
1752
1753 Ok(Token(
1754 Span::new(start_mark, self.mark),
1755 TokenType::Scalar(style, string.into()),
1756 ))
1757 }
1758
1759 fn scan_block_scalar_content_line(&mut self, string: &mut String, line_buffer: &mut String) {
1769 while !self.input.buf_is_empty() && !self.input.next_is_breakz() {
1771 string.push(self.input.peek());
1772 self.skip_blank();
1778 }
1779
1780 if self.input.buf_is_empty() {
1783 while let Some(c) = self.input.raw_read_non_breakz_ch() {
1789 line_buffer.push(c);
1790 }
1791
1792 let n_chars = line_buffer.chars().count();
1794 self.mark.col += n_chars;
1795 self.mark.index += n_chars;
1796
1797 string.reserve(line_buffer.len());
1799 string.push_str(line_buffer);
1800 line_buffer.clear();
1802 }
1803 }
1804
1805 fn skip_block_scalar_indent(&mut self, indent: usize, breaks: &mut String) {
1807 loop {
1808 if indent < self.input.bufmaxlen() - 2 {
1810 self.input.lookahead(self.input.bufmaxlen());
1811 while self.mark.col < indent && self.input.peek() == ' ' {
1812 self.skip_blank();
1813 }
1814 } else {
1815 loop {
1816 self.input.lookahead(self.input.bufmaxlen());
1817 while !self.input.buf_is_empty()
1818 && self.mark.col < indent
1819 && self.input.peek() == ' '
1820 {
1821 self.skip_blank();
1822 }
1823 if self.mark.col == indent
1827 || (!self.input.buf_is_empty() && self.input.peek() != ' ')
1828 {
1829 break;
1830 }
1831 }
1832 self.input.lookahead(2);
1833 }
1834
1835 if self.input.next_is_break() {
1837 self.read_break(breaks);
1838 } else {
1839 break;
1841 }
1842 }
1843 }
1844
1845 fn skip_block_scalar_first_line_indent(&mut self, indent: &mut usize, breaks: &mut String) {
1850 let mut max_indent = 0;
1851 loop {
1852 while self.input.look_ch() == ' ' {
1854 self.skip_blank();
1855 }
1856
1857 if self.mark.col > max_indent {
1858 max_indent = self.mark.col;
1859 }
1860
1861 if self.input.next_is_break() {
1862 self.input.lookahead(2);
1864 self.read_break(breaks);
1865 } else {
1866 break;
1868 }
1869 }
1870
1871 *indent = max_indent.max((self.indent + 1) as usize);
1880 if self.indent > 0 {
1881 *indent = (*indent).max(1);
1882 }
1883 }
1884
1885 fn fetch_flow_scalar(&mut self, single: bool) -> ScanResult {
1886 self.save_simple_key();
1887 self.disallow_simple_key();
1888
1889 let tok = self.scan_flow_scalar(single)?;
1890
1891 self.skip_to_next_token()?;
1894 self.adjacent_value_allowed_at = self.mark.index;
1895
1896 self.tokens.push_back(tok);
1897 Ok(())
1898 }
1899
1900 #[allow(clippy::too_many_lines)]
1901 fn scan_flow_scalar(&mut self, single: bool) -> Result<Token<'input>, ScanError> {
1902 let start_mark = self.mark;
1903
1904 let mut string = String::new();
1905 let mut leading_break = String::new();
1906 let mut trailing_breaks = String::new();
1907 let mut whitespaces = String::new();
1908 let mut leading_blanks;
1909
1910 self.skip_non_blank();
1912
1913 loop {
1914 self.input.lookahead(4);
1916
1917 if self.mark.col == 0 && self.input.next_is_document_indicator() {
1918 return Err(ScanError::new_str(
1919 start_mark,
1920 "while scanning a quoted scalar, found unexpected document indicator",
1921 ));
1922 }
1923
1924 if self.input.next_is_z() {
1925 return Err(ScanError::new_str(
1926 start_mark,
1927 "while scanning a quoted scalar, found unexpected end of stream",
1928 ));
1929 }
1930
1931 if (self.mark.col as isize) < self.indent {
1932 return Err(ScanError::new_str(
1933 start_mark,
1934 "invalid indentation in quoted scalar",
1935 ));
1936 }
1937
1938 leading_blanks = false;
1939 self.consume_flow_scalar_non_whitespace_chars(
1940 single,
1941 &mut string,
1942 &mut leading_blanks,
1943 &start_mark,
1944 )?;
1945
1946 match self.input.look_ch() {
1947 '\'' if single => break,
1948 '"' if !single => break,
1949 _ => {}
1950 }
1951
1952 while self.input.next_is_blank() || self.input.next_is_break() {
1954 if self.input.next_is_blank() {
1955 if leading_blanks {
1957 if self.input.peek() == '\t' && (self.mark.col as isize) < self.indent {
1958 return Err(ScanError::new_str(
1959 self.mark,
1960 "tab cannot be used as indentation",
1961 ));
1962 }
1963 self.skip_blank();
1964 } else {
1965 whitespaces.push(self.input.peek());
1966 self.skip_blank();
1967 }
1968 } else {
1969 self.input.lookahead(2);
1970 if leading_blanks {
1972 self.read_break(&mut trailing_breaks);
1973 } else {
1974 whitespaces.clear();
1975 self.read_break(&mut leading_break);
1976 leading_blanks = true;
1977 }
1978 }
1979 self.input.lookahead(1);
1980 }
1981
1982 if leading_blanks {
1984 if leading_break.is_empty() {
1985 string.push_str(&leading_break);
1986 string.push_str(&trailing_breaks);
1987 trailing_breaks.clear();
1988 leading_break.clear();
1989 } else {
1990 if trailing_breaks.is_empty() {
1991 string.push(' ');
1992 } else {
1993 string.push_str(&trailing_breaks);
1994 trailing_breaks.clear();
1995 }
1996 leading_break.clear();
1997 }
1998 } else {
1999 string.push_str(&whitespaces);
2000 whitespaces.clear();
2001 }
2002 } self.skip_non_blank();
2006 self.skip_ws_to_eol(SkipTabs::Yes)?;
2008 match self.input.peek() {
2009 ',' | '}' | ']' if self.flow_level > 0 => {}
2011 c if is_breakz(c) => {}
2013 ':' if self.flow_level == 0 && start_mark.line == self.mark.line => {}
2016 ':' if self.flow_level > 0 => {}
2018 _ => {
2019 return Err(ScanError::new_str(
2020 self.mark,
2021 "invalid trailing content after double-quoted scalar",
2022 ));
2023 }
2024 }
2025
2026 let style = if single {
2027 ScalarStyle::SingleQuoted
2028 } else {
2029 ScalarStyle::DoubleQuoted
2030 };
2031 Ok(Token(
2032 Span::new(start_mark, self.mark),
2033 TokenType::Scalar(style, string.into()),
2034 ))
2035 }
2036
2037 fn consume_flow_scalar_non_whitespace_chars(
2046 &mut self,
2047 single: bool,
2048 string: &mut String,
2049 leading_blanks: &mut bool,
2050 start_mark: &Marker,
2051 ) -> Result<(), ScanError> {
2052 self.input.lookahead(2);
2053 while !is_blank_or_breakz(self.input.peek()) {
2054 match self.input.peek() {
2055 '\'' if self.input.peek_nth(1) == '\'' && single => {
2057 string.push('\'');
2058 self.skip_n_non_blank(2);
2059 }
2060 '\'' if single => break,
2062 '"' if !single => break,
2063 '\\' if !single && is_break(self.input.peek_nth(1)) => {
2065 self.input.lookahead(3);
2066 self.skip_non_blank();
2067 self.skip_linebreak();
2068 *leading_blanks = true;
2069 break;
2070 }
2071 '\\' if !single => {
2073 string.push(self.resolve_flow_scalar_escape_sequence(start_mark)?);
2074 }
2075 c => {
2076 string.push(c);
2077 self.skip_non_blank();
2078 }
2079 }
2080 self.input.lookahead(2);
2081 }
2082 Ok(())
2083 }
2084
2085 fn resolve_flow_scalar_escape_sequence(
2092 &mut self,
2093 start_mark: &Marker,
2094 ) -> Result<char, ScanError> {
2095 let mut code_length = 0usize;
2096 let mut ret = '\0';
2097
2098 match self.input.peek_nth(1) {
2099 '0' => ret = '\0',
2100 'a' => ret = '\x07',
2101 'b' => ret = '\x08',
2102 't' | '\t' => ret = '\t',
2103 'n' => ret = '\n',
2104 'v' => ret = '\x0b',
2105 'f' => ret = '\x0c',
2106 'r' => ret = '\x0d',
2107 'e' => ret = '\x1b',
2108 ' ' => ret = '\x20',
2109 '"' => ret = '"',
2110 '/' => ret = '/',
2111 '\\' => ret = '\\',
2112 'N' => ret = char::from_u32(0x85).unwrap(),
2114 '_' => ret = char::from_u32(0xA0).unwrap(),
2116 'L' => ret = char::from_u32(0x2028).unwrap(),
2118 'P' => ret = char::from_u32(0x2029).unwrap(),
2120 'x' => code_length = 2,
2121 'u' => code_length = 4,
2122 'U' => code_length = 8,
2123 _ => {
2124 return Err(ScanError::new_str(
2125 *start_mark,
2126 "while parsing a quoted scalar, found unknown escape character",
2127 ));
2128 }
2129 }
2130 self.skip_n_non_blank(2);
2131
2132 if code_length > 0 {
2134 self.input.lookahead(code_length);
2135 let mut value = 0u32;
2136 for i in 0..code_length {
2137 let c = self.input.peek_nth(i);
2138 if !is_hex(c) {
2139 return Err(ScanError::new_str(
2140 *start_mark,
2141 "while parsing a quoted scalar, did not find expected hexadecimal number",
2142 ));
2143 }
2144 value = (value << 4) + as_hex(c);
2145 }
2146
2147 let Some(ch) = char::from_u32(value) else {
2148 return Err(ScanError::new_str(
2149 *start_mark,
2150 "while parsing a quoted scalar, found invalid Unicode character escape code",
2151 ));
2152 };
2153 ret = ch;
2154
2155 self.skip_n_non_blank(code_length);
2156 }
2157 Ok(ret)
2158 }
2159
2160 fn fetch_plain_scalar(&mut self) -> ScanResult {
2161 self.save_simple_key();
2162 self.disallow_simple_key();
2163
2164 let tok = self.scan_plain_scalar()?;
2165
2166 self.tokens.push_back(tok);
2167 Ok(())
2168 }
2169
2170 #[allow(clippy::too_many_lines)]
2175 fn scan_plain_scalar(&mut self) -> Result<Token<'input>, ScanError> {
2176 self.unroll_non_block_indents();
2177 let indent = self.indent + 1;
2178 let start_mark = self.mark;
2179
2180 if self.flow_level > 0 && (start_mark.col as isize) < indent {
2181 return Err(ScanError::new_str(
2182 start_mark,
2183 "invalid indentation in flow construct",
2184 ));
2185 }
2186
2187 let mut string = String::with_capacity(32);
2188 self.buf_whitespaces.clear();
2189 self.buf_leading_break.clear();
2190 self.buf_trailing_breaks.clear();
2191 let mut end_mark = self.mark;
2192
2193 loop {
2194 self.input.lookahead(4);
2195 if (self.leading_whitespace && self.input.next_is_document_indicator())
2196 || self.input.peek() == '#'
2197 {
2198 break;
2199 }
2200
2201 if self.flow_level > 0 && self.input.peek() == '-' && is_flow(self.input.peek_nth(1)) {
2202 return Err(ScanError::new_str(
2203 self.mark,
2204 "plain scalar cannot start with '-' followed by ,[]{}",
2205 ));
2206 }
2207
2208 if !self.input.next_is_blank_or_breakz()
2209 && self.input.next_can_be_plain_scalar(self.flow_level > 0)
2210 {
2211 if self.leading_whitespace {
2212 if self.buf_leading_break.is_empty() {
2213 string.push_str(&self.buf_leading_break);
2214 string.push_str(&self.buf_trailing_breaks);
2215 self.buf_trailing_breaks.clear();
2216 self.buf_leading_break.clear();
2217 } else {
2218 if self.buf_trailing_breaks.is_empty() {
2219 string.push(' ');
2220 } else {
2221 string.push_str(&self.buf_trailing_breaks);
2222 self.buf_trailing_breaks.clear();
2223 }
2224 self.buf_leading_break.clear();
2225 }
2226 self.leading_whitespace = false;
2227 } else if !self.buf_whitespaces.is_empty() {
2228 string.push_str(&self.buf_whitespaces);
2229 self.buf_whitespaces.clear();
2230 }
2231
2232 string.push(self.input.peek());
2234 self.skip_non_blank();
2235 string.reserve(self.input.bufmaxlen());
2236
2237 let mut end = false;
2239 while !end {
2240 self.input.lookahead(self.input.bufmaxlen());
2244 for _ in 0..self.input.bufmaxlen() - 1 {
2245 if self.input.next_is_blank_or_breakz()
2246 || !self.input.next_can_be_plain_scalar(self.flow_level > 0)
2247 {
2248 end = true;
2249 break;
2250 }
2251 string.push(self.input.peek());
2252 self.skip_non_blank();
2253 }
2254 }
2255 end_mark = self.mark;
2256 }
2257
2258 if !(self.input.next_is_blank() || self.input.next_is_break()) {
2263 break;
2264 }
2265
2266 self.input.lookahead(2);
2268 while self.input.next_is_blank_or_break() {
2269 if self.input.next_is_blank() {
2270 if !self.leading_whitespace {
2271 self.buf_whitespaces.push(self.input.peek());
2272 self.skip_blank();
2273 } else if (self.mark.col as isize) < indent && self.input.peek() == '\t' {
2274 self.skip_ws_to_eol(SkipTabs::Yes)?;
2277 if !self.input.next_is_breakz() {
2278 return Err(ScanError::new_str(
2279 start_mark,
2280 "while scanning a plain scalar, found a tab",
2281 ));
2282 }
2283 } else {
2284 self.skip_blank();
2285 }
2286 } else {
2287 if self.leading_whitespace {
2289 self.skip_break();
2290 self.buf_trailing_breaks.push('\n');
2291 } else {
2292 self.buf_whitespaces.clear();
2293 self.skip_break();
2294 self.buf_leading_break.push('\n');
2295 self.leading_whitespace = true;
2296 }
2297 }
2298 self.input.lookahead(2);
2299 }
2300
2301 if self.flow_level == 0 && (self.mark.col as isize) < indent {
2303 break;
2304 }
2305 }
2306
2307 if self.leading_whitespace {
2308 self.allow_simple_key();
2309 }
2310
2311 if string.is_empty() {
2312 Err(ScanError::new_str(
2316 start_mark,
2317 "unexpected end of plain scalar",
2318 ))
2319 } else {
2320 Ok(Token(
2321 Span::new(start_mark, end_mark),
2322 TokenType::Scalar(ScalarStyle::Plain, string.into()),
2323 ))
2324 }
2325 }
2326
2327 fn fetch_key(&mut self) -> ScanResult {
2328 let start_mark = self.mark;
2329 if self.flow_level == 0 {
2330 if !self.simple_key_allowed {
2332 return Err(ScanError::new_str(
2333 self.mark,
2334 "mapping keys are not allowed in this context",
2335 ));
2336 }
2337 self.roll_indent(
2338 start_mark.col,
2339 None,
2340 TokenType::BlockMappingStart,
2341 start_mark,
2342 );
2343 } else {
2344 self.flow_mapping_started = true;
2346 }
2347
2348 self.remove_simple_key()?;
2349
2350 if self.flow_level == 0 {
2351 self.allow_simple_key();
2352 } else {
2353 self.disallow_simple_key();
2354 }
2355
2356 self.skip_non_blank();
2357 self.skip_yaml_whitespace()?;
2358 if self.input.peek() == '\t' {
2359 return Err(ScanError::new_str(
2360 self.mark(),
2361 "tabs disallowed in this context",
2362 ));
2363 }
2364 self.tokens
2365 .push_back(Token(Span::new(start_mark, self.mark), TokenType::Key));
2366 Ok(())
2367 }
2368
2369 fn fetch_flow_value(&mut self) -> ScanResult {
2377 let nc = self.input.peek_nth(1);
2378
2379 if self.mark.index != self.adjacent_value_allowed_at && (nc == '[' || nc == '{') {
2391 return Err(ScanError::new_str(
2392 self.mark,
2393 "':' may not precede any of `[{` in flow mapping",
2394 ));
2395 }
2396
2397 self.fetch_value()
2398 }
2399
2400 fn fetch_value(&mut self) -> ScanResult {
2402 let sk = self.simple_keys.last().unwrap().clone();
2403 let start_mark = self.mark;
2404 let is_implicit_flow_mapping =
2405 !self.implicit_flow_mapping_states.is_empty() && !self.flow_mapping_started;
2406 if is_implicit_flow_mapping {
2407 *self.implicit_flow_mapping_states.last_mut().unwrap() = ImplicitMappingState::Inside;
2408 }
2409
2410 self.skip_non_blank();
2412 if self.input.look_ch() == '\t'
2413 && !self.skip_ws_to_eol(SkipTabs::Yes)?.has_valid_yaml_ws()
2414 && (self.input.peek() == '-' || self.input.next_is_alpha())
2415 {
2416 return Err(ScanError::new_str(
2417 self.mark,
2418 "':' must be followed by a valid YAML whitespace",
2419 ));
2420 }
2421
2422 if sk.possible {
2423 let tok = Token(Span::empty(sk.mark), TokenType::Key);
2425 self.insert_token(sk.token_number - self.tokens_parsed, tok);
2426 if is_implicit_flow_mapping {
2427 if sk.mark.line < start_mark.line {
2428 return Err(ScanError::new_str(
2429 start_mark,
2430 "illegal placement of ':' indicator",
2431 ));
2432 }
2433 self.insert_token(
2434 sk.token_number - self.tokens_parsed,
2435 Token(Span::empty(sk.mark), TokenType::FlowMappingStart),
2436 );
2437 }
2438
2439 self.roll_indent(
2441 sk.mark.col,
2442 Some(sk.token_number),
2443 TokenType::BlockMappingStart,
2444 sk.mark,
2445 );
2446 self.roll_one_col_indent();
2447
2448 self.simple_keys.last_mut().unwrap().possible = false;
2449 self.disallow_simple_key();
2450 } else {
2451 if is_implicit_flow_mapping {
2452 self.tokens
2453 .push_back(Token(Span::empty(start_mark), TokenType::FlowMappingStart));
2454 }
2455 if self.flow_level == 0 {
2457 if !self.simple_key_allowed {
2458 return Err(ScanError::new_str(
2459 start_mark,
2460 "mapping values are not allowed in this context",
2461 ));
2462 }
2463
2464 self.roll_indent(
2465 start_mark.col,
2466 None,
2467 TokenType::BlockMappingStart,
2468 start_mark,
2469 );
2470 }
2471 self.roll_one_col_indent();
2472
2473 if self.flow_level == 0 {
2474 self.allow_simple_key();
2475 } else {
2476 self.disallow_simple_key();
2477 }
2478 }
2479 self.tokens
2480 .push_back(Token(Span::empty(start_mark), TokenType::Value));
2481
2482 Ok(())
2483 }
2484
2485 fn roll_indent(
2491 &mut self,
2492 col: usize,
2493 number: Option<usize>,
2494 tok: TokenType<'input>,
2495 mark: Marker,
2496 ) {
2497 if self.flow_level > 0 {
2498 return;
2499 }
2500
2501 if self.indent <= col as isize {
2505 if let Some(indent) = self.indents.last() {
2506 if !indent.needs_block_end {
2507 self.indent = indent.indent;
2508 self.indents.pop();
2509 }
2510 }
2511 }
2512
2513 if self.indent < col as isize {
2514 self.indents.push(Indent {
2515 indent: self.indent,
2516 needs_block_end: true,
2517 });
2518 self.indent = col as isize;
2519 let tokens_parsed = self.tokens_parsed;
2520 match number {
2521 Some(n) => self.insert_token(n - tokens_parsed, Token(Span::empty(mark), tok)),
2522 None => self.tokens.push_back(Token(Span::empty(mark), tok)),
2523 }
2524 }
2525 }
2526
2527 fn unroll_indent(&mut self, col: isize) {
2533 if self.flow_level > 0 {
2534 return;
2535 }
2536 while self.indent > col {
2537 let indent = self.indents.pop().unwrap();
2538 self.indent = indent.indent;
2539 if indent.needs_block_end {
2540 self.tokens
2541 .push_back(Token(Span::empty(self.mark), TokenType::BlockEnd));
2542 }
2543 }
2544 }
2545
2546 fn roll_one_col_indent(&mut self) {
2552 if self.flow_level == 0 && self.indents.last().is_some_and(|x| x.needs_block_end) {
2553 self.indents.push(Indent {
2554 indent: self.indent,
2555 needs_block_end: false,
2556 });
2557 self.indent += 1;
2558 }
2559 }
2560
2561 fn unroll_non_block_indents(&mut self) {
2563 while let Some(indent) = self.indents.last() {
2564 if indent.needs_block_end {
2565 break;
2566 }
2567 self.indent = indent.indent;
2568 self.indents.pop();
2569 }
2570 }
2571
2572 fn save_simple_key(&mut self) {
2574 if self.simple_key_allowed {
2575 let required = self.flow_level == 0
2576 && self.indent == (self.mark.col as isize)
2577 && self.indents.last().unwrap().needs_block_end;
2578 let mut sk = SimpleKey::new(self.mark);
2579 sk.possible = true;
2580 sk.required = required;
2581 sk.token_number = self.tokens_parsed + self.tokens.len();
2582
2583 self.simple_keys.pop();
2584 self.simple_keys.push(sk);
2585 }
2586 }
2587
2588 fn remove_simple_key(&mut self) -> ScanResult {
2589 let last = self.simple_keys.last_mut().unwrap();
2590 if last.possible && last.required {
2591 return Err(ScanError::new_str(self.mark, "simple key expected"));
2592 }
2593
2594 last.possible = false;
2595 Ok(())
2596 }
2597
2598 fn is_within_block(&self) -> bool {
2600 !self.indents.is_empty()
2601 }
2602
2603 fn end_implicit_mapping(&mut self, mark: Marker) {
2609 if let Some(implicit_mapping) = self.implicit_flow_mapping_states.last_mut() {
2610 if *implicit_mapping == ImplicitMappingState::Inside {
2611 self.flow_mapping_started = false;
2612 *implicit_mapping = ImplicitMappingState::Possible;
2613 self.tokens
2614 .push_back(Token(Span::empty(mark), TokenType::FlowMappingEnd));
2615 }
2616 }
2617 }
2618}
2619
2620#[derive(PartialEq, Eq)]
2624pub enum Chomping {
2625 Strip,
2627 Clip,
2629 Keep,
2631}
2632
2633#[cfg(test)]
2634mod test {
2635 #[test]
2636 fn test_is_anchor_char() {
2637 use super::is_anchor_char;
2638 assert!(is_anchor_char('x'));
2639 }
2640}