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 ReservedDirective(
247 String,
249 Vec<String>,
251 ),
252}
253
254#[derive(Clone, PartialEq, Debug, Eq)]
256pub struct Token<'input>(pub Span, pub TokenType<'input>);
257
258#[derive(Clone, PartialEq, Debug, Eq)]
293struct SimpleKey {
294 possible: bool,
307 required: bool,
315 token_number: usize,
321 mark: Marker,
323}
324
325impl SimpleKey {
326 fn new(mark: Marker) -> SimpleKey {
328 SimpleKey {
329 possible: false,
330 required: false,
331 token_number: 0,
332 mark,
333 }
334 }
335}
336
337#[derive(Clone, Debug, Default)]
339struct Indent {
340 indent: isize,
342 needs_block_end: bool,
360}
361
362#[derive(Debug, Clone, PartialEq)]
384enum ImplicitMappingState {
385 Possible,
390 Inside,
394}
395
396#[derive(Debug)]
406#[allow(clippy::struct_excessive_bools)]
407pub struct Scanner<'input, T> {
408 input: T,
412 mark: Marker,
414 tokens: VecDeque<Token<'input>>,
421 error: Option<ScanError>,
423
424 stream_start_produced: bool,
426 stream_end_produced: bool,
428 adjacent_value_allowed_at: usize,
431 simple_key_allowed: bool,
435 simple_keys: Vec<SimpleKey>,
440 indent: isize,
442 indents: Vec<Indent>,
444 flow_level: u8,
446 tokens_parsed: usize,
450 token_available: bool,
452 leading_whitespace: bool,
454 flow_mapping_started: bool,
461 implicit_flow_mapping_states: Vec<ImplicitMappingState>,
474 interrupted_plain_by_comment: Option<Marker>,
477 buf_leading_break: String,
478 buf_trailing_breaks: String,
479 buf_whitespaces: String,
480}
481
482impl<T: Input + Clone> Clone for Scanner<'_, T> {
483 fn clone(&self) -> Self {
484 Self {
485 input: self.input.clone(),
486 mark: self.mark,
487 tokens: self.tokens.clone(),
488 error: self.error.clone(),
489 stream_start_produced: self.stream_start_produced,
490 stream_end_produced: self.stream_end_produced,
491 adjacent_value_allowed_at: self.adjacent_value_allowed_at,
492 simple_key_allowed: self.simple_key_allowed,
493 simple_keys: self.simple_keys.clone(),
494 indent: self.indent,
495 indents: self.indents.clone(),
496 flow_level: self.flow_level,
497 tokens_parsed: self.tokens_parsed,
498 token_available: self.token_available,
499 leading_whitespace: self.leading_whitespace,
500 flow_mapping_started: self.flow_mapping_started,
501 implicit_flow_mapping_states: self.implicit_flow_mapping_states.clone(),
502 interrupted_plain_by_comment: self.interrupted_plain_by_comment,
503 buf_leading_break: self.buf_leading_break.clone(),
504 buf_trailing_breaks: self.buf_trailing_breaks.clone(),
505 buf_whitespaces: self.buf_whitespaces.clone(),
506 }
507 }
508}
509
510impl<'input, T: Input> Iterator for Scanner<'input, T> {
511 type Item = Token<'input>;
512
513 fn next(&mut self) -> Option<Self::Item> {
514 if self.error.is_some() {
515 return None;
516 }
517 match self.next_token() {
518 Ok(Some(tok)) => {
519 debug_print!(
520 " \x1B[;32m\u{21B3} {:?} \x1B[;36m{:?}\x1B[;m",
521 tok.1,
522 tok.0
523 );
524 Some(tok)
525 }
526 Ok(tok) => tok,
527 Err(e) => {
528 self.error = Some(e);
529 None
530 }
531 }
532 }
533}
534
535pub type ScanResult = Result<(), ScanError>;
537
538impl<'input, T: Input> Scanner<'input, T> {
539 pub fn new(input: T) -> Self {
541 Scanner {
542 input,
543 mark: Marker::new(0, 1, 0),
544 tokens: VecDeque::new(),
545 error: None,
546
547 stream_start_produced: false,
548 stream_end_produced: false,
549 adjacent_value_allowed_at: 0,
550 simple_key_allowed: true,
551 simple_keys: Vec::new(),
552 indent: -1,
553 indents: Vec::new(),
554 flow_level: 0,
555 tokens_parsed: 0,
556 token_available: false,
557 leading_whitespace: true,
558 flow_mapping_started: false,
559 implicit_flow_mapping_states: vec![],
560 interrupted_plain_by_comment: None,
561
562 buf_leading_break: String::new(),
563 buf_trailing_breaks: String::new(),
564 buf_whitespaces: String::new(),
565 }
566 }
567
568 #[inline]
573 pub fn get_error(&self) -> Option<ScanError> {
574 self.error.clone()
575 }
576
577 #[inline]
579 fn skip_blank(&mut self) {
580 self.input.skip();
581
582 self.mark.index += 1;
583 self.mark.col += 1;
584 }
585
586 #[inline]
588 fn skip_non_blank(&mut self) {
589 self.input.skip();
590
591 self.mark.index += 1;
592 self.mark.col += 1;
593 self.leading_whitespace = false;
594 }
595
596 #[inline]
598 fn skip_n_non_blank(&mut self, count: usize) {
599 self.input.skip_n(count);
600
601 self.mark.index += count;
602 self.mark.col += count;
603 self.leading_whitespace = false;
604 }
605
606 #[inline]
608 fn skip_nl(&mut self) {
609 self.input.skip();
610
611 self.mark.index += 1;
612 self.mark.col = 0;
613 self.mark.line += 1;
614 self.leading_whitespace = true;
615 }
616
617 #[inline]
619 fn skip_linebreak(&mut self) {
620 if self.input.next_2_are('\r', '\n') {
621 self.skip_blank();
624 self.skip_nl();
625 } else if self.input.next_is_break() {
626 self.skip_nl();
627 }
628 }
629
630 #[inline]
632 pub fn stream_started(&self) -> bool {
633 self.stream_start_produced
634 }
635
636 #[inline]
638 pub fn stream_ended(&self) -> bool {
639 self.stream_end_produced
640 }
641
642 #[inline]
644 pub fn mark(&self) -> Marker {
645 self.mark
646 }
647
648 #[inline]
655 fn read_break(&mut self, s: &mut String) {
656 self.skip_break();
657 s.push('\n');
658 }
659
660 #[inline]
665 fn skip_break(&mut self) {
666 let c = self.input.peek();
667 let nc = self.input.peek_nth(1);
668 debug_assert!(is_break(c));
669 if c == '\r' && nc == '\n' {
670 self.skip_blank();
671 }
672 self.skip_nl();
673 }
674
675 fn insert_token(&mut self, pos: usize, tok: Token<'input>) {
677 let old_len = self.tokens.len();
678 assert!(pos <= old_len);
679 self.tokens.insert(pos, tok);
680 }
681
682 fn allow_simple_key(&mut self) {
683 self.simple_key_allowed = true;
684 }
685
686 fn disallow_simple_key(&mut self) {
687 self.simple_key_allowed = false;
688 }
689
690 pub fn fetch_next_token(&mut self) -> ScanResult {
695 self.input.lookahead(1);
696
697 if !self.stream_start_produced {
698 self.fetch_stream_start();
699 return Ok(());
700 }
701 self.skip_to_next_token()?;
702
703 debug_print!(
704 " \x1B[38;5;244m\u{2192} fetch_next_token after whitespace {:?} {:?}\x1B[m",
705 self.mark,
706 self.input.peek()
707 );
708
709 self.stale_simple_keys()?;
710
711 let mark = self.mark;
712 self.unroll_indent(mark.col as isize);
713
714 self.input.lookahead(4);
715
716 if self.input.next_is_z() {
717 self.fetch_stream_end()?;
718 return Ok(());
719 }
720
721 if self.mark.col == 0 {
722 if self.input.next_char_is('%') {
723 return self.fetch_directive();
724 } else if self.input.next_is_document_start() {
725 return self.fetch_document_indicator(TokenType::DocumentStart);
726 } else if self.input.next_is_document_end() {
727 self.fetch_document_indicator(TokenType::DocumentEnd)?;
728 self.skip_ws_to_eol(SkipTabs::Yes)?;
729 if !self.input.next_is_breakz() {
730 return Err(ScanError::new_str(
731 self.mark,
732 "invalid content after document end marker",
733 ));
734 }
735 return Ok(());
736 }
737 }
738
739 if (self.mark.col as isize) < self.indent {
740 return Err(ScanError::new_str(self.mark, "invalid indentation"));
741 }
742
743 let c = self.input.peek();
744 let nc = self.input.peek_nth(1);
745 match c {
746 '[' => self.fetch_flow_collection_start(TokenType::FlowSequenceStart),
747 '{' => self.fetch_flow_collection_start(TokenType::FlowMappingStart),
748 ']' => self.fetch_flow_collection_end(TokenType::FlowSequenceEnd),
749 '}' => self.fetch_flow_collection_end(TokenType::FlowMappingEnd),
750 ',' => self.fetch_flow_entry(),
751 '-' if is_blank_or_breakz(nc) => self.fetch_block_entry(),
752 '?' if is_blank_or_breakz(nc) => self.fetch_key(),
753 ':' if is_blank_or_breakz(nc) => self.fetch_value(),
754 ':' if self.flow_level > 0
755 && (is_flow(nc) || self.mark.index == self.adjacent_value_allowed_at) =>
756 {
757 self.fetch_flow_value()
758 }
759 '*' => self.fetch_anchor(true),
761 '&' => self.fetch_anchor(false),
763 '!' => self.fetch_tag(),
764 '|' if self.flow_level == 0 => self.fetch_block_scalar(true),
766 '>' if self.flow_level == 0 => self.fetch_block_scalar(false),
768 '\'' => self.fetch_flow_scalar(true),
769 '"' => self.fetch_flow_scalar(false),
770 '-' if !is_blank_or_breakz(nc) => self.fetch_plain_scalar(),
772 ':' | '?' if !is_blank_or_breakz(nc) && self.flow_level == 0 => {
773 self.fetch_plain_scalar()
774 }
775 '%' | '@' | '`' => Err(ScanError::new(
776 self.mark,
777 format!("unexpected character: `{c}'"),
778 )),
779 _ => self.fetch_plain_scalar(),
780 }
781 }
782
783 pub fn next_token(&mut self) -> Result<Option<Token<'input>>, ScanError> {
787 if self.stream_end_produced {
788 return Ok(None);
789 }
790
791 if !self.token_available {
792 self.fetch_more_tokens()?;
793 }
794 let Some(t) = self.tokens.pop_front() else {
795 return Err(ScanError::new_str(
796 self.mark,
797 "did not find expected next token",
798 ));
799 };
800 self.token_available = false;
801 self.tokens_parsed += 1;
802
803 if let TokenType::StreamEnd = t.1 {
804 self.stream_end_produced = true;
805 }
806 Ok(Some(t))
807 }
808
809 pub fn fetch_more_tokens(&mut self) -> ScanResult {
813 let mut need_more;
814 loop {
815 if self.tokens.is_empty() {
816 need_more = true;
817 } else {
818 need_more = false;
819 self.stale_simple_keys()?;
821 for sk in &self.simple_keys {
823 if sk.possible && sk.token_number == self.tokens_parsed {
824 need_more = true;
825 break;
826 }
827 }
828 }
829
830 if !need_more {
831 break;
832 }
833 self.fetch_next_token()?;
834 }
835 self.token_available = true;
836
837 Ok(())
838 }
839
840 fn stale_simple_keys(&mut self) -> ScanResult {
848 for sk in &mut self.simple_keys {
849 if sk.possible
850 && self.flow_level == 0
852 && (sk.mark.line < self.mark.line || sk.mark.index + 1024 < self.mark.index)
853 {
854 if sk.required {
855 return Err(ScanError::new_str(self.mark, "simple key expect ':'"));
856 }
857 sk.possible = false;
858 }
859 }
860 Ok(())
861 }
862
863 fn skip_to_next_token(&mut self) -> ScanResult {
869 loop {
870 match self.input.look_ch() {
872 '\t' if self.is_within_block()
879 && self.leading_whitespace
880 && (self.mark.col as isize) < self.indent =>
881 {
882 self.skip_ws_to_eol(SkipTabs::Yes)?;
883 if !self.input.next_is_breakz() {
885 return Err(ScanError::new_str(
886 self.mark,
887 "tabs disallowed within this context (block indentation)",
888 ));
889 }
890 }
891 '\t' | ' ' => self.skip_blank(),
892 '\n' | '\r' => {
893 self.input.lookahead(2);
894 self.skip_linebreak();
895 if self.flow_level == 0 {
896 self.allow_simple_key();
897 }
898 }
899 '#' => {
900 let comment_length = self.input.skip_while_non_breakz();
901 self.mark.index += comment_length;
902 self.mark.col += comment_length;
903 }
904 _ => break,
905 }
906 }
907 if let Some(err_mark) = self.interrupted_plain_by_comment.take() {
910 self.input.lookahead(4);
913 let is_immediate_next_line = self.mark.line == err_mark.line + 1;
917 if self.flow_level == 0
918 && is_immediate_next_line
919 && self.mark.col as isize > self.indent
920 && !self.input.next_is_z()
921 && !self.input.next_is_document_indicator()
922 && self.input.next_can_be_plain_scalar(false)
923 {
924 return Err(ScanError::new_str(
925 err_mark,
926 "comment intercepting the multiline text",
927 ));
928 }
929 }
930 Ok(())
931 }
932
933 fn skip_yaml_whitespace(&mut self) -> ScanResult {
938 let mut need_whitespace = true;
939 loop {
940 match self.input.look_ch() {
941 ' ' => {
942 self.skip_blank();
943
944 need_whitespace = false;
945 }
946 '\n' | '\r' => {
947 self.input.lookahead(2);
948 self.skip_linebreak();
949 if self.flow_level == 0 {
950 self.allow_simple_key();
951 }
952 need_whitespace = false;
953 }
954 '#' => {
955 let comment_length = self.input.skip_while_non_breakz();
956 self.mark.index += comment_length;
957 self.mark.col += comment_length;
958 }
959 _ => break,
960 }
961 }
962
963 if need_whitespace {
964 Err(ScanError::new_str(self.mark(), "expected whitespace"))
965 } else {
966 Ok(())
967 }
968 }
969
970 fn skip_ws_to_eol(&mut self, skip_tabs: SkipTabs) -> Result<SkipTabs, ScanError> {
971 let (n_bytes, result) = self.input.skip_ws_to_eol(skip_tabs);
972 self.mark.col += n_bytes;
973 self.mark.index += n_bytes;
974 result.map_err(|msg| ScanError::new_str(self.mark, msg))
975 }
976
977 fn fetch_stream_start(&mut self) {
978 let mark = self.mark;
979 self.indent = -1;
980 self.stream_start_produced = true;
981 self.allow_simple_key();
982 self.tokens.push_back(Token(
983 Span::empty(mark),
984 TokenType::StreamStart(TEncoding::Utf8),
985 ));
986 self.simple_keys.push(SimpleKey::new(Marker::new(0, 0, 0)));
987 }
988
989 fn fetch_stream_end(&mut self) -> ScanResult {
990 if self.mark.col != 0 {
992 self.mark.col = 0;
993 self.mark.line += 1;
994 }
995
996 for sk in &mut self.simple_keys {
999 if sk.required && sk.possible {
1000 return Err(ScanError::new_str(self.mark, "simple key expected"));
1001 }
1002 sk.possible = false;
1003 }
1004
1005 self.unroll_indent(-1);
1006 self.remove_simple_key()?;
1007 self.disallow_simple_key();
1008
1009 self.tokens
1010 .push_back(Token(Span::empty(self.mark), TokenType::StreamEnd));
1011 Ok(())
1012 }
1013
1014 fn fetch_directive(&mut self) -> ScanResult {
1015 self.unroll_indent(-1);
1016 self.remove_simple_key()?;
1017
1018 self.disallow_simple_key();
1019
1020 let tok = self.scan_directive()?;
1021 self.tokens.push_back(tok);
1022
1023 Ok(())
1024 }
1025
1026 fn scan_directive(&mut self) -> Result<Token<'input>, ScanError> {
1027 let start_mark = self.mark;
1028 self.skip_non_blank();
1029
1030 let name = self.scan_directive_name()?;
1031 let tok = match name.as_ref() {
1032 "YAML" => self.scan_version_directive_value(&start_mark)?,
1033 "TAG" => self.scan_tag_directive_value(&start_mark)?,
1034 _ => {
1035 let mut params = Vec::new();
1036 while self.input.next_is_blank() {
1037 let n_blanks = self.input.skip_while_blank();
1038 self.mark.index += n_blanks;
1039 self.mark.col += n_blanks;
1040
1041 if !is_blank_or_breakz(self.input.peek()) {
1042 let mut param = String::new();
1043 let n_chars = self.input.fetch_while_is_yaml_non_space(&mut param);
1044 self.mark.index += n_chars;
1045 self.mark.col += n_chars;
1046 params.push(param);
1047 }
1048 }
1049
1050 Token(
1051 Span::new(start_mark, self.mark),
1052 TokenType::ReservedDirective(name, params),
1053 )
1054 }
1055 };
1056
1057 self.skip_ws_to_eol(SkipTabs::Yes)?;
1058
1059 if self.input.next_is_breakz() {
1060 self.input.lookahead(2);
1061 self.skip_linebreak();
1062 Ok(tok)
1063 } else {
1064 Err(ScanError::new_str(
1065 start_mark,
1066 "while scanning a directive, did not find expected comment or line break",
1067 ))
1068 }
1069 }
1070
1071 fn scan_version_directive_value(&mut self, mark: &Marker) -> Result<Token<'input>, ScanError> {
1072 let n_blanks = self.input.skip_while_blank();
1073 self.mark.index += n_blanks;
1074 self.mark.col += n_blanks;
1075
1076 let major = self.scan_version_directive_number(mark)?;
1077
1078 if self.input.peek() != '.' {
1079 return Err(ScanError::new_str(
1080 *mark,
1081 "while scanning a YAML directive, did not find expected digit or '.' character",
1082 ));
1083 }
1084 self.skip_non_blank();
1085
1086 let minor = self.scan_version_directive_number(mark)?;
1087
1088 Ok(Token(
1089 Span::new(*mark, self.mark),
1090 TokenType::VersionDirective(major, minor),
1091 ))
1092 }
1093
1094 fn scan_directive_name(&mut self) -> Result<String, ScanError> {
1095 let start_mark = self.mark;
1096 let mut string = String::new();
1097
1098 let n_chars = self.input.fetch_while_is_yaml_non_space(&mut string);
1099 self.mark.index += n_chars;
1100 self.mark.col += n_chars;
1101
1102 if string.is_empty() {
1103 return Err(ScanError::new_str(
1104 start_mark,
1105 "while scanning a directive, could not find expected directive name",
1106 ));
1107 }
1108
1109 if !is_blank_or_breakz(self.input.peek()) {
1110 return Err(ScanError::new_str(
1111 start_mark,
1112 "while scanning a directive, found unexpected non-alphabetical character",
1113 ));
1114 }
1115
1116 Ok(string)
1117 }
1118
1119 fn scan_version_directive_number(&mut self, mark: &Marker) -> Result<u32, ScanError> {
1120 let mut val = 0u32;
1121 let mut length = 0usize;
1122 while let Some(digit) = self.input.look_ch().to_digit(10) {
1123 if length + 1 > 9 {
1124 return Err(ScanError::new_str(
1125 *mark,
1126 "while scanning a YAML directive, found extremely long version number",
1127 ));
1128 }
1129 length += 1;
1130 val = val * 10 + digit;
1131 self.skip_non_blank();
1132 }
1133
1134 if length == 0 {
1135 return Err(ScanError::new_str(
1136 *mark,
1137 "while scanning a YAML directive, did not find expected version number",
1138 ));
1139 }
1140
1141 Ok(val)
1142 }
1143
1144 fn scan_tag_directive_value(&mut self, mark: &Marker) -> Result<Token<'input>, ScanError> {
1145 let n_blanks = self.input.skip_while_blank();
1146 self.mark.index += n_blanks;
1147 self.mark.col += n_blanks;
1148
1149 let handle = self.scan_tag_handle(true, mark)?;
1150
1151 let n_blanks = self.input.skip_while_blank();
1152 self.mark.index += n_blanks;
1153 self.mark.col += n_blanks;
1154
1155 let prefix = self.scan_tag_prefix(mark)?;
1156
1157 self.input.lookahead(1);
1158
1159 if self.input.next_is_blank_or_breakz() {
1160 Ok(Token(
1161 Span::new(*mark, self.mark),
1162 TokenType::TagDirective(handle.into(), prefix.into()),
1163 ))
1164 } else {
1165 Err(ScanError::new_str(
1166 *mark,
1167 "while scanning TAG, did not find expected whitespace or line break",
1168 ))
1169 }
1170 }
1171
1172 fn fetch_tag(&mut self) -> ScanResult {
1173 self.save_simple_key();
1174 self.disallow_simple_key();
1175
1176 let tok = self.scan_tag()?;
1177 self.tokens.push_back(tok);
1178 Ok(())
1179 }
1180
1181 fn scan_tag(&mut self) -> Result<Token<'input>, ScanError> {
1182 let start_mark = self.mark;
1183 let mut handle = String::new();
1184 let mut suffix;
1185
1186 self.input.lookahead(2);
1188
1189 if self.input.nth_char_is(1, '<') {
1190 suffix = self.scan_verbatim_tag(&start_mark)?;
1191 } else {
1192 handle = self.scan_tag_handle(false, &start_mark)?;
1194 if handle.len() >= 2 && handle.starts_with('!') && handle.ends_with('!') {
1196 let is_secondary_handle = handle == "!!";
1198 suffix =
1199 self.scan_tag_shorthand_suffix(false, is_secondary_handle, "", &start_mark)?;
1200 } else {
1201 suffix = self.scan_tag_shorthand_suffix(false, false, &handle, &start_mark)?;
1202 "!".clone_into(&mut handle);
1203 if suffix.is_empty() {
1206 handle.clear();
1207 "!".clone_into(&mut suffix);
1208 }
1209 }
1210 }
1211
1212 if is_blank_or_breakz(self.input.look_ch())
1213 || (self.flow_level > 0 && self.input.next_is_flow())
1214 {
1215 Ok(Token(
1217 Span::new(start_mark, self.mark),
1218 TokenType::Tag(handle, suffix),
1219 ))
1220 } else {
1221 Err(ScanError::new_str(
1222 start_mark,
1223 "while scanning a tag, did not find expected whitespace or line break",
1224 ))
1225 }
1226 }
1227
1228 fn scan_tag_handle(&mut self, directive: bool, mark: &Marker) -> Result<String, ScanError> {
1229 let mut string = String::new();
1230 if self.input.look_ch() != '!' {
1231 return Err(ScanError::new_str(
1232 *mark,
1233 "while scanning a tag, did not find expected '!'",
1234 ));
1235 }
1236
1237 string.push(self.input.peek());
1238 self.skip_non_blank();
1239
1240 let n_chars = self.input.fetch_while_is_alpha(&mut string);
1241 self.mark.index += n_chars;
1242 self.mark.col += n_chars;
1243
1244 if self.input.peek() == '!' {
1246 string.push(self.input.peek());
1247 self.skip_non_blank();
1248 } else if directive && string != "!" {
1249 return Err(ScanError::new_str(
1253 *mark,
1254 "while parsing a tag directive, did not find expected '!'",
1255 ));
1256 }
1257 Ok(string)
1258 }
1259
1260 fn scan_tag_prefix(&mut self, start_mark: &Marker) -> Result<String, ScanError> {
1266 let mut string = String::new();
1267
1268 if self.input.look_ch() == '!' {
1269 string.push(self.input.peek());
1271 self.skip_non_blank();
1272 } else if !is_tag_char(self.input.peek()) {
1273 return Err(ScanError::new_str(
1275 *start_mark,
1276 "invalid global tag character",
1277 ));
1278 } else if self.input.peek() == '%' {
1279 string.push(self.scan_uri_escapes(start_mark)?);
1281 } else {
1282 string.push(self.input.peek());
1284 self.skip_non_blank();
1285 }
1286
1287 while is_uri_char(self.input.look_ch()) {
1288 if self.input.peek() == '%' {
1289 string.push(self.scan_uri_escapes(start_mark)?);
1290 } else {
1291 string.push(self.input.peek());
1292 self.skip_non_blank();
1293 }
1294 }
1295
1296 Ok(string)
1297 }
1298
1299 fn scan_verbatim_tag(&mut self, start_mark: &Marker) -> Result<String, ScanError> {
1303 self.skip_non_blank();
1305 self.skip_non_blank();
1306
1307 let mut string = String::new();
1308 while is_uri_char(self.input.look_ch()) {
1309 if self.input.peek() == '%' {
1310 string.push(self.scan_uri_escapes(start_mark)?);
1311 } else {
1312 string.push(self.input.peek());
1313 self.skip_non_blank();
1314 }
1315 }
1316
1317 if self.input.peek() != '>' {
1318 return Err(ScanError::new_str(
1319 *start_mark,
1320 "while scanning a verbatim tag, did not find the expected '>'",
1321 ));
1322 }
1323 self.skip_non_blank();
1324
1325 Ok(string)
1326 }
1327
1328 fn scan_tag_shorthand_suffix(
1329 &mut self,
1330 _directive: bool,
1331 _is_secondary: bool,
1332 head: &str,
1333 mark: &Marker,
1334 ) -> Result<String, ScanError> {
1335 let mut length = head.len();
1336 let mut string = String::new();
1337
1338 if length > 1 {
1341 string.extend(head.chars().skip(1));
1342 }
1343
1344 while is_tag_char(self.input.look_ch()) {
1345 if self.input.peek() == '%' {
1347 string.push(self.scan_uri_escapes(mark)?);
1348 } else {
1349 string.push(self.input.peek());
1350 self.skip_non_blank();
1351 }
1352
1353 length += 1;
1354 }
1355
1356 if length == 0 {
1357 return Err(ScanError::new_str(
1358 *mark,
1359 "while parsing a tag, did not find expected tag URI",
1360 ));
1361 }
1362
1363 Ok(string)
1364 }
1365
1366 fn scan_uri_escapes(&mut self, mark: &Marker) -> Result<char, ScanError> {
1367 let mut width = 0usize;
1368 let mut code = 0u32;
1369 loop {
1370 self.input.lookahead(3);
1371
1372 let c = self.input.peek_nth(1);
1373 let nc = self.input.peek_nth(2);
1374
1375 if !(self.input.peek() == '%' && is_hex(c) && is_hex(nc)) {
1376 return Err(ScanError::new_str(
1377 *mark,
1378 "while parsing a tag, found an invalid escape sequence",
1379 ));
1380 }
1381
1382 let byte = (as_hex(c) << 4) + as_hex(nc);
1383 if width == 0 {
1384 width = match byte {
1385 _ if byte & 0x80 == 0x00 => 1,
1386 _ if byte & 0xE0 == 0xC0 => 2,
1387 _ if byte & 0xF0 == 0xE0 => 3,
1388 _ if byte & 0xF8 == 0xF0 => 4,
1389 _ => {
1390 return Err(ScanError::new_str(
1391 *mark,
1392 "while parsing a tag, found an incorrect leading UTF-8 byte",
1393 ));
1394 }
1395 };
1396 code = byte;
1397 } else {
1398 if byte & 0xc0 != 0x80 {
1399 return Err(ScanError::new_str(
1400 *mark,
1401 "while parsing a tag, found an incorrect trailing UTF-8 byte",
1402 ));
1403 }
1404 code = (code << 8) + byte;
1405 }
1406
1407 self.skip_n_non_blank(3);
1408
1409 width -= 1;
1410 if width == 0 {
1411 break;
1412 }
1413 }
1414
1415 match char::from_u32(code) {
1416 Some(ch) => Ok(ch),
1417 None => Err(ScanError::new_str(
1418 *mark,
1419 "while parsing a tag, found an invalid UTF-8 codepoint",
1420 )),
1421 }
1422 }
1423
1424 fn fetch_anchor(&mut self, alias: bool) -> ScanResult {
1425 self.save_simple_key();
1426 self.disallow_simple_key();
1427
1428 let tok = self.scan_anchor(alias)?;
1429
1430 self.tokens.push_back(tok);
1431
1432 Ok(())
1433 }
1434
1435 fn scan_anchor(&mut self, alias: bool) -> Result<Token<'input>, ScanError> {
1436 let mut string = String::new();
1437 let start_mark = self.mark;
1438
1439 self.skip_non_blank();
1440 while is_anchor_char(self.input.look_ch()) {
1441 string.push(self.input.peek());
1442 self.skip_non_blank();
1443 }
1444
1445 if string.is_empty() {
1446 return Err(ScanError::new_str(
1447 start_mark,
1448 "while scanning an anchor or alias, did not find expected alphabetic or numeric character",
1449 ));
1450 }
1451
1452 let tok = if alias {
1453 TokenType::Alias(string.into())
1454 } else {
1455 TokenType::Anchor(string.into())
1456 };
1457 Ok(Token(Span::new(start_mark, self.mark), tok))
1458 }
1459
1460 fn fetch_flow_collection_start(&mut self, tok: TokenType<'input>) -> ScanResult {
1461 self.save_simple_key();
1463
1464 self.roll_one_col_indent();
1465 self.increase_flow_level()?;
1466
1467 self.allow_simple_key();
1468
1469 let start_mark = self.mark;
1470 self.skip_non_blank();
1471
1472 if tok == TokenType::FlowMappingStart {
1473 self.flow_mapping_started = true;
1474 } else {
1475 self.implicit_flow_mapping_states
1476 .push(ImplicitMappingState::Possible);
1477 }
1478
1479 self.skip_ws_to_eol(SkipTabs::Yes)?;
1480
1481 self.tokens
1482 .push_back(Token(Span::new(start_mark, self.mark), tok));
1483 Ok(())
1484 }
1485
1486 fn fetch_flow_collection_end(&mut self, tok: TokenType<'input>) -> ScanResult {
1487 if self.flow_level == 0 {
1489 return Err(ScanError::new_str(self.mark, "misplaced bracket"));
1490 }
1491
1492 self.remove_simple_key()?;
1493 self.decrease_flow_level();
1494
1495 self.disallow_simple_key();
1496
1497 if matches!(tok, TokenType::FlowSequenceEnd) {
1498 self.end_implicit_mapping(self.mark);
1499 self.implicit_flow_mapping_states.pop();
1501 }
1502
1503 let start_mark = self.mark;
1504 self.skip_non_blank();
1505 self.skip_ws_to_eol(SkipTabs::Yes)?;
1506
1507 if self.flow_level > 0 {
1513 self.adjacent_value_allowed_at = self.mark.index;
1514 }
1515
1516 self.tokens
1517 .push_back(Token(Span::new(start_mark, self.mark), tok));
1518 Ok(())
1519 }
1520
1521 fn fetch_flow_entry(&mut self) -> ScanResult {
1523 self.remove_simple_key()?;
1524 self.allow_simple_key();
1525
1526 self.end_implicit_mapping(self.mark);
1527
1528 let start_mark = self.mark;
1529 self.skip_non_blank();
1530 self.skip_ws_to_eol(SkipTabs::Yes)?;
1531
1532 self.tokens.push_back(Token(
1533 Span::new(start_mark, self.mark),
1534 TokenType::FlowEntry,
1535 ));
1536 Ok(())
1537 }
1538
1539 fn increase_flow_level(&mut self) -> ScanResult {
1540 self.simple_keys.push(SimpleKey::new(Marker::new(0, 0, 0)));
1541 self.flow_level = self
1542 .flow_level
1543 .checked_add(1)
1544 .ok_or_else(|| ScanError::new_str(self.mark, "recursion limit exceeded"))?;
1545 Ok(())
1546 }
1547
1548 fn decrease_flow_level(&mut self) {
1549 if self.flow_level > 0 {
1550 self.flow_level -= 1;
1551 self.simple_keys.pop().unwrap();
1552 }
1553 }
1554
1555 fn fetch_block_entry(&mut self) -> ScanResult {
1561 if self.flow_level > 0 {
1562 return Err(ScanError::new_str(
1564 self.mark,
1565 r#""-" is only valid inside a block"#,
1566 ));
1567 }
1568 if !self.simple_key_allowed {
1570 return Err(ScanError::new_str(
1571 self.mark,
1572 "block sequence entries are not allowed in this context",
1573 ));
1574 }
1575
1576 if let Some(Token(span, TokenType::Anchor(..) | TokenType::Tag(..))) = self.tokens.back() {
1578 if self.mark.col == 0 && span.start.col == 0 && self.indent > -1 {
1579 return Err(ScanError::new_str(
1580 span.start,
1581 "invalid indentation for anchor",
1582 ));
1583 }
1584 }
1585
1586 let mark = self.mark;
1588 self.skip_non_blank();
1589
1590 self.roll_indent(mark.col, None, TokenType::BlockSequenceStart, mark);
1592 let found_tabs = self.skip_ws_to_eol(SkipTabs::Yes)?.found_tabs();
1593 self.input.lookahead(2);
1594 if found_tabs && self.input.next_char_is('-') && is_blank_or_breakz(self.input.peek_nth(1))
1595 {
1596 return Err(ScanError::new_str(
1597 self.mark,
1598 "'-' must be followed by a valid YAML whitespace",
1599 ));
1600 }
1601
1602 self.skip_ws_to_eol(SkipTabs::No)?;
1603 self.input.lookahead(1);
1604 if self.input.next_is_break() || self.input.next_is_flow() {
1605 self.roll_one_col_indent();
1606 }
1607
1608 self.remove_simple_key()?;
1609 self.allow_simple_key();
1610
1611 self.tokens
1612 .push_back(Token(Span::empty(self.mark), TokenType::BlockEntry));
1613
1614 Ok(())
1615 }
1616
1617 fn fetch_document_indicator(&mut self, t: TokenType<'input>) -> ScanResult {
1618 self.unroll_indent(-1);
1619 self.remove_simple_key()?;
1620 self.disallow_simple_key();
1621
1622 let mark = self.mark;
1623
1624 self.skip_n_non_blank(3);
1625
1626 self.tokens.push_back(Token(Span::new(mark, self.mark), t));
1627 Ok(())
1628 }
1629
1630 fn fetch_block_scalar(&mut self, literal: bool) -> ScanResult {
1631 self.save_simple_key();
1632 self.allow_simple_key();
1633 let tok = self.scan_block_scalar(literal)?;
1634
1635 self.tokens.push_back(tok);
1636 Ok(())
1637 }
1638
1639 #[allow(clippy::too_many_lines)]
1640 fn scan_block_scalar(&mut self, literal: bool) -> Result<Token<'input>, ScanError> {
1641 let start_mark = self.mark;
1642 let mut chomping = Chomping::Clip;
1643 let mut increment: usize = 0;
1644 let mut indent: usize = 0;
1645 let mut trailing_blank: bool;
1646 let mut leading_blank: bool = false;
1647 let style = if literal {
1648 ScalarStyle::Literal
1649 } else {
1650 ScalarStyle::Folded
1651 };
1652
1653 let mut string = String::new();
1654 let mut leading_break = String::new();
1655 let mut trailing_breaks = String::new();
1656 let mut chomping_break = String::new();
1657
1658 self.skip_non_blank();
1660 self.unroll_non_block_indents();
1661
1662 if self.input.look_ch() == '+' || self.input.peek() == '-' {
1663 if self.input.peek() == '+' {
1664 chomping = Chomping::Keep;
1665 } else {
1666 chomping = Chomping::Strip;
1667 }
1668 self.skip_non_blank();
1669 self.input.lookahead(1);
1670 if self.input.next_is_digit() {
1671 if self.input.peek() == '0' {
1672 return Err(ScanError::new_str(
1673 start_mark,
1674 "while scanning a block scalar, found an indentation indicator equal to 0",
1675 ));
1676 }
1677 increment = (self.input.peek() as usize) - ('0' as usize);
1678 self.skip_non_blank();
1679 }
1680 } else if self.input.next_is_digit() {
1681 if self.input.peek() == '0' {
1682 return Err(ScanError::new_str(
1683 start_mark,
1684 "while scanning a block scalar, found an indentation indicator equal to 0",
1685 ));
1686 }
1687
1688 increment = (self.input.peek() as usize) - ('0' as usize);
1689 self.skip_non_blank();
1690 self.input.lookahead(1);
1691 if self.input.peek() == '+' || self.input.peek() == '-' {
1692 if self.input.peek() == '+' {
1693 chomping = Chomping::Keep;
1694 } else {
1695 chomping = Chomping::Strip;
1696 }
1697 self.skip_non_blank();
1698 }
1699 }
1700
1701 self.skip_ws_to_eol(SkipTabs::Yes)?;
1702
1703 self.input.lookahead(1);
1705 if !self.input.next_is_breakz() {
1706 return Err(ScanError::new_str(
1707 start_mark,
1708 "while scanning a block scalar, did not find expected comment or line break",
1709 ));
1710 }
1711
1712 if self.input.next_is_break() {
1713 self.input.lookahead(2);
1714 self.read_break(&mut chomping_break);
1715 }
1716
1717 if self.input.look_ch() == '\t' {
1718 return Err(ScanError::new_str(
1719 start_mark,
1720 "a block scalar content cannot start with a tab",
1721 ));
1722 }
1723
1724 if increment > 0 {
1725 indent = if self.indent >= 0 {
1726 (self.indent + increment as isize) as usize
1727 } else {
1728 increment
1729 }
1730 }
1731
1732 if indent == 0 {
1734 self.skip_block_scalar_first_line_indent(&mut indent, &mut trailing_breaks);
1735 } else {
1736 self.skip_block_scalar_indent(indent, &mut trailing_breaks);
1737 }
1738
1739 if self.input.next_is_z() {
1744 let contents = match chomping {
1745 Chomping::Strip => String::new(),
1747 _ if self.mark.line == start_mark.line() => String::new(),
1749 Chomping::Clip => chomping_break,
1752 Chomping::Keep if trailing_breaks.is_empty() => chomping_break,
1755 Chomping::Keep => trailing_breaks,
1757 };
1758 return Ok(Token(
1759 Span::new(start_mark, self.mark),
1760 TokenType::Scalar(style, contents.into()),
1761 ));
1762 }
1763
1764 if self.mark.col < indent && (self.mark.col as isize) > self.indent {
1765 return Err(ScanError::new_str(
1766 self.mark,
1767 "wrongly indented line in block scalar",
1768 ));
1769 }
1770
1771 let mut line_buffer = String::with_capacity(100);
1772 let start_mark = self.mark;
1773 while self.mark.col == indent && !self.input.next_is_z() {
1774 if indent == 0 {
1775 self.input.lookahead(4);
1776 if self.input.next_is_document_end() {
1777 break;
1778 }
1779 }
1780
1781 trailing_blank = self.input.next_is_blank();
1783 if !literal && !leading_break.is_empty() && !leading_blank && !trailing_blank {
1784 string.push_str(&trailing_breaks);
1785 if trailing_breaks.is_empty() {
1786 string.push(' ');
1787 }
1788 } else {
1789 string.push_str(&leading_break);
1790 string.push_str(&trailing_breaks);
1791 }
1792
1793 leading_break.clear();
1794 trailing_breaks.clear();
1795
1796 leading_blank = self.input.next_is_blank();
1797
1798 self.scan_block_scalar_content_line(&mut string, &mut line_buffer);
1799
1800 self.input.lookahead(2);
1802 if self.input.next_is_z() {
1803 break;
1804 }
1805
1806 self.read_break(&mut leading_break);
1807
1808 self.skip_block_scalar_indent(indent, &mut trailing_breaks);
1810 }
1811
1812 if chomping != Chomping::Strip {
1814 string.push_str(&leading_break);
1815 if self.input.next_is_z() && self.mark.col >= indent.max(1) {
1819 string.push('\n');
1820 }
1821 }
1822
1823 if chomping == Chomping::Keep {
1824 string.push_str(&trailing_breaks);
1825 }
1826
1827 Ok(Token(
1828 Span::new(start_mark, self.mark),
1829 TokenType::Scalar(style, string.into()),
1830 ))
1831 }
1832
1833 fn scan_block_scalar_content_line(&mut self, string: &mut String, line_buffer: &mut String) {
1843 while !self.input.buf_is_empty() && !self.input.next_is_breakz() {
1845 string.push(self.input.peek());
1846 self.skip_blank();
1852 }
1853
1854 if self.input.buf_is_empty() {
1857 while let Some(c) = self.input.raw_read_non_breakz_ch() {
1863 line_buffer.push(c);
1864 }
1865
1866 let n_chars = line_buffer.chars().count();
1868 self.mark.col += n_chars;
1869 self.mark.index += n_chars;
1870
1871 string.reserve(line_buffer.len());
1873 string.push_str(line_buffer);
1874 line_buffer.clear();
1876 }
1877 }
1878
1879 fn skip_block_scalar_indent(&mut self, indent: usize, breaks: &mut String) {
1881 loop {
1882 if indent < self.input.bufmaxlen() - 2 {
1884 self.input.lookahead(self.input.bufmaxlen());
1885 while self.mark.col < indent && self.input.peek() == ' ' {
1886 self.skip_blank();
1887 }
1888 } else {
1889 loop {
1890 self.input.lookahead(self.input.bufmaxlen());
1891 while !self.input.buf_is_empty()
1892 && self.mark.col < indent
1893 && self.input.peek() == ' '
1894 {
1895 self.skip_blank();
1896 }
1897 if self.mark.col == indent
1901 || (!self.input.buf_is_empty() && self.input.peek() != ' ')
1902 {
1903 break;
1904 }
1905 }
1906 self.input.lookahead(2);
1907 }
1908
1909 if self.input.next_is_break() {
1911 self.read_break(breaks);
1912 } else {
1913 break;
1915 }
1916 }
1917 }
1918
1919 fn skip_block_scalar_first_line_indent(&mut self, indent: &mut usize, breaks: &mut String) {
1924 let mut max_indent = 0;
1925 loop {
1926 while self.input.look_ch() == ' ' {
1928 self.skip_blank();
1929 }
1930
1931 if self.mark.col > max_indent {
1932 max_indent = self.mark.col;
1933 }
1934
1935 if self.input.next_is_break() {
1936 self.input.lookahead(2);
1938 self.read_break(breaks);
1939 } else {
1940 break;
1942 }
1943 }
1944
1945 *indent = max_indent.max((self.indent + 1) as usize);
1954 if self.indent > 0 {
1955 *indent = (*indent).max(1);
1956 }
1957 }
1958
1959 fn fetch_flow_scalar(&mut self, single: bool) -> ScanResult {
1960 self.save_simple_key();
1961 self.disallow_simple_key();
1962
1963 let tok = self.scan_flow_scalar(single)?;
1964
1965 self.skip_to_next_token()?;
1968 self.adjacent_value_allowed_at = self.mark.index;
1969
1970 self.tokens.push_back(tok);
1971 Ok(())
1972 }
1973
1974 #[allow(clippy::too_many_lines)]
1975 fn scan_flow_scalar(&mut self, single: bool) -> Result<Token<'input>, ScanError> {
1976 let start_mark = self.mark;
1977
1978 let mut string = String::new();
1979 let mut leading_break = String::new();
1980 let mut trailing_breaks = String::new();
1981 let mut whitespaces = String::new();
1982 let mut leading_blanks;
1983
1984 self.skip_non_blank();
1986
1987 loop {
1988 self.input.lookahead(4);
1990
1991 if self.mark.col == 0 && self.input.next_is_document_indicator() {
1992 return Err(ScanError::new_str(
1993 start_mark,
1994 "while scanning a quoted scalar, found unexpected document indicator",
1995 ));
1996 }
1997
1998 if self.input.next_is_z() {
1999 return Err(ScanError::new_str(
2000 start_mark,
2001 "while scanning a quoted scalar, found unexpected end of stream",
2002 ));
2003 }
2004
2005 if (self.mark.col as isize) < self.indent {
2006 return Err(ScanError::new_str(
2007 start_mark,
2008 "invalid indentation in quoted scalar",
2009 ));
2010 }
2011
2012 leading_blanks = false;
2013 self.consume_flow_scalar_non_whitespace_chars(
2014 single,
2015 &mut string,
2016 &mut leading_blanks,
2017 &start_mark,
2018 )?;
2019
2020 match self.input.look_ch() {
2021 '\'' if single => break,
2022 '"' if !single => break,
2023 _ => {}
2024 }
2025
2026 while self.input.next_is_blank() || self.input.next_is_break() {
2028 if self.input.next_is_blank() {
2029 if leading_blanks {
2031 if self.input.peek() == '\t' && (self.mark.col as isize) < self.indent {
2032 return Err(ScanError::new_str(
2033 self.mark,
2034 "tab cannot be used as indentation",
2035 ));
2036 }
2037 self.skip_blank();
2038 } else {
2039 whitespaces.push(self.input.peek());
2040 self.skip_blank();
2041 }
2042 } else {
2043 self.input.lookahead(2);
2044 if leading_blanks {
2046 self.read_break(&mut trailing_breaks);
2047 } else {
2048 whitespaces.clear();
2049 self.read_break(&mut leading_break);
2050 leading_blanks = true;
2051 }
2052 }
2053 self.input.lookahead(1);
2054 }
2055
2056 if leading_blanks {
2058 if leading_break.is_empty() {
2059 string.push_str(&leading_break);
2060 string.push_str(&trailing_breaks);
2061 trailing_breaks.clear();
2062 leading_break.clear();
2063 } else {
2064 if trailing_breaks.is_empty() {
2065 string.push(' ');
2066 } else {
2067 string.push_str(&trailing_breaks);
2068 trailing_breaks.clear();
2069 }
2070 leading_break.clear();
2071 }
2072 } else {
2073 string.push_str(&whitespaces);
2074 whitespaces.clear();
2075 }
2076 } self.skip_non_blank();
2080 self.skip_ws_to_eol(SkipTabs::Yes)?;
2082 match self.input.peek() {
2083 ',' | '}' | ']' if self.flow_level > 0 => {}
2085 c if is_breakz(c) => {}
2087 ':' if self.flow_level == 0 && start_mark.line == self.mark.line => {}
2090 ':' if self.flow_level > 0 => {}
2092 _ => {
2093 return Err(ScanError::new_str(
2094 self.mark,
2095 "invalid trailing content after double-quoted scalar",
2096 ));
2097 }
2098 }
2099
2100 let style = if single {
2101 ScalarStyle::SingleQuoted
2102 } else {
2103 ScalarStyle::DoubleQuoted
2104 };
2105 Ok(Token(
2106 Span::new(start_mark, self.mark),
2107 TokenType::Scalar(style, string.into()),
2108 ))
2109 }
2110
2111 fn consume_flow_scalar_non_whitespace_chars(
2120 &mut self,
2121 single: bool,
2122 string: &mut String,
2123 leading_blanks: &mut bool,
2124 start_mark: &Marker,
2125 ) -> Result<(), ScanError> {
2126 self.input.lookahead(2);
2127 while !is_blank_or_breakz(self.input.peek()) {
2128 match self.input.peek() {
2129 '\'' if self.input.peek_nth(1) == '\'' && single => {
2131 string.push('\'');
2132 self.skip_n_non_blank(2);
2133 }
2134 '\'' if single => break,
2136 '"' if !single => break,
2137 '\\' if !single && is_break(self.input.peek_nth(1)) => {
2139 self.input.lookahead(3);
2140 self.skip_non_blank();
2141 self.skip_linebreak();
2142 *leading_blanks = true;
2143 break;
2144 }
2145 '\\' if !single => {
2147 string.push(self.resolve_flow_scalar_escape_sequence(start_mark)?);
2148 }
2149 c => {
2150 string.push(c);
2151 self.skip_non_blank();
2152 }
2153 }
2154 self.input.lookahead(2);
2155 }
2156 Ok(())
2157 }
2158
2159 fn resolve_flow_scalar_escape_sequence(
2166 &mut self,
2167 start_mark: &Marker,
2168 ) -> Result<char, ScanError> {
2169 let mut code_length = 0usize;
2170 let mut ret = '\0';
2171
2172 match self.input.peek_nth(1) {
2173 '0' => ret = '\0',
2174 'a' => ret = '\x07',
2175 'b' => ret = '\x08',
2176 't' | '\t' => ret = '\t',
2177 'n' => ret = '\n',
2178 'v' => ret = '\x0b',
2179 'f' => ret = '\x0c',
2180 'r' => ret = '\x0d',
2181 'e' => ret = '\x1b',
2182 ' ' => ret = '\x20',
2183 '"' => ret = '"',
2184 '/' => ret = '/',
2185 '\\' => ret = '\\',
2186 'N' => ret = char::from_u32(0x85).unwrap(),
2188 '_' => ret = char::from_u32(0xA0).unwrap(),
2190 'L' => ret = char::from_u32(0x2028).unwrap(),
2192 'P' => ret = char::from_u32(0x2029).unwrap(),
2194 'x' => code_length = 2,
2195 'u' => code_length = 4,
2196 'U' => code_length = 8,
2197 _ => {
2198 return Err(ScanError::new_str(
2199 *start_mark,
2200 "while parsing a quoted scalar, found unknown escape character",
2201 ));
2202 }
2203 }
2204 self.skip_n_non_blank(2);
2205
2206 if code_length > 0 {
2208 self.input.lookahead(code_length);
2209 let mut value = 0u32;
2210 for i in 0..code_length {
2211 let c = self.input.peek_nth(i);
2212 if !is_hex(c) {
2213 return Err(ScanError::new_str(
2214 *start_mark,
2215 "while parsing a quoted scalar, did not find expected hexadecimal number",
2216 ));
2217 }
2218 value = (value << 4) + as_hex(c);
2219 }
2220
2221 let Some(ch) = char::from_u32(value) else {
2222 return Err(ScanError::new_str(
2223 *start_mark,
2224 "while parsing a quoted scalar, found invalid Unicode character escape code",
2225 ));
2226 };
2227 ret = ch;
2228
2229 self.skip_n_non_blank(code_length);
2230 }
2231 Ok(ret)
2232 }
2233
2234 fn fetch_plain_scalar(&mut self) -> ScanResult {
2235 self.save_simple_key();
2236 self.disallow_simple_key();
2237
2238 let tok = self.scan_plain_scalar()?;
2239
2240 self.tokens.push_back(tok);
2241 Ok(())
2242 }
2243
2244 #[allow(clippy::too_many_lines)]
2249 fn scan_plain_scalar(&mut self) -> Result<Token<'input>, ScanError> {
2250 self.unroll_non_block_indents();
2251 let indent = self.indent + 1;
2252 let start_mark = self.mark;
2253
2254 if self.flow_level > 0 && (start_mark.col as isize) < indent {
2255 return Err(ScanError::new_str(
2256 start_mark,
2257 "invalid indentation in flow construct",
2258 ));
2259 }
2260
2261 let mut string = String::with_capacity(32);
2262 self.buf_whitespaces.clear();
2263 self.buf_leading_break.clear();
2264 self.buf_trailing_breaks.clear();
2265 let mut end_mark = self.mark;
2266
2267 loop {
2268 self.input.lookahead(4);
2269 if (self.mark.col == 0 && self.input.next_is_document_indicator())
2270 || self.input.peek() == '#'
2271 {
2272 if self.input.peek() == '#'
2277 && !string.is_empty()
2278 && !self.buf_whitespaces.is_empty()
2279 && self.flow_level == 0
2280 {
2281 self.interrupted_plain_by_comment = Some(self.mark);
2282 }
2283 break;
2284 }
2285
2286 if self.flow_level > 0 && self.input.peek() == '-' && is_flow(self.input.peek_nth(1)) {
2287 return Err(ScanError::new_str(
2288 self.mark,
2289 "plain scalar cannot start with '-' followed by ,[]{}",
2290 ));
2291 }
2292
2293 if !self.input.next_is_blank_or_breakz()
2294 && self.input.next_can_be_plain_scalar(self.flow_level > 0)
2295 {
2296 if self.leading_whitespace {
2297 if self.buf_leading_break.is_empty() {
2298 string.push_str(&self.buf_leading_break);
2299 string.push_str(&self.buf_trailing_breaks);
2300 self.buf_trailing_breaks.clear();
2301 self.buf_leading_break.clear();
2302 } else {
2303 if self.buf_trailing_breaks.is_empty() {
2304 string.push(' ');
2305 } else {
2306 string.push_str(&self.buf_trailing_breaks);
2307 self.buf_trailing_breaks.clear();
2308 }
2309 self.buf_leading_break.clear();
2310 }
2311 self.leading_whitespace = false;
2312 } else if !self.buf_whitespaces.is_empty() {
2313 string.push_str(&self.buf_whitespaces);
2314 self.buf_whitespaces.clear();
2315 }
2316
2317 string.push(self.input.peek());
2319 self.skip_non_blank();
2320 string.reserve(self.input.bufmaxlen());
2321
2322 let mut end = false;
2324 while !end {
2325 self.input.lookahead(self.input.bufmaxlen());
2329 for _ in 0..self.input.bufmaxlen() - 1 {
2330 if self.input.next_is_blank_or_breakz()
2331 || !self.input.next_can_be_plain_scalar(self.flow_level > 0)
2332 {
2333 end = true;
2334 break;
2335 }
2336 string.push(self.input.peek());
2337 self.skip_non_blank();
2338 }
2339 }
2340 end_mark = self.mark;
2341 }
2342
2343 if !(self.input.next_is_blank() || self.input.next_is_break()) {
2348 break;
2349 }
2350
2351 self.input.lookahead(2);
2353 while self.input.next_is_blank_or_break() {
2354 if self.input.next_is_blank() {
2355 if !self.leading_whitespace {
2356 self.buf_whitespaces.push(self.input.peek());
2357 self.skip_blank();
2358 } else if (self.mark.col as isize) < indent && self.input.peek() == '\t' {
2359 self.skip_ws_to_eol(SkipTabs::Yes)?;
2362 if !self.input.next_is_breakz() {
2363 return Err(ScanError::new_str(
2364 start_mark,
2365 "while scanning a plain scalar, found a tab",
2366 ));
2367 }
2368 } else {
2369 self.skip_blank();
2370 }
2371 } else {
2372 if self.leading_whitespace {
2374 self.skip_break();
2375 self.buf_trailing_breaks.push('\n');
2376 } else {
2377 self.buf_whitespaces.clear();
2378 self.skip_break();
2379 self.buf_leading_break.push('\n');
2380 self.leading_whitespace = true;
2381 }
2382 }
2383 self.input.lookahead(2);
2384 }
2385
2386 if self.flow_level == 0 && (self.mark.col as isize) < indent {
2388 break;
2389 }
2390 }
2391
2392 if self.leading_whitespace {
2393 self.allow_simple_key();
2394 }
2395
2396 if string.is_empty() {
2397 Err(ScanError::new_str(
2401 start_mark,
2402 "unexpected end of plain scalar",
2403 ))
2404 } else {
2405 Ok(Token(
2406 Span::new(start_mark, end_mark),
2407 TokenType::Scalar(ScalarStyle::Plain, string.into()),
2408 ))
2409 }
2410 }
2411
2412 fn fetch_key(&mut self) -> ScanResult {
2413 let start_mark = self.mark;
2414 if self.flow_level == 0 {
2415 if !self.simple_key_allowed {
2417 return Err(ScanError::new_str(
2418 self.mark,
2419 "mapping keys are not allowed in this context",
2420 ));
2421 }
2422 self.roll_indent(
2423 start_mark.col,
2424 None,
2425 TokenType::BlockMappingStart,
2426 start_mark,
2427 );
2428 } else {
2429 self.flow_mapping_started = true;
2431 }
2432
2433 self.remove_simple_key()?;
2434
2435 if self.flow_level == 0 {
2436 self.allow_simple_key();
2437 } else {
2438 self.disallow_simple_key();
2439 }
2440
2441 self.skip_non_blank();
2442 self.skip_yaml_whitespace()?;
2443 if self.input.peek() == '\t' {
2444 return Err(ScanError::new_str(
2445 self.mark(),
2446 "tabs disallowed in this context",
2447 ));
2448 }
2449 self.tokens
2450 .push_back(Token(Span::new(start_mark, self.mark), TokenType::Key));
2451 Ok(())
2452 }
2453
2454 fn fetch_flow_value(&mut self) -> ScanResult {
2462 let nc = self.input.peek_nth(1);
2463
2464 if self.mark.index != self.adjacent_value_allowed_at && (nc == '[' || nc == '{') {
2476 return Err(ScanError::new_str(
2477 self.mark,
2478 "':' may not precede any of `[{` in flow mapping",
2479 ));
2480 }
2481
2482 self.fetch_value()
2483 }
2484
2485 fn fetch_value(&mut self) -> ScanResult {
2487 let sk = self.simple_keys.last().unwrap().clone();
2488 let start_mark = self.mark;
2489 let is_implicit_flow_mapping =
2490 !self.implicit_flow_mapping_states.is_empty() && !self.flow_mapping_started;
2491 if is_implicit_flow_mapping {
2492 *self.implicit_flow_mapping_states.last_mut().unwrap() = ImplicitMappingState::Inside;
2493 }
2494
2495 self.skip_non_blank();
2497 if self.input.look_ch() == '\t'
2498 && !self.skip_ws_to_eol(SkipTabs::Yes)?.has_valid_yaml_ws()
2499 && (self.input.peek() == '-' || self.input.next_is_alpha())
2500 {
2501 return Err(ScanError::new_str(
2502 self.mark,
2503 "':' must be followed by a valid YAML whitespace",
2504 ));
2505 }
2506
2507 if sk.possible {
2508 let tok = Token(Span::empty(sk.mark), TokenType::Key);
2510 self.insert_token(sk.token_number - self.tokens_parsed, tok);
2511 if is_implicit_flow_mapping {
2512 if sk.mark.line < start_mark.line {
2513 return Err(ScanError::new_str(
2514 start_mark,
2515 "illegal placement of ':' indicator",
2516 ));
2517 }
2518 self.insert_token(
2519 sk.token_number - self.tokens_parsed,
2520 Token(Span::empty(sk.mark), TokenType::FlowMappingStart),
2521 );
2522 }
2523
2524 self.roll_indent(
2526 sk.mark.col,
2527 Some(sk.token_number),
2528 TokenType::BlockMappingStart,
2529 sk.mark,
2530 );
2531 self.roll_one_col_indent();
2532
2533 self.simple_keys.last_mut().unwrap().possible = false;
2534 self.disallow_simple_key();
2535 } else {
2536 if is_implicit_flow_mapping {
2537 self.tokens
2538 .push_back(Token(Span::empty(start_mark), TokenType::FlowMappingStart));
2539 }
2540 if self.flow_level == 0 {
2542 if !self.simple_key_allowed {
2543 return Err(ScanError::new_str(
2544 start_mark,
2545 "mapping values are not allowed in this context",
2546 ));
2547 }
2548
2549 self.roll_indent(
2550 start_mark.col,
2551 None,
2552 TokenType::BlockMappingStart,
2553 start_mark,
2554 );
2555 }
2556 self.roll_one_col_indent();
2557
2558 if self.flow_level == 0 {
2559 self.allow_simple_key();
2560 } else {
2561 self.disallow_simple_key();
2562 }
2563 }
2564 self.tokens
2565 .push_back(Token(Span::empty(start_mark), TokenType::Value));
2566
2567 Ok(())
2568 }
2569
2570 fn roll_indent(
2576 &mut self,
2577 col: usize,
2578 number: Option<usize>,
2579 tok: TokenType<'input>,
2580 mark: Marker,
2581 ) {
2582 if self.flow_level > 0 {
2583 return;
2584 }
2585
2586 if self.indent <= col as isize {
2590 if let Some(indent) = self.indents.last() {
2591 if !indent.needs_block_end {
2592 self.indent = indent.indent;
2593 self.indents.pop();
2594 }
2595 }
2596 }
2597
2598 if self.indent < col as isize {
2599 self.indents.push(Indent {
2600 indent: self.indent,
2601 needs_block_end: true,
2602 });
2603 self.indent = col as isize;
2604 let tokens_parsed = self.tokens_parsed;
2605 match number {
2606 Some(n) => self.insert_token(n - tokens_parsed, Token(Span::empty(mark), tok)),
2607 None => self.tokens.push_back(Token(Span::empty(mark), tok)),
2608 }
2609 }
2610 }
2611
2612 fn unroll_indent(&mut self, col: isize) {
2618 if self.flow_level > 0 {
2619 return;
2620 }
2621 while self.indent > col {
2622 let indent = self.indents.pop().unwrap();
2623 self.indent = indent.indent;
2624 if indent.needs_block_end {
2625 self.tokens
2626 .push_back(Token(Span::empty(self.mark), TokenType::BlockEnd));
2627 }
2628 }
2629 }
2630
2631 fn roll_one_col_indent(&mut self) {
2637 if self.flow_level == 0 && self.indents.last().is_some_and(|x| x.needs_block_end) {
2638 self.indents.push(Indent {
2639 indent: self.indent,
2640 needs_block_end: false,
2641 });
2642 self.indent += 1;
2643 }
2644 }
2645
2646 fn unroll_non_block_indents(&mut self) {
2648 while let Some(indent) = self.indents.last() {
2649 if indent.needs_block_end {
2650 break;
2651 }
2652 self.indent = indent.indent;
2653 self.indents.pop();
2654 }
2655 }
2656
2657 fn save_simple_key(&mut self) {
2659 if self.simple_key_allowed {
2660 let required = self.flow_level == 0
2661 && self.indent == (self.mark.col as isize)
2662 && self.indents.last().unwrap().needs_block_end;
2663 let mut sk = SimpleKey::new(self.mark);
2664 sk.possible = true;
2665 sk.required = required;
2666 sk.token_number = self.tokens_parsed + self.tokens.len();
2667
2668 self.simple_keys.pop();
2669 self.simple_keys.push(sk);
2670 }
2671 }
2672
2673 fn remove_simple_key(&mut self) -> ScanResult {
2674 let last = self.simple_keys.last_mut().unwrap();
2675 if last.possible && last.required {
2676 return Err(ScanError::new_str(self.mark, "simple key expected"));
2677 }
2678
2679 last.possible = false;
2680 Ok(())
2681 }
2682
2683 fn is_within_block(&self) -> bool {
2685 !self.indents.is_empty()
2686 }
2687
2688 fn end_implicit_mapping(&mut self, mark: Marker) {
2694 if let Some(implicit_mapping) = self.implicit_flow_mapping_states.last_mut() {
2695 if *implicit_mapping == ImplicitMappingState::Inside {
2696 self.flow_mapping_started = false;
2697 *implicit_mapping = ImplicitMappingState::Possible;
2698 self.tokens
2699 .push_back(Token(Span::empty(mark), TokenType::FlowMappingEnd));
2700 }
2701 }
2702 }
2703}
2704
2705#[derive(PartialEq, Eq)]
2709pub enum Chomping {
2710 Strip,
2712 Clip,
2714 Keep,
2716}
2717
2718#[cfg(test)]
2719mod test {
2720 #[test]
2721 fn test_is_anchor_char() {
2722 use super::is_anchor_char;
2723 assert!(is_anchor_char('x'));
2724 }
2725}