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(start_mark, "while scanning an anchor or alias, did not find expected alphabetic or numeric character"));
1378 }
1379
1380 let tok = if alias {
1381 TokenType::Alias(string.into())
1382 } else {
1383 TokenType::Anchor(string.into())
1384 };
1385 Ok(Token(Span::new(start_mark, self.mark), tok))
1386 }
1387
1388 fn fetch_flow_collection_start(&mut self, tok: TokenType<'input>) -> ScanResult {
1389 self.save_simple_key();
1391
1392 self.roll_one_col_indent();
1393 self.increase_flow_level()?;
1394
1395 self.allow_simple_key();
1396
1397 let start_mark = self.mark;
1398 self.skip_non_blank();
1399
1400 if tok == TokenType::FlowMappingStart {
1401 self.flow_mapping_started = true;
1402 } else {
1403 self.implicit_flow_mapping_states
1404 .push(ImplicitMappingState::Possible);
1405 }
1406
1407 self.skip_ws_to_eol(SkipTabs::Yes)?;
1408
1409 self.tokens
1410 .push_back(Token(Span::new(start_mark, self.mark), tok));
1411 Ok(())
1412 }
1413
1414 fn fetch_flow_collection_end(&mut self, tok: TokenType<'input>) -> ScanResult {
1415 self.remove_simple_key()?;
1416 self.decrease_flow_level();
1417
1418 self.disallow_simple_key();
1419
1420 if matches!(tok, TokenType::FlowSequenceEnd) {
1421 self.end_implicit_mapping(self.mark);
1422 self.implicit_flow_mapping_states.pop();
1424 }
1425
1426 let start_mark = self.mark;
1427 self.skip_non_blank();
1428 self.skip_ws_to_eol(SkipTabs::Yes)?;
1429
1430 if self.flow_level > 0 {
1436 self.adjacent_value_allowed_at = self.mark.index;
1437 }
1438
1439 self.tokens
1440 .push_back(Token(Span::new(start_mark, self.mark), tok));
1441 Ok(())
1442 }
1443
1444 fn fetch_flow_entry(&mut self) -> ScanResult {
1446 self.remove_simple_key()?;
1447 self.allow_simple_key();
1448
1449 self.end_implicit_mapping(self.mark);
1450
1451 let start_mark = self.mark;
1452 self.skip_non_blank();
1453 self.skip_ws_to_eol(SkipTabs::Yes)?;
1454
1455 self.tokens.push_back(Token(
1456 Span::new(start_mark, self.mark),
1457 TokenType::FlowEntry,
1458 ));
1459 Ok(())
1460 }
1461
1462 fn increase_flow_level(&mut self) -> ScanResult {
1463 self.simple_keys.push(SimpleKey::new(Marker::new(0, 0, 0)));
1464 self.flow_level = self
1465 .flow_level
1466 .checked_add(1)
1467 .ok_or_else(|| ScanError::new_str(self.mark, "recursion limit exceeded"))?;
1468 Ok(())
1469 }
1470
1471 fn decrease_flow_level(&mut self) {
1472 if self.flow_level > 0 {
1473 self.flow_level -= 1;
1474 self.simple_keys.pop().unwrap();
1475 }
1476 }
1477
1478 fn fetch_block_entry(&mut self) -> ScanResult {
1484 if self.flow_level > 0 {
1485 return Err(ScanError::new_str(
1487 self.mark,
1488 r#""-" is only valid inside a block"#,
1489 ));
1490 }
1491 if !self.simple_key_allowed {
1493 return Err(ScanError::new_str(
1494 self.mark,
1495 "block sequence entries are not allowed in this context",
1496 ));
1497 }
1498
1499 if let Some(Token(span, TokenType::Anchor(..) | TokenType::Tag(..))) = self.tokens.back() {
1501 if self.mark.col == 0 && span.start.col == 0 && self.indent > -1 {
1502 return Err(ScanError::new_str(
1503 span.start,
1504 "invalid indentation for anchor",
1505 ));
1506 }
1507 }
1508
1509 let mark = self.mark;
1511 self.skip_non_blank();
1512
1513 self.roll_indent(mark.col, None, TokenType::BlockSequenceStart, mark);
1515 let found_tabs = self.skip_ws_to_eol(SkipTabs::Yes)?.found_tabs();
1516 self.input.lookahead(2);
1517 if found_tabs && self.input.next_char_is('-') && is_blank_or_breakz(self.input.peek_nth(1))
1518 {
1519 return Err(ScanError::new_str(
1520 self.mark,
1521 "'-' must be followed by a valid YAML whitespace",
1522 ));
1523 }
1524
1525 self.skip_ws_to_eol(SkipTabs::No)?;
1526 self.input.lookahead(1);
1527 if self.input.next_is_break() || self.input.next_is_flow() {
1528 self.roll_one_col_indent();
1529 }
1530
1531 self.remove_simple_key()?;
1532 self.allow_simple_key();
1533
1534 self.tokens
1535 .push_back(Token(Span::empty(self.mark), TokenType::BlockEntry));
1536
1537 Ok(())
1538 }
1539
1540 fn fetch_document_indicator(&mut self, t: TokenType<'input>) -> ScanResult {
1541 self.unroll_indent(-1);
1542 self.remove_simple_key()?;
1543 self.disallow_simple_key();
1544
1545 let mark = self.mark;
1546
1547 self.skip_n_non_blank(3);
1548
1549 self.tokens.push_back(Token(Span::new(mark, self.mark), t));
1550 Ok(())
1551 }
1552
1553 fn fetch_block_scalar(&mut self, literal: bool) -> ScanResult {
1554 self.save_simple_key();
1555 self.allow_simple_key();
1556 let tok = self.scan_block_scalar(literal)?;
1557
1558 self.tokens.push_back(tok);
1559 Ok(())
1560 }
1561
1562 #[allow(clippy::too_many_lines)]
1563 fn scan_block_scalar(&mut self, literal: bool) -> Result<Token<'input>, ScanError> {
1564 let start_mark = self.mark;
1565 let mut chomping = Chomping::Clip;
1566 let mut increment: usize = 0;
1567 let mut indent: usize = 0;
1568 let mut trailing_blank: bool;
1569 let mut leading_blank: bool = false;
1570 let style = if literal {
1571 ScalarStyle::Literal
1572 } else {
1573 ScalarStyle::Folded
1574 };
1575
1576 let mut string = String::new();
1577 let mut leading_break = String::new();
1578 let mut trailing_breaks = String::new();
1579 let mut chomping_break = String::new();
1580
1581 self.skip_non_blank();
1583 self.unroll_non_block_indents();
1584
1585 if self.input.look_ch() == '+' || self.input.peek() == '-' {
1586 if self.input.peek() == '+' {
1587 chomping = Chomping::Keep;
1588 } else {
1589 chomping = Chomping::Strip;
1590 }
1591 self.skip_non_blank();
1592 self.input.lookahead(1);
1593 if self.input.next_is_digit() {
1594 if self.input.peek() == '0' {
1595 return Err(ScanError::new_str(
1596 start_mark,
1597 "while scanning a block scalar, found an indentation indicator equal to 0",
1598 ));
1599 }
1600 increment = (self.input.peek() as usize) - ('0' as usize);
1601 self.skip_non_blank();
1602 }
1603 } else if self.input.next_is_digit() {
1604 if self.input.peek() == '0' {
1605 return Err(ScanError::new_str(
1606 start_mark,
1607 "while scanning a block scalar, found an indentation indicator equal to 0",
1608 ));
1609 }
1610
1611 increment = (self.input.peek() as usize) - ('0' as usize);
1612 self.skip_non_blank();
1613 self.input.lookahead(1);
1614 if self.input.peek() == '+' || self.input.peek() == '-' {
1615 if self.input.peek() == '+' {
1616 chomping = Chomping::Keep;
1617 } else {
1618 chomping = Chomping::Strip;
1619 }
1620 self.skip_non_blank();
1621 }
1622 }
1623
1624 self.skip_ws_to_eol(SkipTabs::Yes)?;
1625
1626 self.input.lookahead(1);
1628 if !self.input.next_is_breakz() {
1629 return Err(ScanError::new_str(
1630 start_mark,
1631 "while scanning a block scalar, did not find expected comment or line break",
1632 ));
1633 }
1634
1635 if self.input.next_is_break() {
1636 self.input.lookahead(2);
1637 self.read_break(&mut chomping_break);
1638 }
1639
1640 if self.input.look_ch() == '\t' {
1641 return Err(ScanError::new_str(
1642 start_mark,
1643 "a block scalar content cannot start with a tab",
1644 ));
1645 }
1646
1647 if increment > 0 {
1648 indent = if self.indent >= 0 {
1649 (self.indent + increment as isize) as usize
1650 } else {
1651 increment
1652 }
1653 }
1654
1655 if indent == 0 {
1657 self.skip_block_scalar_first_line_indent(&mut indent, &mut trailing_breaks);
1658 } else {
1659 self.skip_block_scalar_indent(indent, &mut trailing_breaks);
1660 }
1661
1662 if self.input.next_is_z() {
1667 let contents = match chomping {
1668 Chomping::Strip => String::new(),
1670 _ if self.mark.line == start_mark.line() => String::new(),
1672 Chomping::Clip => chomping_break,
1675 Chomping::Keep if trailing_breaks.is_empty() => chomping_break,
1678 Chomping::Keep => trailing_breaks,
1680 };
1681 return Ok(Token(
1682 Span::new(start_mark, self.mark),
1683 TokenType::Scalar(style, contents.into()),
1684 ));
1685 }
1686
1687 if self.mark.col < indent && (self.mark.col as isize) > self.indent {
1688 return Err(ScanError::new_str(
1689 self.mark,
1690 "wrongly indented line in block scalar",
1691 ));
1692 }
1693
1694 let mut line_buffer = String::with_capacity(100);
1695 let start_mark = self.mark;
1696 while self.mark.col == indent && !self.input.next_is_z() {
1697 if indent == 0 {
1698 self.input.lookahead(4);
1699 if self.input.next_is_document_end() {
1700 break;
1701 }
1702 }
1703
1704 trailing_blank = self.input.next_is_blank();
1706 if !literal && !leading_break.is_empty() && !leading_blank && !trailing_blank {
1707 string.push_str(&trailing_breaks);
1708 if trailing_breaks.is_empty() {
1709 string.push(' ');
1710 }
1711 } else {
1712 string.push_str(&leading_break);
1713 string.push_str(&trailing_breaks);
1714 }
1715
1716 leading_break.clear();
1717 trailing_breaks.clear();
1718
1719 leading_blank = self.input.next_is_blank();
1720
1721 self.scan_block_scalar_content_line(&mut string, &mut line_buffer);
1722
1723 self.input.lookahead(2);
1725 if self.input.next_is_z() {
1726 break;
1727 }
1728
1729 self.read_break(&mut leading_break);
1730
1731 self.skip_block_scalar_indent(indent, &mut trailing_breaks);
1733 }
1734
1735 if chomping != Chomping::Strip {
1737 string.push_str(&leading_break);
1738 if self.input.next_is_z() && self.mark.col >= indent.max(1) {
1742 string.push('\n');
1743 }
1744 }
1745
1746 if chomping == Chomping::Keep {
1747 string.push_str(&trailing_breaks);
1748 }
1749
1750 Ok(Token(
1751 Span::new(start_mark, self.mark),
1752 TokenType::Scalar(style, string.into()),
1753 ))
1754 }
1755
1756 fn scan_block_scalar_content_line(&mut self, string: &mut String, line_buffer: &mut String) {
1766 while !self.input.buf_is_empty() && !self.input.next_is_breakz() {
1768 string.push(self.input.peek());
1769 self.skip_blank();
1775 }
1776
1777 if self.input.buf_is_empty() {
1780 while let Some(c) = self.input.raw_read_non_breakz_ch() {
1786 line_buffer.push(c);
1787 }
1788
1789 let n_chars = line_buffer.chars().count();
1791 self.mark.col += n_chars;
1792 self.mark.index += n_chars;
1793
1794 string.reserve(line_buffer.len());
1796 string.push_str(line_buffer);
1797 line_buffer.clear();
1799 }
1800 }
1801
1802 fn skip_block_scalar_indent(&mut self, indent: usize, breaks: &mut String) {
1804 loop {
1805 if indent < self.input.bufmaxlen() - 2 {
1807 self.input.lookahead(self.input.bufmaxlen());
1808 while self.mark.col < indent && self.input.peek() == ' ' {
1809 self.skip_blank();
1810 }
1811 } else {
1812 loop {
1813 self.input.lookahead(self.input.bufmaxlen());
1814 while !self.input.buf_is_empty()
1815 && self.mark.col < indent
1816 && self.input.peek() == ' '
1817 {
1818 self.skip_blank();
1819 }
1820 if self.mark.col == indent
1824 || (!self.input.buf_is_empty() && self.input.peek() != ' ')
1825 {
1826 break;
1827 }
1828 }
1829 self.input.lookahead(2);
1830 }
1831
1832 if self.input.next_is_break() {
1834 self.read_break(breaks);
1835 } else {
1836 break;
1838 }
1839 }
1840 }
1841
1842 fn skip_block_scalar_first_line_indent(&mut self, indent: &mut usize, breaks: &mut String) {
1847 let mut max_indent = 0;
1848 loop {
1849 while self.input.look_ch() == ' ' {
1851 self.skip_blank();
1852 }
1853
1854 if self.mark.col > max_indent {
1855 max_indent = self.mark.col;
1856 }
1857
1858 if self.input.next_is_break() {
1859 self.input.lookahead(2);
1861 self.read_break(breaks);
1862 } else {
1863 break;
1865 }
1866 }
1867
1868 *indent = max_indent.max((self.indent + 1) as usize);
1877 if self.indent > 0 {
1878 *indent = (*indent).max(1);
1879 }
1880 }
1881
1882 fn fetch_flow_scalar(&mut self, single: bool) -> ScanResult {
1883 self.save_simple_key();
1884 self.disallow_simple_key();
1885
1886 let tok = self.scan_flow_scalar(single)?;
1887
1888 self.skip_to_next_token()?;
1891 self.adjacent_value_allowed_at = self.mark.index;
1892
1893 self.tokens.push_back(tok);
1894 Ok(())
1895 }
1896
1897 #[allow(clippy::too_many_lines)]
1898 fn scan_flow_scalar(&mut self, single: bool) -> Result<Token<'input>, ScanError> {
1899 let start_mark = self.mark;
1900
1901 let mut string = String::new();
1902 let mut leading_break = String::new();
1903 let mut trailing_breaks = String::new();
1904 let mut whitespaces = String::new();
1905 let mut leading_blanks;
1906
1907 self.skip_non_blank();
1909
1910 loop {
1911 self.input.lookahead(4);
1913
1914 if self.mark.col == 0 && self.input.next_is_document_indicator() {
1915 return Err(ScanError::new_str(
1916 start_mark,
1917 "while scanning a quoted scalar, found unexpected document indicator",
1918 ));
1919 }
1920
1921 if self.input.next_is_z() {
1922 return Err(ScanError::new_str(
1923 start_mark,
1924 "while scanning a quoted scalar, found unexpected end of stream",
1925 ));
1926 }
1927
1928 if (self.mark.col as isize) < self.indent {
1929 return Err(ScanError::new_str(
1930 start_mark,
1931 "invalid indentation in quoted scalar",
1932 ));
1933 }
1934
1935 leading_blanks = false;
1936 self.consume_flow_scalar_non_whitespace_chars(
1937 single,
1938 &mut string,
1939 &mut leading_blanks,
1940 &start_mark,
1941 )?;
1942
1943 match self.input.look_ch() {
1944 '\'' if single => break,
1945 '"' if !single => break,
1946 _ => {}
1947 }
1948
1949 while self.input.next_is_blank() || self.input.next_is_break() {
1951 if self.input.next_is_blank() {
1952 if leading_blanks {
1954 if self.input.peek() == '\t' && (self.mark.col as isize) < self.indent {
1955 return Err(ScanError::new_str(
1956 self.mark,
1957 "tab cannot be used as indentation",
1958 ));
1959 }
1960 self.skip_blank();
1961 } else {
1962 whitespaces.push(self.input.peek());
1963 self.skip_blank();
1964 }
1965 } else {
1966 self.input.lookahead(2);
1967 if leading_blanks {
1969 self.read_break(&mut trailing_breaks);
1970 } else {
1971 whitespaces.clear();
1972 self.read_break(&mut leading_break);
1973 leading_blanks = true;
1974 }
1975 }
1976 self.input.lookahead(1);
1977 }
1978
1979 if leading_blanks {
1981 if leading_break.is_empty() {
1982 string.push_str(&leading_break);
1983 string.push_str(&trailing_breaks);
1984 trailing_breaks.clear();
1985 leading_break.clear();
1986 } else {
1987 if trailing_breaks.is_empty() {
1988 string.push(' ');
1989 } else {
1990 string.push_str(&trailing_breaks);
1991 trailing_breaks.clear();
1992 }
1993 leading_break.clear();
1994 }
1995 } else {
1996 string.push_str(&whitespaces);
1997 whitespaces.clear();
1998 }
1999 } self.skip_non_blank();
2003 self.skip_ws_to_eol(SkipTabs::Yes)?;
2005 match self.input.peek() {
2006 ',' | '}' | ']' if self.flow_level > 0 => {}
2008 c if is_breakz(c) => {}
2010 ':' if self.flow_level == 0 && start_mark.line == self.mark.line => {}
2013 ':' if self.flow_level > 0 => {}
2015 _ => {
2016 return Err(ScanError::new_str(
2017 self.mark,
2018 "invalid trailing content after double-quoted scalar",
2019 ));
2020 }
2021 }
2022
2023 let style = if single {
2024 ScalarStyle::SingleQuoted
2025 } else {
2026 ScalarStyle::DoubleQuoted
2027 };
2028 Ok(Token(
2029 Span::new(start_mark, self.mark),
2030 TokenType::Scalar(style, string.into()),
2031 ))
2032 }
2033
2034 fn consume_flow_scalar_non_whitespace_chars(
2043 &mut self,
2044 single: bool,
2045 string: &mut String,
2046 leading_blanks: &mut bool,
2047 start_mark: &Marker,
2048 ) -> Result<(), ScanError> {
2049 self.input.lookahead(2);
2050 while !is_blank_or_breakz(self.input.peek()) {
2051 match self.input.peek() {
2052 '\'' if self.input.peek_nth(1) == '\'' && single => {
2054 string.push('\'');
2055 self.skip_n_non_blank(2);
2056 }
2057 '\'' if single => break,
2059 '"' if !single => break,
2060 '\\' if !single && is_break(self.input.peek_nth(1)) => {
2062 self.input.lookahead(3);
2063 self.skip_non_blank();
2064 self.skip_linebreak();
2065 *leading_blanks = true;
2066 break;
2067 }
2068 '\\' if !single => {
2070 string.push(self.resolve_flow_scalar_escape_sequence(start_mark)?);
2071 }
2072 c => {
2073 string.push(c);
2074 self.skip_non_blank();
2075 }
2076 }
2077 self.input.lookahead(2);
2078 }
2079 Ok(())
2080 }
2081
2082 fn resolve_flow_scalar_escape_sequence(
2089 &mut self,
2090 start_mark: &Marker,
2091 ) -> Result<char, ScanError> {
2092 let mut code_length = 0usize;
2093 let mut ret = '\0';
2094
2095 match self.input.peek_nth(1) {
2096 '0' => ret = '\0',
2097 'a' => ret = '\x07',
2098 'b' => ret = '\x08',
2099 't' | '\t' => ret = '\t',
2100 'n' => ret = '\n',
2101 'v' => ret = '\x0b',
2102 'f' => ret = '\x0c',
2103 'r' => ret = '\x0d',
2104 'e' => ret = '\x1b',
2105 ' ' => ret = '\x20',
2106 '"' => ret = '"',
2107 '/' => ret = '/',
2108 '\\' => ret = '\\',
2109 'N' => ret = char::from_u32(0x85).unwrap(),
2111 '_' => ret = char::from_u32(0xA0).unwrap(),
2113 'L' => ret = char::from_u32(0x2028).unwrap(),
2115 'P' => ret = char::from_u32(0x2029).unwrap(),
2117 'x' => code_length = 2,
2118 'u' => code_length = 4,
2119 'U' => code_length = 8,
2120 _ => {
2121 return Err(ScanError::new_str(
2122 *start_mark,
2123 "while parsing a quoted scalar, found unknown escape character",
2124 ))
2125 }
2126 }
2127 self.skip_n_non_blank(2);
2128
2129 if code_length > 0 {
2131 self.input.lookahead(code_length);
2132 let mut value = 0u32;
2133 for i in 0..code_length {
2134 let c = self.input.peek_nth(i);
2135 if !is_hex(c) {
2136 return Err(ScanError::new_str(
2137 *start_mark,
2138 "while parsing a quoted scalar, did not find expected hexadecimal number",
2139 ));
2140 }
2141 value = (value << 4) + as_hex(c);
2142 }
2143
2144 let Some(ch) = char::from_u32(value) else {
2145 return Err(ScanError::new_str(
2146 *start_mark,
2147 "while parsing a quoted scalar, found invalid Unicode character escape code",
2148 ));
2149 };
2150 ret = ch;
2151
2152 self.skip_n_non_blank(code_length);
2153 }
2154 Ok(ret)
2155 }
2156
2157 fn fetch_plain_scalar(&mut self) -> ScanResult {
2158 self.save_simple_key();
2159 self.disallow_simple_key();
2160
2161 let tok = self.scan_plain_scalar()?;
2162
2163 self.tokens.push_back(tok);
2164 Ok(())
2165 }
2166
2167 #[allow(clippy::too_many_lines)]
2172 fn scan_plain_scalar(&mut self) -> Result<Token<'input>, ScanError> {
2173 self.unroll_non_block_indents();
2174 let indent = self.indent + 1;
2175 let start_mark = self.mark;
2176
2177 if self.flow_level > 0 && (start_mark.col as isize) < indent {
2178 return Err(ScanError::new_str(
2179 start_mark,
2180 "invalid indentation in flow construct",
2181 ));
2182 }
2183
2184 let mut string = String::with_capacity(32);
2185 self.buf_whitespaces.clear();
2186 self.buf_leading_break.clear();
2187 self.buf_trailing_breaks.clear();
2188 let mut end_mark = self.mark;
2189
2190 loop {
2191 self.input.lookahead(4);
2192 if (self.leading_whitespace && self.input.next_is_document_indicator())
2193 || self.input.peek() == '#'
2194 {
2195 break;
2196 }
2197
2198 if self.flow_level > 0 && self.input.peek() == '-' && is_flow(self.input.peek_nth(1)) {
2199 return Err(ScanError::new_str(
2200 self.mark,
2201 "plain scalar cannot start with '-' followed by ,[]{}",
2202 ));
2203 }
2204
2205 if !self.input.next_is_blank_or_breakz()
2206 && self.input.next_can_be_plain_scalar(self.flow_level > 0)
2207 {
2208 if self.leading_whitespace {
2209 if self.buf_leading_break.is_empty() {
2210 string.push_str(&self.buf_leading_break);
2211 string.push_str(&self.buf_trailing_breaks);
2212 self.buf_trailing_breaks.clear();
2213 self.buf_leading_break.clear();
2214 } else {
2215 if self.buf_trailing_breaks.is_empty() {
2216 string.push(' ');
2217 } else {
2218 string.push_str(&self.buf_trailing_breaks);
2219 self.buf_trailing_breaks.clear();
2220 }
2221 self.buf_leading_break.clear();
2222 }
2223 self.leading_whitespace = false;
2224 } else if !self.buf_whitespaces.is_empty() {
2225 string.push_str(&self.buf_whitespaces);
2226 self.buf_whitespaces.clear();
2227 }
2228
2229 string.push(self.input.peek());
2231 self.skip_non_blank();
2232 string.reserve(self.input.bufmaxlen());
2233
2234 let mut end = false;
2236 while !end {
2237 self.input.lookahead(self.input.bufmaxlen());
2241 for _ in 0..self.input.bufmaxlen() - 1 {
2242 if self.input.next_is_blank_or_breakz()
2243 || !self.input.next_can_be_plain_scalar(self.flow_level > 0)
2244 {
2245 end = true;
2246 break;
2247 }
2248 string.push(self.input.peek());
2249 self.skip_non_blank();
2250 }
2251 }
2252 end_mark = self.mark;
2253 }
2254
2255 if !(self.input.next_is_blank() || self.input.next_is_break()) {
2260 break;
2261 }
2262
2263 self.input.lookahead(2);
2265 while self.input.next_is_blank_or_break() {
2266 if self.input.next_is_blank() {
2267 if !self.leading_whitespace {
2268 self.buf_whitespaces.push(self.input.peek());
2269 self.skip_blank();
2270 } else if (self.mark.col as isize) < indent && self.input.peek() == '\t' {
2271 self.skip_ws_to_eol(SkipTabs::Yes)?;
2274 if !self.input.next_is_breakz() {
2275 return Err(ScanError::new_str(
2276 start_mark,
2277 "while scanning a plain scalar, found a tab",
2278 ));
2279 }
2280 } else {
2281 self.skip_blank();
2282 }
2283 } else {
2284 if self.leading_whitespace {
2286 self.skip_break();
2287 self.buf_trailing_breaks.push('\n');
2288 } else {
2289 self.buf_whitespaces.clear();
2290 self.skip_break();
2291 self.buf_leading_break.push('\n');
2292 self.leading_whitespace = true;
2293 }
2294 }
2295 self.input.lookahead(2);
2296 }
2297
2298 if self.flow_level == 0 && (self.mark.col as isize) < indent {
2300 break;
2301 }
2302 }
2303
2304 if self.leading_whitespace {
2305 self.allow_simple_key();
2306 }
2307
2308 if string.is_empty() {
2309 Err(ScanError::new_str(
2313 start_mark,
2314 "unexpected end of plain scalar",
2315 ))
2316 } else {
2317 Ok(Token(
2318 Span::new(start_mark, end_mark),
2319 TokenType::Scalar(ScalarStyle::Plain, string.into()),
2320 ))
2321 }
2322 }
2323
2324 fn fetch_key(&mut self) -> ScanResult {
2325 let start_mark = self.mark;
2326 if self.flow_level == 0 {
2327 if !self.simple_key_allowed {
2329 return Err(ScanError::new_str(
2330 self.mark,
2331 "mapping keys are not allowed in this context",
2332 ));
2333 }
2334 self.roll_indent(
2335 start_mark.col,
2336 None,
2337 TokenType::BlockMappingStart,
2338 start_mark,
2339 );
2340 } else {
2341 self.flow_mapping_started = true;
2343 }
2344
2345 self.remove_simple_key()?;
2346
2347 if self.flow_level == 0 {
2348 self.allow_simple_key();
2349 } else {
2350 self.disallow_simple_key();
2351 }
2352
2353 self.skip_non_blank();
2354 self.skip_yaml_whitespace()?;
2355 if self.input.peek() == '\t' {
2356 return Err(ScanError::new_str(
2357 self.mark(),
2358 "tabs disallowed in this context",
2359 ));
2360 }
2361 self.tokens
2362 .push_back(Token(Span::new(start_mark, self.mark), TokenType::Key));
2363 Ok(())
2364 }
2365
2366 fn fetch_flow_value(&mut self) -> ScanResult {
2374 let nc = self.input.peek_nth(1);
2375
2376 if self.mark.index != self.adjacent_value_allowed_at && (nc == '[' || nc == '{') {
2388 return Err(ScanError::new_str(
2389 self.mark,
2390 "':' may not precede any of `[{` in flow mapping",
2391 ));
2392 }
2393
2394 self.fetch_value()
2395 }
2396
2397 fn fetch_value(&mut self) -> ScanResult {
2399 let sk = self.simple_keys.last().unwrap().clone();
2400 let start_mark = self.mark;
2401 let is_implicit_flow_mapping =
2402 !self.implicit_flow_mapping_states.is_empty() && !self.flow_mapping_started;
2403 if is_implicit_flow_mapping {
2404 *self.implicit_flow_mapping_states.last_mut().unwrap() = ImplicitMappingState::Inside;
2405 }
2406
2407 self.skip_non_blank();
2409 if self.input.look_ch() == '\t'
2410 && !self.skip_ws_to_eol(SkipTabs::Yes)?.has_valid_yaml_ws()
2411 && (self.input.peek() == '-' || self.input.next_is_alpha())
2412 {
2413 return Err(ScanError::new_str(
2414 self.mark,
2415 "':' must be followed by a valid YAML whitespace",
2416 ));
2417 }
2418
2419 if sk.possible {
2420 let tok = Token(Span::empty(sk.mark), TokenType::Key);
2422 self.insert_token(sk.token_number - self.tokens_parsed, tok);
2423 if is_implicit_flow_mapping {
2424 if sk.mark.line < start_mark.line {
2425 return Err(ScanError::new_str(
2426 start_mark,
2427 "illegal placement of ':' indicator",
2428 ));
2429 }
2430 self.insert_token(
2431 sk.token_number - self.tokens_parsed,
2432 Token(Span::empty(sk.mark), TokenType::FlowMappingStart),
2433 );
2434 }
2435
2436 self.roll_indent(
2438 sk.mark.col,
2439 Some(sk.token_number),
2440 TokenType::BlockMappingStart,
2441 sk.mark,
2442 );
2443 self.roll_one_col_indent();
2444
2445 self.simple_keys.last_mut().unwrap().possible = false;
2446 self.disallow_simple_key();
2447 } else {
2448 if is_implicit_flow_mapping {
2449 self.tokens
2450 .push_back(Token(Span::empty(start_mark), TokenType::FlowMappingStart));
2451 }
2452 if self.flow_level == 0 {
2454 if !self.simple_key_allowed {
2455 return Err(ScanError::new_str(
2456 start_mark,
2457 "mapping values are not allowed in this context",
2458 ));
2459 }
2460
2461 self.roll_indent(
2462 start_mark.col,
2463 None,
2464 TokenType::BlockMappingStart,
2465 start_mark,
2466 );
2467 }
2468 self.roll_one_col_indent();
2469
2470 if self.flow_level == 0 {
2471 self.allow_simple_key();
2472 } else {
2473 self.disallow_simple_key();
2474 }
2475 }
2476 self.tokens
2477 .push_back(Token(Span::empty(start_mark), TokenType::Value));
2478
2479 Ok(())
2480 }
2481
2482 fn roll_indent(
2488 &mut self,
2489 col: usize,
2490 number: Option<usize>,
2491 tok: TokenType<'input>,
2492 mark: Marker,
2493 ) {
2494 if self.flow_level > 0 {
2495 return;
2496 }
2497
2498 if self.indent <= col as isize {
2502 if let Some(indent) = self.indents.last() {
2503 if !indent.needs_block_end {
2504 self.indent = indent.indent;
2505 self.indents.pop();
2506 }
2507 }
2508 }
2509
2510 if self.indent < col as isize {
2511 self.indents.push(Indent {
2512 indent: self.indent,
2513 needs_block_end: true,
2514 });
2515 self.indent = col as isize;
2516 let tokens_parsed = self.tokens_parsed;
2517 match number {
2518 Some(n) => self.insert_token(n - tokens_parsed, Token(Span::empty(mark), tok)),
2519 None => self.tokens.push_back(Token(Span::empty(mark), tok)),
2520 }
2521 }
2522 }
2523
2524 fn unroll_indent(&mut self, col: isize) {
2530 if self.flow_level > 0 {
2531 return;
2532 }
2533 while self.indent > col {
2534 let indent = self.indents.pop().unwrap();
2535 self.indent = indent.indent;
2536 if indent.needs_block_end {
2537 self.tokens
2538 .push_back(Token(Span::empty(self.mark), TokenType::BlockEnd));
2539 }
2540 }
2541 }
2542
2543 fn roll_one_col_indent(&mut self) {
2549 if self.flow_level == 0 && self.indents.last().map_or(false, |x| x.needs_block_end) {
2550 self.indents.push(Indent {
2551 indent: self.indent,
2552 needs_block_end: false,
2553 });
2554 self.indent += 1;
2555 }
2556 }
2557
2558 fn unroll_non_block_indents(&mut self) {
2560 while let Some(indent) = self.indents.last() {
2561 if indent.needs_block_end {
2562 break;
2563 }
2564 self.indent = indent.indent;
2565 self.indents.pop();
2566 }
2567 }
2568
2569 fn save_simple_key(&mut self) {
2571 if self.simple_key_allowed {
2572 let required = self.flow_level == 0
2573 && self.indent == (self.mark.col as isize)
2574 && self.indents.last().unwrap().needs_block_end;
2575 let mut sk = SimpleKey::new(self.mark);
2576 sk.possible = true;
2577 sk.required = required;
2578 sk.token_number = self.tokens_parsed + self.tokens.len();
2579
2580 self.simple_keys.pop();
2581 self.simple_keys.push(sk);
2582 }
2583 }
2584
2585 fn remove_simple_key(&mut self) -> ScanResult {
2586 let last = self.simple_keys.last_mut().unwrap();
2587 if last.possible && last.required {
2588 return Err(ScanError::new_str(self.mark, "simple key expected"));
2589 }
2590
2591 last.possible = false;
2592 Ok(())
2593 }
2594
2595 fn is_within_block(&self) -> bool {
2597 !self.indents.is_empty()
2598 }
2599
2600 fn end_implicit_mapping(&mut self, mark: Marker) {
2606 if let Some(implicit_mapping) = self.implicit_flow_mapping_states.last_mut() {
2607 if *implicit_mapping == ImplicitMappingState::Inside {
2608 self.flow_mapping_started = false;
2609 *implicit_mapping = ImplicitMappingState::Possible;
2610 self.tokens
2611 .push_back(Token(Span::empty(mark), TokenType::FlowMappingEnd));
2612 }
2613 }
2614 }
2615}
2616
2617#[derive(PartialEq, Eq)]
2621pub enum Chomping {
2622 Strip,
2624 Clip,
2626 Keep,
2628}
2629
2630#[cfg(test)]
2631mod test {
2632 #[test]
2633 fn test_is_anchor_char() {
2634 use super::is_anchor_char;
2635 assert!(is_anchor_char('x'));
2636 }
2637}