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 if self.input.peek_opt() == Some('\0') {
718 return Err(ScanError::new_str(self.mark, "found unprintable character"));
719 }
720 self.fetch_stream_end()?;
721 return Ok(());
722 }
723
724 if self.mark.col == 0 {
725 if self.input.next_char_is('%') {
726 return self.fetch_directive();
727 } else if self.input.next_is_document_start() {
728 return self.fetch_document_indicator(TokenType::DocumentStart);
729 } else if self.input.next_is_document_end() {
730 self.fetch_document_indicator(TokenType::DocumentEnd)?;
731 self.skip_ws_to_eol(SkipTabs::Yes)?;
732 if !self.input.next_is_breakz() {
733 return Err(ScanError::new_str(
734 self.mark,
735 "invalid content after document end marker",
736 ));
737 }
738 return Ok(());
739 }
740 }
741
742 if (self.mark.col as isize) < self.indent {
743 return Err(ScanError::new_str(self.mark, "invalid indentation"));
744 }
745
746 let c = self.input.peek();
747 let nc = self.input.peek_nth(1);
748 match c {
749 '[' => self.fetch_flow_collection_start(TokenType::FlowSequenceStart),
750 '{' => self.fetch_flow_collection_start(TokenType::FlowMappingStart),
751 ']' => self.fetch_flow_collection_end(TokenType::FlowSequenceEnd),
752 '}' => self.fetch_flow_collection_end(TokenType::FlowMappingEnd),
753 ',' => self.fetch_flow_entry(),
754 '-' if is_blank_or_breakz(nc) => self.fetch_block_entry(),
755 '?' if is_blank_or_breakz(nc) => self.fetch_key(),
756 ':' if is_blank_or_breakz(nc) => self.fetch_value(),
757 ':' if self.flow_level > 0
758 && (is_flow(nc) || self.mark.index == self.adjacent_value_allowed_at) =>
759 {
760 self.fetch_flow_value()
761 }
762 '*' => self.fetch_anchor(true),
764 '&' => self.fetch_anchor(false),
766 '!' => self.fetch_tag(),
767 '|' if self.flow_level == 0 => self.fetch_block_scalar(true),
769 '>' if self.flow_level == 0 => self.fetch_block_scalar(false),
771 '\'' => self.fetch_flow_scalar(true),
772 '"' => self.fetch_flow_scalar(false),
773 '-' if !is_blank_or_breakz(nc) => self.fetch_plain_scalar(),
775 ':' | '?' if !is_blank_or_breakz(nc) && self.flow_level == 0 => {
776 self.fetch_plain_scalar()
777 }
778 '%' | '@' | '`' => Err(ScanError::new(
779 self.mark,
780 format!("unexpected character: `{c}'"),
781 )),
782 _ => self.fetch_plain_scalar(),
783 }
784 }
785
786 pub fn next_token(&mut self) -> Result<Option<Token<'input>>, ScanError> {
790 if self.stream_end_produced {
791 return Ok(None);
792 }
793
794 if !self.token_available {
795 self.fetch_more_tokens()?;
796 }
797 let Some(t) = self.tokens.pop_front() else {
798 return Err(ScanError::new_str(
799 self.mark,
800 "did not find expected next token",
801 ));
802 };
803 self.token_available = false;
804 self.tokens_parsed += 1;
805
806 if let TokenType::StreamEnd = t.1 {
807 self.stream_end_produced = true;
808 }
809 Ok(Some(t))
810 }
811
812 pub fn fetch_more_tokens(&mut self) -> ScanResult {
816 let mut need_more;
817 loop {
818 if self.tokens.is_empty() {
819 need_more = true;
820 } else {
821 need_more = false;
822 self.stale_simple_keys()?;
824 for sk in &self.simple_keys {
826 if sk.possible && sk.token_number == self.tokens_parsed {
827 need_more = true;
828 break;
829 }
830 }
831 }
832
833 if !need_more {
834 break;
835 }
836 self.fetch_next_token()?;
837 }
838 self.token_available = true;
839
840 Ok(())
841 }
842
843 fn stale_simple_keys(&mut self) -> ScanResult {
851 for sk in &mut self.simple_keys {
852 if sk.possible
853 && self.flow_level == 0
855 && (sk.mark.line < self.mark.line || sk.mark.index + 1024 < self.mark.index)
856 {
857 if sk.required {
858 return Err(ScanError::new_str(self.mark, "simple key expect ':'"));
859 }
860 sk.possible = false;
861 }
862 }
863 Ok(())
864 }
865
866 fn skip_to_next_token(&mut self) -> ScanResult {
872 loop {
873 match self.input.look_ch() {
875 '\t' if self.is_within_block()
882 && self.leading_whitespace
883 && (self.mark.col as isize) < self.indent =>
884 {
885 self.skip_ws_to_eol(SkipTabs::Yes)?;
886 if !self.input.next_is_breakz() {
888 return Err(ScanError::new_str(
889 self.mark,
890 "tabs disallowed within this context (block indentation)",
891 ));
892 }
893 }
894 '\t' | ' ' => self.skip_blank(),
895 '\n' | '\r' => {
896 self.input.lookahead(2);
897 self.skip_linebreak();
898 if self.flow_level == 0 {
899 self.allow_simple_key();
900 }
901 }
902 '#' => {
903 let comment_length = self.input.skip_while_non_breakz();
904 self.mark.index += comment_length;
905 self.mark.col += comment_length;
906 }
907 _ => break,
908 }
909 }
910 if let Some(err_mark) = self.interrupted_plain_by_comment.take() {
913 self.input.lookahead(4);
916 let is_immediate_next_line = self.mark.line == err_mark.line + 1;
920 if self.flow_level == 0
921 && is_immediate_next_line
922 && self.mark.col as isize > self.indent
923 && !self.input.next_is_z()
924 && !self.input.next_is_document_indicator()
925 && self.input.next_can_be_plain_scalar(false)
926 {
927 return Err(ScanError::new_str(
928 err_mark,
929 "comment intercepting the multiline text",
930 ));
931 }
932 }
933 Ok(())
934 }
935
936 fn skip_yaml_whitespace(&mut self) -> ScanResult {
941 let mut need_whitespace = true;
942 loop {
943 match self.input.look_ch() {
944 ' ' => {
945 self.skip_blank();
946
947 need_whitespace = false;
948 }
949 '\n' | '\r' => {
950 self.input.lookahead(2);
951 self.skip_linebreak();
952 if self.flow_level == 0 {
953 self.allow_simple_key();
954 }
955 need_whitespace = false;
956 }
957 '#' => {
958 let comment_length = self.input.skip_while_non_breakz();
959 self.mark.index += comment_length;
960 self.mark.col += comment_length;
961 }
962 _ => break,
963 }
964 }
965
966 if need_whitespace {
967 Err(ScanError::new_str(self.mark(), "expected whitespace"))
968 } else {
969 Ok(())
970 }
971 }
972
973 fn skip_ws_to_eol(&mut self, skip_tabs: SkipTabs) -> Result<SkipTabs, ScanError> {
974 let (n_bytes, result) = self.input.skip_ws_to_eol(skip_tabs);
975 self.mark.col += n_bytes;
976 self.mark.index += n_bytes;
977 result.map_err(|msg| ScanError::new_str(self.mark, msg))
978 }
979
980 fn fetch_stream_start(&mut self) {
981 let mark = self.mark;
982 self.indent = -1;
983 self.stream_start_produced = true;
984 self.allow_simple_key();
985 self.tokens.push_back(Token(
986 Span::empty(mark),
987 TokenType::StreamStart(TEncoding::Utf8),
988 ));
989 self.simple_keys.push(SimpleKey::new(Marker::new(0, 0, 0)));
990 }
991
992 fn fetch_stream_end(&mut self) -> ScanResult {
993 if self.mark.col != 0 {
995 self.mark.col = 0;
996 self.mark.line += 1;
997 }
998
999 for sk in &mut self.simple_keys {
1002 if sk.required && sk.possible {
1003 return Err(ScanError::new_str(self.mark, "simple key expected"));
1004 }
1005 sk.possible = false;
1006 }
1007
1008 self.unroll_indent(-1);
1009 self.remove_simple_key()?;
1010 self.disallow_simple_key();
1011
1012 self.tokens
1013 .push_back(Token(Span::empty(self.mark), TokenType::StreamEnd));
1014 Ok(())
1015 }
1016
1017 fn fetch_directive(&mut self) -> ScanResult {
1018 self.unroll_indent(-1);
1019 self.remove_simple_key()?;
1020
1021 self.disallow_simple_key();
1022
1023 let tok = self.scan_directive()?;
1024 self.tokens.push_back(tok);
1025
1026 Ok(())
1027 }
1028
1029 fn scan_directive(&mut self) -> Result<Token<'input>, ScanError> {
1030 let start_mark = self.mark;
1031 self.skip_non_blank();
1032
1033 let name = self.scan_directive_name()?;
1034 let tok = match name.as_ref() {
1035 "YAML" => self.scan_version_directive_value(&start_mark)?,
1036 "TAG" => self.scan_tag_directive_value(&start_mark)?,
1037 _ => {
1038 let mut params = Vec::new();
1039 while self.input.next_is_blank() {
1040 let n_blanks = self.input.skip_while_blank();
1041 self.mark.index += n_blanks;
1042 self.mark.col += n_blanks;
1043
1044 if !is_blank_or_breakz(self.input.peek()) {
1045 let mut param = String::new();
1046 let n_chars = self.input.fetch_while_is_yaml_non_space(&mut param);
1047 self.mark.index += n_chars;
1048 self.mark.col += n_chars;
1049 params.push(param);
1050 }
1051 }
1052
1053 Token(
1054 Span::new(start_mark, self.mark),
1055 TokenType::ReservedDirective(name, params),
1056 )
1057 }
1058 };
1059
1060 self.skip_ws_to_eol(SkipTabs::Yes)?;
1061
1062 if self.input.next_is_breakz() {
1063 self.input.lookahead(2);
1064 self.skip_linebreak();
1065 Ok(tok)
1066 } else {
1067 Err(ScanError::new_str(
1068 start_mark,
1069 "while scanning a directive, did not find expected comment or line break",
1070 ))
1071 }
1072 }
1073
1074 fn scan_version_directive_value(&mut self, mark: &Marker) -> Result<Token<'input>, ScanError> {
1075 let n_blanks = self.input.skip_while_blank();
1076 self.mark.index += n_blanks;
1077 self.mark.col += n_blanks;
1078
1079 let major = self.scan_version_directive_number(mark)?;
1080
1081 if self.input.peek() != '.' {
1082 return Err(ScanError::new_str(
1083 *mark,
1084 "while scanning a YAML directive, did not find expected digit or '.' character",
1085 ));
1086 }
1087 self.skip_non_blank();
1088
1089 let minor = self.scan_version_directive_number(mark)?;
1090
1091 Ok(Token(
1092 Span::new(*mark, self.mark),
1093 TokenType::VersionDirective(major, minor),
1094 ))
1095 }
1096
1097 fn scan_directive_name(&mut self) -> Result<String, ScanError> {
1098 let start_mark = self.mark;
1099 let mut string = String::new();
1100
1101 let n_chars = self.input.fetch_while_is_yaml_non_space(&mut string);
1102 self.mark.index += n_chars;
1103 self.mark.col += n_chars;
1104
1105 if string.is_empty() {
1106 return Err(ScanError::new_str(
1107 start_mark,
1108 "while scanning a directive, could not find expected directive name",
1109 ));
1110 }
1111
1112 if !is_blank_or_breakz(self.input.peek()) {
1113 return Err(ScanError::new_str(
1114 start_mark,
1115 "while scanning a directive, found unexpected non-alphabetical character",
1116 ));
1117 }
1118
1119 Ok(string)
1120 }
1121
1122 fn scan_version_directive_number(&mut self, mark: &Marker) -> Result<u32, ScanError> {
1123 let mut val = 0u32;
1124 let mut length = 0usize;
1125 while let Some(digit) = self.input.look_ch().to_digit(10) {
1126 if length + 1 > 9 {
1127 return Err(ScanError::new_str(
1128 *mark,
1129 "while scanning a YAML directive, found extremely long version number",
1130 ));
1131 }
1132 length += 1;
1133 val = val * 10 + digit;
1134 self.skip_non_blank();
1135 }
1136
1137 if length == 0 {
1138 return Err(ScanError::new_str(
1139 *mark,
1140 "while scanning a YAML directive, did not find expected version number",
1141 ));
1142 }
1143
1144 Ok(val)
1145 }
1146
1147 fn scan_tag_directive_value(&mut self, mark: &Marker) -> Result<Token<'input>, ScanError> {
1148 let n_blanks = self.input.skip_while_blank();
1149 self.mark.index += n_blanks;
1150 self.mark.col += n_blanks;
1151
1152 let handle = self.scan_tag_handle(true, mark)?;
1153
1154 let n_blanks = self.input.skip_while_blank();
1155 self.mark.index += n_blanks;
1156 self.mark.col += n_blanks;
1157
1158 let prefix = self.scan_tag_prefix(mark)?;
1159
1160 self.input.lookahead(1);
1161
1162 if self.input.next_is_blank_or_breakz() {
1163 Ok(Token(
1164 Span::new(*mark, self.mark),
1165 TokenType::TagDirective(handle.into(), prefix.into()),
1166 ))
1167 } else {
1168 Err(ScanError::new_str(
1169 *mark,
1170 "while scanning TAG, did not find expected whitespace or line break",
1171 ))
1172 }
1173 }
1174
1175 fn fetch_tag(&mut self) -> ScanResult {
1176 self.save_simple_key();
1177 self.disallow_simple_key();
1178
1179 let tok = self.scan_tag()?;
1180 self.tokens.push_back(tok);
1181 Ok(())
1182 }
1183
1184 fn scan_tag(&mut self) -> Result<Token<'input>, ScanError> {
1185 let start_mark = self.mark;
1186 let mut handle = String::new();
1187 let mut suffix;
1188
1189 self.input.lookahead(2);
1191
1192 if self.input.nth_char_is(1, '<') {
1193 suffix = self.scan_verbatim_tag(&start_mark)?;
1194 } else {
1195 handle = self.scan_tag_handle(false, &start_mark)?;
1197 if handle.len() >= 2 && handle.starts_with('!') && handle.ends_with('!') {
1199 let is_secondary_handle = handle == "!!";
1201 suffix =
1202 self.scan_tag_shorthand_suffix(false, is_secondary_handle, "", &start_mark)?;
1203 } else {
1204 suffix = self.scan_tag_shorthand_suffix(false, false, &handle, &start_mark)?;
1205 "!".clone_into(&mut handle);
1206 if suffix.is_empty() {
1209 handle.clear();
1210 "!".clone_into(&mut suffix);
1211 }
1212 }
1213 }
1214
1215 if is_blank_or_breakz(self.input.look_ch())
1216 || (self.flow_level > 0 && self.input.next_is_flow())
1217 {
1218 Ok(Token(
1220 Span::new(start_mark, self.mark),
1221 TokenType::Tag(handle, suffix),
1222 ))
1223 } else {
1224 Err(ScanError::new_str(
1225 start_mark,
1226 "while scanning a tag, did not find expected whitespace or line break",
1227 ))
1228 }
1229 }
1230
1231 fn scan_tag_handle(&mut self, directive: bool, mark: &Marker) -> Result<String, ScanError> {
1232 let mut string = String::new();
1233 if self.input.look_ch() != '!' {
1234 return Err(ScanError::new_str(
1235 *mark,
1236 "while scanning a tag, did not find expected '!'",
1237 ));
1238 }
1239
1240 string.push(self.input.peek());
1241 self.skip_non_blank();
1242
1243 let n_chars = self.input.fetch_while_is_alpha(&mut string);
1244 self.mark.index += n_chars;
1245 self.mark.col += n_chars;
1246
1247 if self.input.peek() == '!' {
1249 string.push(self.input.peek());
1250 self.skip_non_blank();
1251 } else if directive && string != "!" {
1252 return Err(ScanError::new_str(
1256 *mark,
1257 "while parsing a tag directive, did not find expected '!'",
1258 ));
1259 }
1260 Ok(string)
1261 }
1262
1263 fn scan_tag_prefix(&mut self, start_mark: &Marker) -> Result<String, ScanError> {
1269 let mut string = String::new();
1270
1271 if self.input.look_ch() == '!' {
1272 string.push(self.input.peek());
1274 self.skip_non_blank();
1275 } else if !is_tag_char(self.input.peek()) {
1276 return Err(ScanError::new_str(
1278 *start_mark,
1279 "invalid global tag character",
1280 ));
1281 } else if self.input.peek() == '%' {
1282 string.push(self.scan_uri_escapes(start_mark)?);
1284 } else {
1285 string.push(self.input.peek());
1287 self.skip_non_blank();
1288 }
1289
1290 while is_uri_char(self.input.look_ch()) {
1291 if self.input.peek() == '%' {
1292 string.push(self.scan_uri_escapes(start_mark)?);
1293 } else {
1294 string.push(self.input.peek());
1295 self.skip_non_blank();
1296 }
1297 }
1298
1299 Ok(string)
1300 }
1301
1302 fn scan_verbatim_tag(&mut self, start_mark: &Marker) -> Result<String, ScanError> {
1306 self.skip_non_blank();
1308 self.skip_non_blank();
1309
1310 let mut string = String::new();
1311 while is_uri_char(self.input.look_ch()) {
1312 if self.input.peek() == '%' {
1313 string.push(self.scan_uri_escapes(start_mark)?);
1314 } else {
1315 string.push(self.input.peek());
1316 self.skip_non_blank();
1317 }
1318 }
1319
1320 if self.input.peek() != '>' {
1321 return Err(ScanError::new_str(
1322 *start_mark,
1323 "while scanning a verbatim tag, did not find the expected '>'",
1324 ));
1325 }
1326 self.skip_non_blank();
1327
1328 Ok(string)
1329 }
1330
1331 fn scan_tag_shorthand_suffix(
1332 &mut self,
1333 _directive: bool,
1334 _is_secondary: bool,
1335 head: &str,
1336 mark: &Marker,
1337 ) -> Result<String, ScanError> {
1338 let mut length = head.len();
1339 let mut string = String::new();
1340
1341 if length > 1 {
1344 string.extend(head.chars().skip(1));
1345 }
1346
1347 while is_tag_char(self.input.look_ch()) {
1348 if self.input.peek() == '%' {
1350 string.push(self.scan_uri_escapes(mark)?);
1351 } else {
1352 string.push(self.input.peek());
1353 self.skip_non_blank();
1354 }
1355
1356 length += 1;
1357 }
1358
1359 if length == 0 {
1360 return Err(ScanError::new_str(
1361 *mark,
1362 "while parsing a tag, did not find expected tag URI",
1363 ));
1364 }
1365
1366 Ok(string)
1367 }
1368
1369 fn scan_uri_escapes(&mut self, mark: &Marker) -> Result<char, ScanError> {
1370 let mut width = 0usize;
1371 let mut code = 0u32;
1372 loop {
1373 self.input.lookahead(3);
1374
1375 let c = self.input.peek_nth(1);
1376 let nc = self.input.peek_nth(2);
1377
1378 if !(self.input.peek() == '%' && is_hex(c) && is_hex(nc)) {
1379 return Err(ScanError::new_str(
1380 *mark,
1381 "while parsing a tag, found an invalid escape sequence",
1382 ));
1383 }
1384
1385 let byte = (as_hex(c) << 4) + as_hex(nc);
1386 if width == 0 {
1387 width = match byte {
1388 _ if byte & 0x80 == 0x00 => 1,
1389 _ if byte & 0xE0 == 0xC0 => 2,
1390 _ if byte & 0xF0 == 0xE0 => 3,
1391 _ if byte & 0xF8 == 0xF0 => 4,
1392 _ => {
1393 return Err(ScanError::new_str(
1394 *mark,
1395 "while parsing a tag, found an incorrect leading UTF-8 byte",
1396 ));
1397 }
1398 };
1399 code = byte;
1400 } else {
1401 if byte & 0xc0 != 0x80 {
1402 return Err(ScanError::new_str(
1403 *mark,
1404 "while parsing a tag, found an incorrect trailing UTF-8 byte",
1405 ));
1406 }
1407 code = (code << 8) + byte;
1408 }
1409
1410 self.skip_n_non_blank(3);
1411
1412 width -= 1;
1413 if width == 0 {
1414 break;
1415 }
1416 }
1417
1418 match char::from_u32(code) {
1419 Some(ch) => Ok(ch),
1420 None => Err(ScanError::new_str(
1421 *mark,
1422 "while parsing a tag, found an invalid UTF-8 codepoint",
1423 )),
1424 }
1425 }
1426
1427 fn fetch_anchor(&mut self, alias: bool) -> ScanResult {
1428 self.save_simple_key();
1429 self.disallow_simple_key();
1430
1431 let tok = self.scan_anchor(alias)?;
1432
1433 self.tokens.push_back(tok);
1434
1435 Ok(())
1436 }
1437
1438 fn scan_anchor(&mut self, alias: bool) -> Result<Token<'input>, ScanError> {
1439 let mut string = String::new();
1440 let start_mark = self.mark;
1441
1442 self.skip_non_blank();
1443 while is_anchor_char(self.input.look_ch()) {
1444 string.push(self.input.peek());
1445 self.skip_non_blank();
1446 }
1447
1448 if string.is_empty() {
1449 return Err(ScanError::new_str(
1450 start_mark,
1451 "while scanning an anchor or alias, did not find expected alphabetic or numeric character",
1452 ));
1453 }
1454
1455 let tok = if alias {
1456 TokenType::Alias(string.into())
1457 } else {
1458 TokenType::Anchor(string.into())
1459 };
1460 Ok(Token(Span::new(start_mark, self.mark), tok))
1461 }
1462
1463 fn fetch_flow_collection_start(&mut self, tok: TokenType<'input>) -> ScanResult {
1464 self.save_simple_key();
1466
1467 self.roll_one_col_indent();
1468 self.increase_flow_level()?;
1469
1470 self.allow_simple_key();
1471
1472 let start_mark = self.mark;
1473 self.skip_non_blank();
1474
1475 if tok == TokenType::FlowMappingStart {
1476 self.flow_mapping_started = true;
1477 } else {
1478 self.implicit_flow_mapping_states
1479 .push(ImplicitMappingState::Possible);
1480 }
1481
1482 self.skip_ws_to_eol(SkipTabs::Yes)?;
1483
1484 self.tokens
1485 .push_back(Token(Span::new(start_mark, self.mark), tok));
1486 Ok(())
1487 }
1488
1489 fn fetch_flow_collection_end(&mut self, tok: TokenType<'input>) -> ScanResult {
1490 if self.flow_level == 0 {
1492 return Err(ScanError::new_str(self.mark, "misplaced bracket"));
1493 }
1494
1495 self.remove_simple_key()?;
1496 self.decrease_flow_level();
1497
1498 self.disallow_simple_key();
1499
1500 if matches!(tok, TokenType::FlowSequenceEnd) {
1501 self.end_implicit_mapping(self.mark);
1502 self.implicit_flow_mapping_states.pop();
1504 }
1505
1506 let start_mark = self.mark;
1507 self.skip_non_blank();
1508 self.skip_ws_to_eol(SkipTabs::Yes)?;
1509
1510 if self.flow_level > 0 {
1516 self.adjacent_value_allowed_at = self.mark.index;
1517 }
1518
1519 self.tokens
1520 .push_back(Token(Span::new(start_mark, self.mark), tok));
1521 Ok(())
1522 }
1523
1524 fn fetch_flow_entry(&mut self) -> ScanResult {
1526 self.remove_simple_key()?;
1527 self.allow_simple_key();
1528
1529 self.end_implicit_mapping(self.mark);
1530
1531 let start_mark = self.mark;
1532 self.skip_non_blank();
1533 self.skip_ws_to_eol(SkipTabs::Yes)?;
1534
1535 self.tokens.push_back(Token(
1536 Span::new(start_mark, self.mark),
1537 TokenType::FlowEntry,
1538 ));
1539 Ok(())
1540 }
1541
1542 fn increase_flow_level(&mut self) -> ScanResult {
1543 self.simple_keys.push(SimpleKey::new(Marker::new(0, 0, 0)));
1544 self.flow_level = self
1545 .flow_level
1546 .checked_add(1)
1547 .ok_or_else(|| ScanError::new_str(self.mark, "recursion limit exceeded"))?;
1548 Ok(())
1549 }
1550
1551 fn decrease_flow_level(&mut self) {
1552 if self.flow_level > 0 {
1553 self.flow_level -= 1;
1554 self.simple_keys.pop().unwrap();
1555 }
1556 }
1557
1558 fn fetch_block_entry(&mut self) -> ScanResult {
1564 if self.flow_level > 0 {
1565 return Err(ScanError::new_str(
1567 self.mark,
1568 r#""-" is only valid inside a block"#,
1569 ));
1570 }
1571 if !self.simple_key_allowed {
1573 return Err(ScanError::new_str(
1574 self.mark,
1575 "block sequence entries are not allowed in this context",
1576 ));
1577 }
1578
1579 if let Some(Token(span, TokenType::Anchor(..) | TokenType::Tag(..))) = self.tokens.back() {
1581 if self.mark.col == 0 && span.start.col == 0 && self.indent > -1 {
1582 return Err(ScanError::new_str(
1583 span.start,
1584 "invalid indentation for anchor",
1585 ));
1586 }
1587 }
1588
1589 let mark = self.mark;
1591 self.skip_non_blank();
1592
1593 self.roll_indent(mark.col, None, TokenType::BlockSequenceStart, mark);
1595 let found_tabs = self.skip_ws_to_eol(SkipTabs::Yes)?.found_tabs();
1596 self.input.lookahead(2);
1597 if found_tabs && self.input.next_char_is('-') && is_blank_or_breakz(self.input.peek_nth(1))
1598 {
1599 return Err(ScanError::new_str(
1600 self.mark,
1601 "'-' must be followed by a valid YAML whitespace",
1602 ));
1603 }
1604
1605 self.skip_ws_to_eol(SkipTabs::No)?;
1606 self.input.lookahead(1);
1607 if self.input.next_is_break() || self.input.next_is_flow() {
1608 self.roll_one_col_indent();
1609 }
1610
1611 self.remove_simple_key()?;
1612 self.allow_simple_key();
1613
1614 self.tokens
1615 .push_back(Token(Span::empty(self.mark), TokenType::BlockEntry));
1616
1617 Ok(())
1618 }
1619
1620 fn fetch_document_indicator(&mut self, t: TokenType<'input>) -> ScanResult {
1621 self.unroll_indent(-1);
1622 self.remove_simple_key()?;
1623 self.disallow_simple_key();
1624
1625 let mark = self.mark;
1626
1627 self.skip_n_non_blank(3);
1628
1629 self.tokens.push_back(Token(Span::new(mark, self.mark), t));
1630 Ok(())
1631 }
1632
1633 fn fetch_block_scalar(&mut self, literal: bool) -> ScanResult {
1634 self.save_simple_key();
1635 self.allow_simple_key();
1636 let tok = self.scan_block_scalar(literal)?;
1637
1638 self.tokens.push_back(tok);
1639 Ok(())
1640 }
1641
1642 #[allow(clippy::too_many_lines)]
1643 fn scan_block_scalar(&mut self, literal: bool) -> Result<Token<'input>, ScanError> {
1644 let start_mark = self.mark;
1645 let mut chomping = Chomping::Clip;
1646 let mut increment: usize = 0;
1647 let mut indent: usize = 0;
1648 let mut trailing_blank: bool;
1649 let mut leading_blank: bool = false;
1650 let style = if literal {
1651 ScalarStyle::Literal
1652 } else {
1653 ScalarStyle::Folded
1654 };
1655
1656 let mut string = String::new();
1657 let mut leading_break = String::new();
1658 let mut trailing_breaks = String::new();
1659 let mut chomping_break = String::new();
1660
1661 self.skip_non_blank();
1663 self.unroll_non_block_indents();
1664
1665 if self.input.look_ch() == '+' || self.input.peek() == '-' {
1666 if self.input.peek() == '+' {
1667 chomping = Chomping::Keep;
1668 } else {
1669 chomping = Chomping::Strip;
1670 }
1671 self.skip_non_blank();
1672 self.input.lookahead(1);
1673 if self.input.next_is_digit() {
1674 if self.input.peek() == '0' {
1675 return Err(ScanError::new_str(
1676 start_mark,
1677 "while scanning a block scalar, found an indentation indicator equal to 0",
1678 ));
1679 }
1680 increment = (self.input.peek() as usize) - ('0' as usize);
1681 self.skip_non_blank();
1682 }
1683 } else if self.input.next_is_digit() {
1684 if self.input.peek() == '0' {
1685 return Err(ScanError::new_str(
1686 start_mark,
1687 "while scanning a block scalar, found an indentation indicator equal to 0",
1688 ));
1689 }
1690
1691 increment = (self.input.peek() as usize) - ('0' as usize);
1692 self.skip_non_blank();
1693 self.input.lookahead(1);
1694 if self.input.peek() == '+' || self.input.peek() == '-' {
1695 if self.input.peek() == '+' {
1696 chomping = Chomping::Keep;
1697 } else {
1698 chomping = Chomping::Strip;
1699 }
1700 self.skip_non_blank();
1701 }
1702 }
1703
1704 self.skip_ws_to_eol(SkipTabs::Yes)?;
1705
1706 self.input.lookahead(1);
1708 if !self.input.next_is_breakz() {
1709 return Err(ScanError::new_str(
1710 start_mark,
1711 "while scanning a block scalar, did not find expected comment or line break",
1712 ));
1713 }
1714
1715 if self.input.next_is_break() {
1716 self.input.lookahead(2);
1717 self.read_break(&mut chomping_break);
1718 }
1719
1720 if self.input.look_ch() == '\t' {
1721 return Err(ScanError::new_str(
1722 start_mark,
1723 "a block scalar content cannot start with a tab",
1724 ));
1725 }
1726
1727 if increment > 0 {
1728 indent = if self.indent >= 0 {
1729 (self.indent + increment as isize) as usize
1730 } else {
1731 increment
1732 }
1733 }
1734
1735 if indent == 0 {
1737 self.skip_block_scalar_first_line_indent(&mut indent, &mut trailing_breaks);
1738 } else {
1739 self.skip_block_scalar_indent(indent, &mut trailing_breaks);
1740 }
1741
1742 if self.input.next_is_z() {
1747 let contents = match chomping {
1748 Chomping::Strip => String::new(),
1750 _ if self.mark.line == start_mark.line() => String::new(),
1752 Chomping::Clip => chomping_break,
1755 Chomping::Keep if trailing_breaks.is_empty() => chomping_break,
1758 Chomping::Keep => trailing_breaks,
1760 };
1761 return Ok(Token(
1762 Span::new(start_mark, self.mark),
1763 TokenType::Scalar(style, contents.into()),
1764 ));
1765 }
1766
1767 if self.mark.col < indent && (self.mark.col as isize) > self.indent {
1768 return Err(ScanError::new_str(
1769 self.mark,
1770 "wrongly indented line in block scalar",
1771 ));
1772 }
1773
1774 let mut line_buffer = String::with_capacity(100);
1775 let start_mark = self.mark;
1776 while self.mark.col == indent && !self.input.next_is_z() {
1777 if indent == 0 {
1778 self.input.lookahead(4);
1779 if self.input.next_is_document_end() {
1780 break;
1781 }
1782 }
1783
1784 trailing_blank = self.input.next_is_blank();
1786 if !literal && !leading_break.is_empty() && !leading_blank && !trailing_blank {
1787 string.push_str(&trailing_breaks);
1788 if trailing_breaks.is_empty() {
1789 string.push(' ');
1790 }
1791 } else {
1792 string.push_str(&leading_break);
1793 string.push_str(&trailing_breaks);
1794 }
1795
1796 leading_break.clear();
1797 trailing_breaks.clear();
1798
1799 leading_blank = self.input.next_is_blank();
1800
1801 self.scan_block_scalar_content_line(&mut string, &mut line_buffer);
1802
1803 self.input.lookahead(2);
1805 if self.input.next_is_z() {
1806 break;
1807 }
1808
1809 self.read_break(&mut leading_break);
1810
1811 self.skip_block_scalar_indent(indent, &mut trailing_breaks);
1813 }
1814
1815 if chomping != Chomping::Strip {
1817 string.push_str(&leading_break);
1818 if self.input.next_is_z() && self.mark.col >= indent.max(1) {
1822 string.push('\n');
1823 }
1824 }
1825
1826 if chomping == Chomping::Keep {
1827 string.push_str(&trailing_breaks);
1828 }
1829
1830 Ok(Token(
1831 Span::new(start_mark, self.mark),
1832 TokenType::Scalar(style, string.into()),
1833 ))
1834 }
1835
1836 fn scan_block_scalar_content_line(&mut self, string: &mut String, line_buffer: &mut String) {
1846 while !self.input.buf_is_empty() && !self.input.next_is_breakz() {
1848 string.push(self.input.peek());
1849 self.skip_blank();
1855 }
1856
1857 if self.input.buf_is_empty() {
1860 while let Some(c) = self.input.raw_read_non_breakz_ch() {
1866 line_buffer.push(c);
1867 }
1868
1869 let n_chars = line_buffer.chars().count();
1871 self.mark.col += n_chars;
1872 self.mark.index += n_chars;
1873
1874 string.reserve(line_buffer.len());
1876 string.push_str(line_buffer);
1877 line_buffer.clear();
1879 }
1880 }
1881
1882 fn skip_block_scalar_indent(&mut self, indent: usize, breaks: &mut String) {
1884 loop {
1885 if indent < self.input.bufmaxlen() - 2 {
1887 self.input.lookahead(self.input.bufmaxlen());
1888 while self.mark.col < indent && self.input.peek() == ' ' {
1889 self.skip_blank();
1890 }
1891 } else {
1892 loop {
1893 self.input.lookahead(self.input.bufmaxlen());
1894 while !self.input.buf_is_empty()
1895 && self.mark.col < indent
1896 && self.input.peek() == ' '
1897 {
1898 self.skip_blank();
1899 }
1900 if self.mark.col == indent
1904 || (!self.input.buf_is_empty() && self.input.peek() != ' ')
1905 {
1906 break;
1907 }
1908 }
1909 self.input.lookahead(2);
1910 }
1911
1912 if self.input.next_is_break() {
1914 self.read_break(breaks);
1915 } else {
1916 break;
1918 }
1919 }
1920 }
1921
1922 fn skip_block_scalar_first_line_indent(&mut self, indent: &mut usize, breaks: &mut String) {
1927 let mut max_indent = 0;
1928 loop {
1929 while self.input.look_ch() == ' ' {
1931 self.skip_blank();
1932 }
1933
1934 if self.mark.col > max_indent {
1935 max_indent = self.mark.col;
1936 }
1937
1938 if self.input.next_is_break() {
1939 self.input.lookahead(2);
1941 self.read_break(breaks);
1942 } else {
1943 break;
1945 }
1946 }
1947
1948 *indent = max_indent.max((self.indent + 1) as usize);
1957 if self.indent > 0 {
1958 *indent = (*indent).max(1);
1959 }
1960 }
1961
1962 fn fetch_flow_scalar(&mut self, single: bool) -> ScanResult {
1963 self.save_simple_key();
1964 self.disallow_simple_key();
1965
1966 let tok = self.scan_flow_scalar(single)?;
1967
1968 self.skip_to_next_token()?;
1971 self.adjacent_value_allowed_at = self.mark.index;
1972
1973 self.tokens.push_back(tok);
1974 Ok(())
1975 }
1976
1977 #[allow(clippy::too_many_lines)]
1978 fn scan_flow_scalar(&mut self, single: bool) -> Result<Token<'input>, ScanError> {
1979 let start_mark = self.mark;
1980
1981 let mut string = String::new();
1982 let mut leading_break = String::new();
1983 let mut trailing_breaks = String::new();
1984 let mut whitespaces = String::new();
1985 let mut leading_blanks;
1986
1987 self.skip_non_blank();
1989
1990 loop {
1991 self.input.lookahead(4);
1993
1994 if self.mark.col == 0 && self.input.next_is_document_indicator() {
1995 return Err(ScanError::new_str(
1996 start_mark,
1997 "while scanning a quoted scalar, found unexpected document indicator",
1998 ));
1999 }
2000
2001 if self.input.next_is_z() {
2002 return Err(ScanError::new_str(
2003 start_mark,
2004 "while scanning a quoted scalar, found unexpected end of stream",
2005 ));
2006 }
2007
2008 if (self.mark.col as isize) < self.indent {
2009 return Err(ScanError::new_str(
2010 start_mark,
2011 "invalid indentation in quoted scalar",
2012 ));
2013 }
2014
2015 leading_blanks = false;
2016 self.consume_flow_scalar_non_whitespace_chars(
2017 single,
2018 &mut string,
2019 &mut leading_blanks,
2020 &start_mark,
2021 )?;
2022
2023 match self.input.look_ch() {
2024 '\'' if single => break,
2025 '"' if !single => break,
2026 _ => {}
2027 }
2028
2029 while self.input.next_is_blank() || self.input.next_is_break() {
2031 if self.input.next_is_blank() {
2032 if leading_blanks {
2034 if self.input.peek() == '\t' && (self.mark.col as isize) < self.indent {
2035 return Err(ScanError::new_str(
2036 self.mark,
2037 "tab cannot be used as indentation",
2038 ));
2039 }
2040 self.skip_blank();
2041 } else {
2042 whitespaces.push(self.input.peek());
2043 self.skip_blank();
2044 }
2045 } else {
2046 self.input.lookahead(2);
2047 if leading_blanks {
2049 self.read_break(&mut trailing_breaks);
2050 } else {
2051 whitespaces.clear();
2052 self.read_break(&mut leading_break);
2053 leading_blanks = true;
2054 }
2055 }
2056 self.input.lookahead(1);
2057 }
2058
2059 if leading_blanks {
2061 if leading_break.is_empty() {
2062 string.push_str(&leading_break);
2063 string.push_str(&trailing_breaks);
2064 trailing_breaks.clear();
2065 leading_break.clear();
2066 } else {
2067 if trailing_breaks.is_empty() {
2068 string.push(' ');
2069 } else {
2070 string.push_str(&trailing_breaks);
2071 trailing_breaks.clear();
2072 }
2073 leading_break.clear();
2074 }
2075 } else {
2076 string.push_str(&whitespaces);
2077 whitespaces.clear();
2078 }
2079 } self.skip_non_blank();
2083 self.skip_ws_to_eol(SkipTabs::Yes)?;
2085 match self.input.peek() {
2086 ',' | '}' | ']' if self.flow_level > 0 => {}
2088 c if is_breakz(c) => {}
2090 ':' if self.flow_level == 0 && start_mark.line == self.mark.line => {}
2093 ':' if self.flow_level > 0 => {}
2095 _ => {
2096 return Err(ScanError::new_str(
2097 self.mark,
2098 "invalid trailing content after double-quoted scalar",
2099 ));
2100 }
2101 }
2102
2103 let style = if single {
2104 ScalarStyle::SingleQuoted
2105 } else {
2106 ScalarStyle::DoubleQuoted
2107 };
2108 Ok(Token(
2109 Span::new(start_mark, self.mark),
2110 TokenType::Scalar(style, string.into()),
2111 ))
2112 }
2113
2114 fn consume_flow_scalar_non_whitespace_chars(
2123 &mut self,
2124 single: bool,
2125 string: &mut String,
2126 leading_blanks: &mut bool,
2127 start_mark: &Marker,
2128 ) -> Result<(), ScanError> {
2129 self.input.lookahead(2);
2130 while !is_blank_or_breakz(self.input.peek()) {
2131 match self.input.peek() {
2132 '\'' if self.input.peek_nth(1) == '\'' && single => {
2134 string.push('\'');
2135 self.skip_n_non_blank(2);
2136 }
2137 '\'' if single => break,
2139 '"' if !single => break,
2140 '\\' if !single && is_break(self.input.peek_nth(1)) => {
2142 self.input.lookahead(3);
2143 self.skip_non_blank();
2144 self.skip_linebreak();
2145 *leading_blanks = true;
2146 break;
2147 }
2148 '\\' if !single => {
2150 string.push(self.resolve_flow_scalar_escape_sequence(start_mark)?);
2151 }
2152 c => {
2153 string.push(c);
2154 self.skip_non_blank();
2155 }
2156 }
2157 self.input.lookahead(2);
2158 }
2159 Ok(())
2160 }
2161
2162 fn resolve_flow_scalar_escape_sequence(
2169 &mut self,
2170 start_mark: &Marker,
2171 ) -> Result<char, ScanError> {
2172 let mut code_length = 0usize;
2173 let mut ret = '\0';
2174
2175 match self.input.peek_nth(1) {
2176 '0' => ret = '\0',
2177 'a' => ret = '\x07',
2178 'b' => ret = '\x08',
2179 't' | '\t' => ret = '\t',
2180 'n' => ret = '\n',
2181 'v' => ret = '\x0b',
2182 'f' => ret = '\x0c',
2183 'r' => ret = '\x0d',
2184 'e' => ret = '\x1b',
2185 ' ' => ret = '\x20',
2186 '"' => ret = '"',
2187 '/' => ret = '/',
2188 '\\' => ret = '\\',
2189 'N' => ret = char::from_u32(0x85).unwrap(),
2191 '_' => ret = char::from_u32(0xA0).unwrap(),
2193 'L' => ret = char::from_u32(0x2028).unwrap(),
2195 'P' => ret = char::from_u32(0x2029).unwrap(),
2197 'x' => code_length = 2,
2198 'u' => code_length = 4,
2199 'U' => code_length = 8,
2200 _ => {
2201 return Err(ScanError::new_str(
2202 *start_mark,
2203 "while parsing a quoted scalar, found unknown escape character",
2204 ));
2205 }
2206 }
2207 self.skip_n_non_blank(2);
2208
2209 if code_length > 0 {
2211 self.input.lookahead(code_length);
2212 let mut value = 0u32;
2213 for i in 0..code_length {
2214 let c = self.input.peek_nth(i);
2215 if !is_hex(c) {
2216 return Err(ScanError::new_str(
2217 *start_mark,
2218 "while parsing a quoted scalar, did not find expected hexadecimal number",
2219 ));
2220 }
2221 value = (value << 4) + as_hex(c);
2222 }
2223
2224 let Some(ch) = char::from_u32(value) else {
2225 return Err(ScanError::new_str(
2226 *start_mark,
2227 "while parsing a quoted scalar, found invalid Unicode character escape code",
2228 ));
2229 };
2230 ret = ch;
2231
2232 self.skip_n_non_blank(code_length);
2233 }
2234 Ok(ret)
2235 }
2236
2237 fn fetch_plain_scalar(&mut self) -> ScanResult {
2238 self.save_simple_key();
2239 self.disallow_simple_key();
2240
2241 let tok = self.scan_plain_scalar()?;
2242
2243 self.tokens.push_back(tok);
2244 Ok(())
2245 }
2246
2247 #[allow(clippy::too_many_lines)]
2252 fn scan_plain_scalar(&mut self) -> Result<Token<'input>, ScanError> {
2253 self.unroll_non_block_indents();
2254 let indent = self.indent + 1;
2255 let start_mark = self.mark;
2256
2257 if self.flow_level > 0 && (start_mark.col as isize) < indent {
2258 return Err(ScanError::new_str(
2259 start_mark,
2260 "invalid indentation in flow construct",
2261 ));
2262 }
2263
2264 let mut string = String::with_capacity(32);
2265 self.buf_whitespaces.clear();
2266 self.buf_leading_break.clear();
2267 self.buf_trailing_breaks.clear();
2268 let mut end_mark = self.mark;
2269
2270 loop {
2271 self.input.lookahead(4);
2272 if (self.mark.col == 0 && self.input.next_is_document_indicator())
2273 || self.input.peek() == '#'
2274 {
2275 if self.input.peek() == '#'
2280 && !string.is_empty()
2281 && !self.buf_whitespaces.is_empty()
2282 && self.flow_level == 0
2283 {
2284 self.interrupted_plain_by_comment = Some(self.mark);
2285 }
2286 break;
2287 }
2288
2289 if self.flow_level > 0 && self.input.peek() == '-' && is_flow(self.input.peek_nth(1)) {
2290 return Err(ScanError::new_str(
2291 self.mark,
2292 "plain scalar cannot start with '-' followed by ,[]{}",
2293 ));
2294 }
2295
2296 if !self.input.next_is_blank_or_breakz()
2297 && self.input.next_can_be_plain_scalar(self.flow_level > 0)
2298 {
2299 if self.leading_whitespace {
2300 if self.buf_leading_break.is_empty() {
2301 string.push_str(&self.buf_leading_break);
2302 string.push_str(&self.buf_trailing_breaks);
2303 self.buf_trailing_breaks.clear();
2304 self.buf_leading_break.clear();
2305 } else {
2306 if self.buf_trailing_breaks.is_empty() {
2307 string.push(' ');
2308 } else {
2309 string.push_str(&self.buf_trailing_breaks);
2310 self.buf_trailing_breaks.clear();
2311 }
2312 self.buf_leading_break.clear();
2313 }
2314 self.leading_whitespace = false;
2315 } else if !self.buf_whitespaces.is_empty() {
2316 string.push_str(&self.buf_whitespaces);
2317 self.buf_whitespaces.clear();
2318 }
2319
2320 string.push(self.input.peek());
2322 self.skip_non_blank();
2323 string.reserve(self.input.bufmaxlen());
2324
2325 let mut end = false;
2327 while !end {
2328 self.input.lookahead(self.input.bufmaxlen());
2332 for _ in 0..self.input.bufmaxlen() - 1 {
2333 if self.input.next_is_blank_or_breakz()
2334 || !self.input.next_can_be_plain_scalar(self.flow_level > 0)
2335 {
2336 end = true;
2337 break;
2338 }
2339 string.push(self.input.peek());
2340 self.skip_non_blank();
2341 }
2342 }
2343 end_mark = self.mark;
2344 }
2345
2346 if !(self.input.next_is_blank() || self.input.next_is_break()) {
2351 break;
2352 }
2353
2354 self.input.lookahead(2);
2356 while self.input.next_is_blank_or_break() {
2357 if self.input.next_is_blank() {
2358 if !self.leading_whitespace {
2359 self.buf_whitespaces.push(self.input.peek());
2360 self.skip_blank();
2361 } else if (self.mark.col as isize) < indent && self.input.peek() == '\t' {
2362 self.skip_ws_to_eol(SkipTabs::Yes)?;
2365 if !self.input.next_is_breakz() {
2366 return Err(ScanError::new_str(
2367 start_mark,
2368 "while scanning a plain scalar, found a tab",
2369 ));
2370 }
2371 } else {
2372 self.skip_blank();
2373 }
2374 } else {
2375 if self.leading_whitespace {
2377 self.skip_break();
2378 self.buf_trailing_breaks.push('\n');
2379 } else {
2380 self.buf_whitespaces.clear();
2381 self.skip_break();
2382 self.buf_leading_break.push('\n');
2383 self.leading_whitespace = true;
2384 }
2385 }
2386 self.input.lookahead(2);
2387 }
2388
2389 if self.flow_level == 0 && (self.mark.col as isize) < indent {
2391 break;
2392 }
2393 }
2394
2395 if self.leading_whitespace {
2396 self.allow_simple_key();
2397 }
2398
2399 if string.is_empty() {
2400 Err(ScanError::new_str(
2404 start_mark,
2405 "unexpected end of plain scalar",
2406 ))
2407 } else {
2408 Ok(Token(
2409 Span::new(start_mark, end_mark),
2410 TokenType::Scalar(ScalarStyle::Plain, string.into()),
2411 ))
2412 }
2413 }
2414
2415 fn fetch_key(&mut self) -> ScanResult {
2416 let start_mark = self.mark;
2417 if self.flow_level == 0 {
2418 if !self.simple_key_allowed {
2420 return Err(ScanError::new_str(
2421 self.mark,
2422 "mapping keys are not allowed in this context",
2423 ));
2424 }
2425 self.roll_indent(
2426 start_mark.col,
2427 None,
2428 TokenType::BlockMappingStart,
2429 start_mark,
2430 );
2431 } else {
2432 self.flow_mapping_started = true;
2434 }
2435
2436 self.remove_simple_key()?;
2437
2438 if self.flow_level == 0 {
2439 self.allow_simple_key();
2440 } else {
2441 self.disallow_simple_key();
2442 }
2443
2444 self.skip_non_blank();
2445 self.skip_yaml_whitespace()?;
2446 if self.input.peek() == '\t' {
2447 return Err(ScanError::new_str(
2448 self.mark(),
2449 "tabs disallowed in this context",
2450 ));
2451 }
2452 self.tokens
2453 .push_back(Token(Span::new(start_mark, self.mark), TokenType::Key));
2454 Ok(())
2455 }
2456
2457 fn fetch_flow_value(&mut self) -> ScanResult {
2465 let nc = self.input.peek_nth(1);
2466
2467 if self.mark.index != self.adjacent_value_allowed_at && (nc == '[' || nc == '{') {
2479 return Err(ScanError::new_str(
2480 self.mark,
2481 "':' may not precede any of `[{` in flow mapping",
2482 ));
2483 }
2484
2485 self.fetch_value()
2486 }
2487
2488 fn fetch_value(&mut self) -> ScanResult {
2490 let sk = self.simple_keys.last().unwrap().clone();
2491 let start_mark = self.mark;
2492 let is_implicit_flow_mapping =
2493 !self.implicit_flow_mapping_states.is_empty() && !self.flow_mapping_started;
2494 if is_implicit_flow_mapping {
2495 *self.implicit_flow_mapping_states.last_mut().unwrap() = ImplicitMappingState::Inside;
2496 }
2497
2498 self.skip_non_blank();
2500 if self.input.look_ch() == '\t'
2501 && !self.skip_ws_to_eol(SkipTabs::Yes)?.has_valid_yaml_ws()
2502 && (self.input.peek() == '-' || self.input.next_is_alpha())
2503 {
2504 return Err(ScanError::new_str(
2505 self.mark,
2506 "':' must be followed by a valid YAML whitespace",
2507 ));
2508 }
2509
2510 if sk.possible {
2511 let tok = Token(Span::empty(sk.mark), TokenType::Key);
2513 self.insert_token(sk.token_number - self.tokens_parsed, tok);
2514 if is_implicit_flow_mapping {
2515 if sk.mark.line < start_mark.line {
2516 return Err(ScanError::new_str(
2517 start_mark,
2518 "illegal placement of ':' indicator",
2519 ));
2520 }
2521 self.insert_token(
2522 sk.token_number - self.tokens_parsed,
2523 Token(Span::empty(sk.mark), TokenType::FlowMappingStart),
2524 );
2525 }
2526
2527 self.roll_indent(
2529 sk.mark.col,
2530 Some(sk.token_number),
2531 TokenType::BlockMappingStart,
2532 sk.mark,
2533 );
2534 self.roll_one_col_indent();
2535
2536 self.simple_keys.last_mut().unwrap().possible = false;
2537 self.disallow_simple_key();
2538 } else {
2539 if is_implicit_flow_mapping {
2540 self.tokens
2541 .push_back(Token(Span::empty(start_mark), TokenType::FlowMappingStart));
2542 }
2543 if self.flow_level == 0 {
2545 if !self.simple_key_allowed {
2546 return Err(ScanError::new_str(
2547 start_mark,
2548 "mapping values are not allowed in this context",
2549 ));
2550 }
2551
2552 self.roll_indent(
2553 start_mark.col,
2554 None,
2555 TokenType::BlockMappingStart,
2556 start_mark,
2557 );
2558 }
2559 self.roll_one_col_indent();
2560
2561 if self.flow_level == 0 {
2562 self.allow_simple_key();
2563 } else {
2564 self.disallow_simple_key();
2565 }
2566 }
2567 self.tokens
2568 .push_back(Token(Span::empty(start_mark), TokenType::Value));
2569
2570 Ok(())
2571 }
2572
2573 fn roll_indent(
2579 &mut self,
2580 col: usize,
2581 number: Option<usize>,
2582 tok: TokenType<'input>,
2583 mark: Marker,
2584 ) {
2585 if self.flow_level > 0 {
2586 return;
2587 }
2588
2589 if self.indent <= col as isize {
2593 if let Some(indent) = self.indents.last() {
2594 if !indent.needs_block_end {
2595 self.indent = indent.indent;
2596 self.indents.pop();
2597 }
2598 }
2599 }
2600
2601 if self.indent < col as isize {
2602 self.indents.push(Indent {
2603 indent: self.indent,
2604 needs_block_end: true,
2605 });
2606 self.indent = col as isize;
2607 let tokens_parsed = self.tokens_parsed;
2608 match number {
2609 Some(n) => self.insert_token(n - tokens_parsed, Token(Span::empty(mark), tok)),
2610 None => self.tokens.push_back(Token(Span::empty(mark), tok)),
2611 }
2612 }
2613 }
2614
2615 fn unroll_indent(&mut self, col: isize) {
2621 if self.flow_level > 0 {
2622 return;
2623 }
2624 while self.indent > col {
2625 let indent = self.indents.pop().unwrap();
2626 self.indent = indent.indent;
2627 if indent.needs_block_end {
2628 self.tokens
2629 .push_back(Token(Span::empty(self.mark), TokenType::BlockEnd));
2630 }
2631 }
2632 }
2633
2634 fn roll_one_col_indent(&mut self) {
2640 if self.flow_level == 0 && self.indents.last().is_some_and(|x| x.needs_block_end) {
2641 self.indents.push(Indent {
2642 indent: self.indent,
2643 needs_block_end: false,
2644 });
2645 self.indent += 1;
2646 }
2647 }
2648
2649 fn unroll_non_block_indents(&mut self) {
2651 while let Some(indent) = self.indents.last() {
2652 if indent.needs_block_end {
2653 break;
2654 }
2655 self.indent = indent.indent;
2656 self.indents.pop();
2657 }
2658 }
2659
2660 fn save_simple_key(&mut self) {
2662 if self.simple_key_allowed {
2663 let required = self.flow_level == 0
2664 && self.indent == (self.mark.col as isize)
2665 && self.indents.last().unwrap().needs_block_end;
2666 let mut sk = SimpleKey::new(self.mark);
2667 sk.possible = true;
2668 sk.required = required;
2669 sk.token_number = self.tokens_parsed + self.tokens.len();
2670
2671 self.simple_keys.pop();
2672 self.simple_keys.push(sk);
2673 }
2674 }
2675
2676 fn remove_simple_key(&mut self) -> ScanResult {
2677 let last = self.simple_keys.last_mut().unwrap();
2678 if last.possible && last.required {
2679 return Err(ScanError::new_str(self.mark, "simple key expected"));
2680 }
2681
2682 last.possible = false;
2683 Ok(())
2684 }
2685
2686 fn is_within_block(&self) -> bool {
2688 !self.indents.is_empty()
2689 }
2690
2691 fn end_implicit_mapping(&mut self, mark: Marker) {
2697 if let Some(implicit_mapping) = self.implicit_flow_mapping_states.last_mut() {
2698 if *implicit_mapping == ImplicitMappingState::Inside {
2699 self.flow_mapping_started = false;
2700 *implicit_mapping = ImplicitMappingState::Possible;
2701 self.tokens
2702 .push_back(Token(Span::empty(mark), TokenType::FlowMappingEnd));
2703 }
2704 }
2705 }
2706}
2707
2708#[derive(PartialEq, Eq)]
2712pub enum Chomping {
2713 Strip,
2715 Clip,
2717 Keep,
2719}
2720
2721#[cfg(test)]
2722mod test {
2723 #[test]
2724 fn test_is_anchor_char() {
2725 use super::is_anchor_char;
2726 assert!(is_anchor_char('x'));
2727 }
2728}