More fixes towards invalid tabs.

This commit is contained in:
Ethiraric 2023-12-24 00:02:42 +01:00
parent ffe0cfb6d5
commit da233d5426

View file

@ -648,7 +648,7 @@ impl<T: Iterator<Item = char>> Scanner<T> {
&& self.leading_whitespace
&& (self.mark.col as isize) < self.indent =>
{
self.skip_ws_to_eol(true);
self.skip_ws_to_eol(SkipTabs::Yes);
// If we have content on that line with a tab, return an error.
if !is_breakz(self.ch()) {
return Err(ScanError::new(
@ -716,11 +716,15 @@ impl<T: Iterator<Item = char>> Scanner<T> {
}
/// Skip yaml whitespace at most up to eol. Also skips comments.
fn skip_ws_to_eol(&mut self, skip_tab: bool) {
fn skip_ws_to_eol(&mut self, skip_tabs: SkipTabs) -> SkipTabs {
let mut encountered_tab = false;
loop {
match self.look_ch() {
' ' => self.skip(),
'\t' if skip_tab => self.skip(),
'\t' if skip_tabs != SkipTabs::No => {
encountered_tab = true;
self.skip();
}
'#' => {
while !is_breakz(self.ch()) {
self.skip();
@ -730,6 +734,8 @@ impl<T: Iterator<Item = char>> Scanner<T> {
_ => break,
}
}
SkipTabs::Result(encountered_tab)
}
fn fetch_stream_start(&mut self) {
@ -1259,18 +1265,16 @@ impl<T: Iterator<Item = char>> Scanner<T> {
// generate BLOCK-SEQUENCE-START if indented
self.roll_indent(mark.col, None, TokenType::BlockSequenceStart, mark);
if self.ch() == '\t' {
self.skip_to_next_token()?;
let found_tabs = self.skip_ws_to_eol(SkipTabs::Yes).found_tabs();
self.lookahead(2);
if self.buffer[0] == '-' && is_blankz(self.buffer[1]) {
if found_tabs && self.buffer[0] == '-' && is_blankz(self.buffer[1]) {
return Err(ScanError::new(
self.mark,
"'-' must be followed by a valid YAML whitespace",
));
}
}
self.skip_ws_to_eol(false);
self.skip_ws_to_eol(SkipTabs::No);
if is_break(self.look_ch()) || is_flow(self.ch()) {
self.indents.push(Indent {
indent: self.indent,
@ -2029,3 +2033,26 @@ impl<T: Iterator<Item = char>> Scanner<T> {
!self.indents.is_empty()
}
}
/// Behavior to adopt regarding treating tabs as whitespace.
#[derive(Copy, Clone, Eq, PartialEq)]
enum SkipTabs {
/// Skip all tabs as whitespace.
Yes,
/// Don't skip any tab. Return from the function when encountering one.
No,
/// Return value from the function.
Result(
/// Whether tabs were encountered.
bool,
),
}
impl SkipTabs {
/// Whether tabs were found while skipping whitespace.
///
/// This function must be called after a call to `skip_ws_to_eol`.
fn found_tabs(self) -> bool {
matches!(self, SkipTabs::Result(true))
}
}