Move scanning low-level functions to Input
.
This commit is contained in:
parent
696ca59a16
commit
93b7e55bcf
3 changed files with 375 additions and 69 deletions
|
@ -4,7 +4,9 @@ pub mod str;
|
|||
#[allow(clippy::module_name_repetitions)]
|
||||
pub use buffered::BufferedInput;
|
||||
|
||||
use crate::char_traits::{is_blank_or_breakz, is_breakz, is_flow};
|
||||
use crate::char_traits::{
|
||||
is_alpha, is_blank, is_blank_or_breakz, is_break, is_breakz, is_digit, is_flow, is_z,
|
||||
};
|
||||
|
||||
/// Interface for a source of characters.
|
||||
///
|
||||
|
@ -170,7 +172,7 @@ pub trait Input {
|
|||
///
|
||||
/// # Return
|
||||
/// Return a tuple with the number of characters that were consumed and the result of skipping
|
||||
/// whitespace. The number of characters returned can be used to advance the index and columns,
|
||||
/// whitespace. The number of characters returned can be used to advance the index and column,
|
||||
/// since no end-of-line character will be consumed.
|
||||
/// See [`SkipTabs`] For more details on the success variant.
|
||||
///
|
||||
|
@ -230,6 +232,188 @@ pub trait Input {
|
|||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Check whether the next character is [a blank] or [a break].
|
||||
///
|
||||
/// The character must have previously been fetched through [`lookahead`]
|
||||
///
|
||||
/// # Return
|
||||
/// Returns true if the character is [a blank] or [a break], false otherwise.
|
||||
///
|
||||
/// [`lookahead`]: Input::lookahead
|
||||
/// [a blank]: is_blank
|
||||
/// [a break]: is_break
|
||||
#[inline]
|
||||
fn next_is_blank_or_break(&self) -> bool {
|
||||
is_blank(self.peek()) || is_break(self.peek())
|
||||
}
|
||||
|
||||
/// Check whether the next character is [a blank] or [a breakz].
|
||||
///
|
||||
/// The character must have previously been fetched through [`lookahead`]
|
||||
///
|
||||
/// # Return
|
||||
/// Returns true if the character is [a blank] or [a break], false otherwise.
|
||||
///
|
||||
/// [`lookahead`]: Input::lookahead
|
||||
/// [a blank]: is_blank
|
||||
/// [a breakz]: is_breakz
|
||||
#[inline]
|
||||
fn next_is_blank_or_breakz(&self) -> bool {
|
||||
is_blank(self.peek()) || is_breakz(self.peek())
|
||||
}
|
||||
|
||||
/// Check whether the next character is [a blank].
|
||||
///
|
||||
/// The character must have previously been fetched through [`lookahead`]
|
||||
///
|
||||
/// # Return
|
||||
/// Returns true if the character is [a blank], false otherwise.
|
||||
///
|
||||
/// [`lookahead`]: Input::lookahead
|
||||
/// [a blank]: is_blank
|
||||
#[inline]
|
||||
fn next_is_blank(&self) -> bool {
|
||||
is_blank(self.peek())
|
||||
}
|
||||
|
||||
/// Check whether the next character is [a break].
|
||||
///
|
||||
/// The character must have previously been fetched through [`lookahead`]
|
||||
///
|
||||
/// # Return
|
||||
/// Returns true if the character is [a break], false otherwise.
|
||||
///
|
||||
/// [`lookahead`]: Input::lookahead
|
||||
/// [a break]: is_break
|
||||
#[inline]
|
||||
fn next_is_break(&self) -> bool {
|
||||
is_break(self.peek())
|
||||
}
|
||||
|
||||
/// Check whether the next character is [a breakz].
|
||||
///
|
||||
/// The character must have previously been fetched through [`lookahead`]
|
||||
///
|
||||
/// # Return
|
||||
/// Returns true if the character is [a breakz], false otherwise.
|
||||
///
|
||||
/// [`lookahead`]: Input::lookahead
|
||||
/// [a breakz]: is_breakz
|
||||
#[inline]
|
||||
fn next_is_breakz(&self) -> bool {
|
||||
is_breakz(self.peek())
|
||||
}
|
||||
|
||||
/// Check whether the next character is [a z].
|
||||
///
|
||||
/// The character must have previously been fetched through [`lookahead`]
|
||||
///
|
||||
/// # Return
|
||||
/// Returns true if the character is [a z], false otherwise.
|
||||
///
|
||||
/// [`lookahead`]: Input::lookahead
|
||||
/// [a z]: is_z
|
||||
#[inline]
|
||||
fn next_is_z(&self) -> bool {
|
||||
is_z(self.peek())
|
||||
}
|
||||
|
||||
/// Check whether the next character is [a flow].
|
||||
///
|
||||
/// The character must have previously been fetched through [`lookahead`]
|
||||
///
|
||||
/// # Return
|
||||
/// Returns true if the character is [a flow], false otherwise.
|
||||
///
|
||||
/// [`lookahead`]: Input::lookahead
|
||||
/// [a flow]: is_flow
|
||||
#[inline]
|
||||
fn next_is_flow(&self) -> bool {
|
||||
is_flow(self.peek())
|
||||
}
|
||||
|
||||
/// Check whether the next character is [a digit].
|
||||
///
|
||||
/// The character must have previously been fetched through [`lookahead`]
|
||||
///
|
||||
/// # Return
|
||||
/// Returns true if the character is [a digit], false otherwise.
|
||||
///
|
||||
/// [`lookahead`]: Input::lookahead
|
||||
/// [a digit]: is_digit
|
||||
#[inline]
|
||||
fn next_is_digit(&self) -> bool {
|
||||
is_digit(self.peek())
|
||||
}
|
||||
|
||||
/// Check whether the next character is [a letter].
|
||||
///
|
||||
/// The character must have previously been fetched through [`lookahead`]
|
||||
///
|
||||
/// # Return
|
||||
/// Returns true if the character is [a letter], false otherwise.
|
||||
///
|
||||
/// [`lookahead`]: Input::lookahead
|
||||
/// [a letter]: is_alpha
|
||||
#[inline]
|
||||
fn next_is_alpha(&self) -> bool {
|
||||
is_alpha(self.peek())
|
||||
}
|
||||
|
||||
/// Skip characters from the input until a [breakz] is found.
|
||||
///
|
||||
/// The characters are consumed from the input.
|
||||
///
|
||||
/// # Return
|
||||
/// Return the number of characters that were consumed. The number of characters returned can
|
||||
/// be used to advance the index and column, since no end-of-line character will be consumed.
|
||||
///
|
||||
/// [breakz]: is_breakz
|
||||
#[inline]
|
||||
fn skip_while_non_breakz(&mut self) -> usize {
|
||||
let mut count = 0;
|
||||
while !is_breakz(self.look_ch()) {
|
||||
count += 1;
|
||||
self.skip();
|
||||
}
|
||||
count
|
||||
}
|
||||
|
||||
/// Skip characters from the input while [blanks] are found.
|
||||
///
|
||||
/// The characters are consumed from the input.
|
||||
///
|
||||
/// # Return
|
||||
/// Return the number of characters that were consumed. The number of characters returned can
|
||||
/// be used to advance the index and column, since no end-of-line character will be consumed.
|
||||
///
|
||||
/// [blanks]: is_blank
|
||||
fn skip_while_blank(&mut self) -> usize {
|
||||
let mut n_chars = 0;
|
||||
while is_blank(self.look_ch()) {
|
||||
n_chars += 1;
|
||||
self.skip();
|
||||
}
|
||||
n_chars
|
||||
}
|
||||
|
||||
/// Fetch characters from the input while we encounter letters and store them in `out`.
|
||||
///
|
||||
/// The characters are consumed from the input.
|
||||
///
|
||||
/// # Return
|
||||
/// Return the number of characters that were consumed. The number of characters returned can
|
||||
/// be used to advance the index and column, since no end-of-line character will be consumed.
|
||||
fn fetch_while_is_alpha(&mut self, out: &mut String) -> usize {
|
||||
let mut n_chars = 0;
|
||||
while is_alpha(self.look_ch()) {
|
||||
n_chars += 1;
|
||||
out.push(self.peek());
|
||||
self.skip();
|
||||
}
|
||||
n_chars
|
||||
}
|
||||
}
|
||||
|
||||
/// Behavior to adopt regarding treating tabs as whitespace.
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use crate::{
|
||||
char_traits::{is_blank_or_breakz, is_breakz, is_flow},
|
||||
char_traits::{
|
||||
is_alpha, is_blank, is_blank_or_breakz, is_break, is_breakz, is_digit, is_flow, is_z,
|
||||
},
|
||||
input::{Input, SkipTabs},
|
||||
};
|
||||
|
||||
|
@ -60,7 +62,9 @@ impl<'a> Input for StrInput<'a> {
|
|||
|
||||
#[inline]
|
||||
fn push_back(&mut self, c: char) {
|
||||
self.buffer = put_back_in_str(self.buffer, c);
|
||||
// SAFETY: The preconditions of this function is that the character we are given is the one
|
||||
// immediately preceding `self.buffer`.
|
||||
self.buffer = unsafe { put_back_in_str(self.buffer, c) };
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -270,6 +274,122 @@ impl<'a> Input for StrInput<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn next_is_blank_or_break(&self) -> bool {
|
||||
!self.buffer.is_empty()
|
||||
&& (is_blank(self.buffer.as_bytes()[0] as char)
|
||||
|| is_break(self.buffer.as_bytes()[0] as char))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn next_is_blank_or_breakz(&self) -> bool {
|
||||
self.buffer.is_empty()
|
||||
|| (is_blank(self.buffer.as_bytes()[0] as char)
|
||||
|| is_breakz(self.buffer.as_bytes()[0] as char))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn next_is_blank(&self) -> bool {
|
||||
!self.buffer.is_empty() && is_blank(self.buffer.as_bytes()[0] as char)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn next_is_break(&self) -> bool {
|
||||
!self.buffer.is_empty() && is_break(self.buffer.as_bytes()[0] as char)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn next_is_breakz(&self) -> bool {
|
||||
self.buffer.is_empty() || is_breakz(self.buffer.as_bytes()[0] as char)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn next_is_z(&self) -> bool {
|
||||
self.buffer.is_empty() || is_z(self.buffer.as_bytes()[0] as char)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn next_is_flow(&self) -> bool {
|
||||
!self.buffer.is_empty() && is_flow(self.buffer.as_bytes()[0] as char)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn next_is_digit(&self) -> bool {
|
||||
!self.buffer.is_empty() && is_digit(self.buffer.as_bytes()[0] as char)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn next_is_alpha(&self) -> bool {
|
||||
!self.buffer.is_empty() && is_alpha(self.buffer.as_bytes()[0] as char)
|
||||
}
|
||||
|
||||
fn skip_while_non_breakz(&mut self) -> usize {
|
||||
let mut found_breakz = false;
|
||||
let mut count = 0;
|
||||
|
||||
// Skip over all non-breaks.
|
||||
let mut chars = self.buffer.chars();
|
||||
for c in chars.by_ref() {
|
||||
if is_breakz(c) {
|
||||
found_breakz = true;
|
||||
break;
|
||||
}
|
||||
count += 1;
|
||||
}
|
||||
|
||||
self.buffer = if found_breakz {
|
||||
// If we read a breakz, we need to put it back to the buffer.
|
||||
// SAFETY: The last character we extracted is either a '\n', '\r' or '\0', all of which
|
||||
// are 1-byte long.
|
||||
unsafe { extend_left(chars.as_str(), 1) }
|
||||
} else {
|
||||
chars.as_str()
|
||||
};
|
||||
|
||||
count
|
||||
}
|
||||
|
||||
fn skip_while_blank(&mut self) -> usize {
|
||||
// Since all characters we look for are ascii, we can directly use the byte API of str.
|
||||
let mut i = 0;
|
||||
while i < self.buffer.len() {
|
||||
if !is_blank(self.buffer.as_bytes()[i] as char) {
|
||||
break;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
self.buffer = &self.buffer[i..];
|
||||
i
|
||||
}
|
||||
|
||||
fn fetch_while_is_alpha(&mut self, out: &mut String) -> usize {
|
||||
let mut not_alpha = None;
|
||||
|
||||
// Skip while we have alpha characters.
|
||||
let mut chars = self.buffer.chars();
|
||||
for c in chars.by_ref() {
|
||||
if !is_alpha(c) {
|
||||
not_alpha = Some(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let remaining_string = if let Some(c) = not_alpha {
|
||||
let n_bytes_read = chars.as_str().as_ptr() as usize - self.buffer.as_ptr() as usize;
|
||||
let last_char_bytes = c.len_utf8();
|
||||
&self.buffer[n_bytes_read - last_char_bytes..]
|
||||
} else {
|
||||
chars.as_str()
|
||||
};
|
||||
|
||||
let n_bytes_to_append = remaining_string.as_ptr() as usize - self.buffer.as_ptr() as usize;
|
||||
out.reserve(n_bytes_to_append);
|
||||
out.push_str(&self.buffer[..n_bytes_to_append]);
|
||||
self.buffer = remaining_string;
|
||||
|
||||
n_bytes_to_append
|
||||
}
|
||||
}
|
||||
|
||||
/// The buffer size we return to the scanner.
|
||||
|
@ -309,13 +429,13 @@ const BUFFER_LEN: usize = 128;
|
|||
/// assert_eq!(s1, s3);
|
||||
/// assert_eq!(s1.as_ptr(), s3.as_ptr());
|
||||
/// ```
|
||||
fn put_back_in_str(s: &str, c: char) -> &str {
|
||||
unsafe fn put_back_in_str(s: &str, c: char) -> &str {
|
||||
let n_bytes = c.len_utf8();
|
||||
|
||||
// SAFETY: The character that gets pushed back is guaranteed to be the one that is
|
||||
// immediately preceding our buffer. We can compute the length of the character and move
|
||||
// our buffer back that many bytes.
|
||||
unsafe { extend_left(s, n_bytes) }
|
||||
extend_left(s, n_bytes)
|
||||
}
|
||||
|
||||
/// Extend the string by moving the start pointer to the left by `n` bytes.
|
||||
|
@ -369,7 +489,7 @@ mod test {
|
|||
pub fn put_back_in_str_example() {
|
||||
let s1 = "foo";
|
||||
let s2 = &s1[1..];
|
||||
let s3 = put_back_in_str(s2, 'f'); // OK, 'f' is the character immediately preceding
|
||||
let s3 = unsafe { put_back_in_str(s2, 'f') }; // OK, 'f' is the character immediately preceding
|
||||
assert_eq!(s1, s3);
|
||||
assert_eq!(s1.as_ptr(), s3.as_ptr());
|
||||
}
|
||||
|
|
|
@ -13,8 +13,8 @@ use std::{char, collections::VecDeque, error::Error, fmt};
|
|||
|
||||
use crate::{
|
||||
char_traits::{
|
||||
as_hex, is_alpha, is_anchor_char, is_blank, is_blank_or_breakz, is_break, is_breakz,
|
||||
is_digit, is_flow, is_hex, is_tag_char, is_uri_char, is_z,
|
||||
as_hex, is_anchor_char, is_blank_or_breakz, is_break, is_breakz, is_flow, is_hex,
|
||||
is_tag_char, is_uri_char,
|
||||
},
|
||||
input::{Input, SkipTabs},
|
||||
};
|
||||
|
@ -533,7 +533,7 @@ impl<T: Input> Scanner<T> {
|
|||
// will be reset by `skip_nl`.
|
||||
self.skip_blank();
|
||||
self.skip_nl();
|
||||
} else if is_break(self.input.peek()) {
|
||||
} else if self.input.next_is_break() {
|
||||
self.skip_nl();
|
||||
}
|
||||
}
|
||||
|
@ -616,7 +616,7 @@ impl<T: Input> Scanner<T> {
|
|||
|
||||
self.input.lookahead(4);
|
||||
|
||||
if is_z(self.input.peek()) {
|
||||
if self.input.next_is_z() {
|
||||
self.fetch_stream_end()?;
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -629,7 +629,7 @@ impl<T: Input> Scanner<T> {
|
|||
} else if self.input.next_is_document_end() {
|
||||
self.fetch_document_indicator(TokenType::DocumentEnd)?;
|
||||
self.skip_ws_to_eol(SkipTabs::Yes)?;
|
||||
if !is_breakz(self.input.peek()) {
|
||||
if !self.input.next_is_breakz() {
|
||||
return Err(ScanError::new_str(
|
||||
self.mark,
|
||||
"invalid content after document end marker",
|
||||
|
@ -784,7 +784,7 @@ impl<T: Input> Scanner<T> {
|
|||
{
|
||||
self.skip_ws_to_eol(SkipTabs::Yes)?;
|
||||
// If we have content on that line with a tab, return an error.
|
||||
if !is_breakz(self.input.peek()) {
|
||||
if !self.input.next_is_breakz() {
|
||||
return Err(ScanError::new_str(
|
||||
self.mark,
|
||||
"tabs disallowed within this context (block indentation)",
|
||||
|
@ -800,9 +800,9 @@ impl<T: Input> Scanner<T> {
|
|||
}
|
||||
}
|
||||
'#' => {
|
||||
while !is_breakz(self.input.look_ch()) {
|
||||
self.skip_non_blank();
|
||||
}
|
||||
let comment_length = self.input.skip_while_non_breakz();
|
||||
self.mark.index += comment_length;
|
||||
self.mark.col += comment_length;
|
||||
}
|
||||
_ => break,
|
||||
}
|
||||
|
@ -832,9 +832,9 @@ impl<T: Input> Scanner<T> {
|
|||
need_whitespace = false;
|
||||
}
|
||||
'#' => {
|
||||
while !is_breakz(self.input.look_ch()) {
|
||||
self.skip_non_blank();
|
||||
}
|
||||
let comment_length = self.input.skip_while_non_breakz();
|
||||
self.mark.index += comment_length;
|
||||
self.mark.col += comment_length;
|
||||
}
|
||||
_ => break,
|
||||
}
|
||||
|
@ -912,9 +912,9 @@ impl<T: Input> Scanner<T> {
|
|||
// XXX This should be a warning instead of an error
|
||||
_ => {
|
||||
// skip current line
|
||||
while !is_breakz(self.input.look_ch()) {
|
||||
self.skip_non_blank();
|
||||
}
|
||||
let line_len = self.input.skip_while_non_breakz();
|
||||
self.mark.index += line_len;
|
||||
self.mark.col += line_len;
|
||||
// XXX return an empty TagDirective token
|
||||
Token(
|
||||
start_mark,
|
||||
|
@ -927,7 +927,7 @@ impl<T: Input> Scanner<T> {
|
|||
|
||||
self.skip_ws_to_eol(SkipTabs::Yes)?;
|
||||
|
||||
if is_breakz(self.input.peek()) {
|
||||
if self.input.next_is_breakz() {
|
||||
self.input.lookahead(2);
|
||||
self.skip_linebreak();
|
||||
Ok(tok)
|
||||
|
@ -940,9 +940,9 @@ impl<T: Input> Scanner<T> {
|
|||
}
|
||||
|
||||
fn scan_version_directive_value(&mut self, mark: &Marker) -> Result<Token, ScanError> {
|
||||
while is_blank(self.input.look_ch()) {
|
||||
self.skip_blank();
|
||||
}
|
||||
let n_blanks = self.input.skip_while_blank();
|
||||
self.mark.index += n_blanks;
|
||||
self.mark.col += n_blanks;
|
||||
|
||||
let major = self.scan_version_directive_number(mark)?;
|
||||
|
||||
|
@ -962,10 +962,10 @@ impl<T: Input> Scanner<T> {
|
|||
fn scan_directive_name(&mut self) -> Result<String, ScanError> {
|
||||
let start_mark = self.mark;
|
||||
let mut string = String::new();
|
||||
while is_alpha(self.input.look_ch()) {
|
||||
string.push(self.input.peek());
|
||||
self.skip_non_blank();
|
||||
}
|
||||
|
||||
let n_chars = self.input.fetch_while_is_alpha(&mut string);
|
||||
self.mark.index += n_chars;
|
||||
self.mark.col += n_chars;
|
||||
|
||||
if string.is_empty() {
|
||||
return Err(ScanError::new_str(
|
||||
|
@ -1010,22 +1010,21 @@ impl<T: Input> Scanner<T> {
|
|||
}
|
||||
|
||||
fn scan_tag_directive_value(&mut self, mark: &Marker) -> Result<Token, ScanError> {
|
||||
/* Eat whitespaces. */
|
||||
while is_blank(self.input.look_ch()) {
|
||||
self.skip_blank();
|
||||
}
|
||||
let n_blanks = self.input.skip_while_blank();
|
||||
self.mark.index += n_blanks;
|
||||
self.mark.col += n_blanks;
|
||||
|
||||
let handle = self.scan_tag_handle(true, mark)?;
|
||||
|
||||
/* Eat whitespaces. */
|
||||
while is_blank(self.input.look_ch()) {
|
||||
self.skip_blank();
|
||||
}
|
||||
let n_blanks = self.input.skip_while_blank();
|
||||
self.mark.index += n_blanks;
|
||||
self.mark.col += n_blanks;
|
||||
|
||||
let prefix = self.scan_tag_prefix(mark)?;
|
||||
|
||||
self.input.lookahead(1);
|
||||
|
||||
if is_blank_or_breakz(self.input.peek()) {
|
||||
if self.input.next_is_blank_or_breakz() {
|
||||
Ok(Token(*mark, TokenType::TagDirective(handle, prefix)))
|
||||
} else {
|
||||
Err(ScanError::new_str(
|
||||
|
@ -1076,7 +1075,7 @@ impl<T: Input> Scanner<T> {
|
|||
}
|
||||
|
||||
if is_blank_or_breakz(self.input.look_ch())
|
||||
|| (self.flow_level > 0 && is_flow(self.input.peek()))
|
||||
|| (self.flow_level > 0 && self.input.next_is_flow())
|
||||
{
|
||||
// XXX: ex 7.2, an empty scalar can follow a secondary tag
|
||||
Ok(Token(start_mark, TokenType::Tag(handle, suffix)))
|
||||
|
@ -1100,10 +1099,9 @@ impl<T: Input> Scanner<T> {
|
|||
string.push(self.input.peek());
|
||||
self.skip_non_blank();
|
||||
|
||||
while is_alpha(self.input.look_ch()) {
|
||||
string.push(self.input.peek());
|
||||
self.skip_non_blank();
|
||||
}
|
||||
let n_chars = self.input.fetch_while_is_alpha(&mut string);
|
||||
self.mark.index += n_chars;
|
||||
self.mark.col += n_chars;
|
||||
|
||||
// Check if the trailing character is '!' and copy it.
|
||||
if self.input.peek() == '!' {
|
||||
|
@ -1448,7 +1446,8 @@ impl<T: Input> Scanner<T> {
|
|||
}
|
||||
|
||||
self.skip_ws_to_eol(SkipTabs::No)?;
|
||||
if is_break(self.input.look_ch()) || is_flow(self.input.peek()) {
|
||||
self.input.lookahead(1);
|
||||
if self.input.next_is_break() || self.input.next_is_flow() {
|
||||
self.roll_one_col_indent();
|
||||
}
|
||||
|
||||
|
@ -1513,7 +1512,8 @@ impl<T: Input> Scanner<T> {
|
|||
chomping = Chomping::Strip;
|
||||
}
|
||||
self.skip_non_blank();
|
||||
if is_digit(self.input.look_ch()) {
|
||||
self.input.lookahead(1);
|
||||
if self.input.next_is_digit() {
|
||||
if self.input.peek() == '0' {
|
||||
return Err(ScanError::new_str(
|
||||
start_mark,
|
||||
|
@ -1523,7 +1523,7 @@ impl<T: Input> Scanner<T> {
|
|||
increment = (self.input.peek() as usize) - ('0' as usize);
|
||||
self.skip_non_blank();
|
||||
}
|
||||
} else if is_digit(self.input.peek()) {
|
||||
} else if self.input.next_is_digit() {
|
||||
if self.input.peek() == '0' {
|
||||
return Err(ScanError::new_str(
|
||||
start_mark,
|
||||
|
@ -1547,14 +1547,15 @@ impl<T: Input> Scanner<T> {
|
|||
self.skip_ws_to_eol(SkipTabs::Yes)?;
|
||||
|
||||
// Check if we are at the end of the line.
|
||||
if !is_breakz(self.input.look_ch()) {
|
||||
self.input.lookahead(1);
|
||||
if !self.input.next_is_breakz() {
|
||||
return Err(ScanError::new_str(
|
||||
start_mark,
|
||||
"while scanning a block scalar, did not find expected comment or line break",
|
||||
));
|
||||
}
|
||||
|
||||
if is_break(self.input.peek()) {
|
||||
if self.input.next_is_break() {
|
||||
self.input.lookahead(2);
|
||||
self.read_break(&mut chomping_break);
|
||||
}
|
||||
|
@ -1585,7 +1586,7 @@ impl<T: Input> Scanner<T> {
|
|||
// ```yaml
|
||||
// - |+
|
||||
// ```
|
||||
if is_z(self.input.peek()) {
|
||||
if self.input.next_is_z() {
|
||||
let contents = match chomping {
|
||||
// We strip trailing linebreaks. Nothing remain.
|
||||
Chomping::Strip => String::new(),
|
||||
|
@ -1612,7 +1613,7 @@ impl<T: Input> Scanner<T> {
|
|||
|
||||
let mut line_buffer = String::with_capacity(100);
|
||||
let start_mark = self.mark;
|
||||
while self.mark.col == indent && !is_z(self.input.peek()) {
|
||||
while self.mark.col == indent && !self.input.next_is_z() {
|
||||
if indent == 0 {
|
||||
self.input.lookahead(4);
|
||||
if self.input.next_is_document_end() {
|
||||
|
@ -1621,7 +1622,7 @@ impl<T: Input> Scanner<T> {
|
|||
}
|
||||
|
||||
// We are at the first content character of a content line.
|
||||
trailing_blank = is_blank(self.input.peek());
|
||||
trailing_blank = self.input.next_is_blank();
|
||||
if !literal && !leading_break.is_empty() && !leading_blank && !trailing_blank {
|
||||
string.push_str(&trailing_breaks);
|
||||
if trailing_breaks.is_empty() {
|
||||
|
@ -1635,12 +1636,12 @@ impl<T: Input> Scanner<T> {
|
|||
leading_break.clear();
|
||||
trailing_breaks.clear();
|
||||
|
||||
leading_blank = is_blank(self.input.peek());
|
||||
leading_blank = self.input.next_is_blank();
|
||||
|
||||
self.scan_block_scalar_content_line(&mut string, &mut line_buffer);
|
||||
|
||||
// break on EOF
|
||||
if is_z(self.input.peek()) {
|
||||
if self.input.next_is_z() {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1657,7 +1658,7 @@ impl<T: Input> Scanner<T> {
|
|||
// If we had reached an eof but the last character wasn't an end-of-line, check if the
|
||||
// last line was indented at least as the rest of the scalar, then we need to consider
|
||||
// there is a newline.
|
||||
if is_z(self.input.peek()) && self.mark.col >= indent.max(1) {
|
||||
if self.input.next_is_z() && self.mark.col >= indent.max(1) {
|
||||
string.push('\n');
|
||||
}
|
||||
}
|
||||
|
@ -1680,7 +1681,7 @@ impl<T: Input> Scanner<T> {
|
|||
/// line. This function does not consume the line break character(s) after the line.
|
||||
fn scan_block_scalar_content_line(&mut self, string: &mut String, line_buffer: &mut String) {
|
||||
// Start by evaluating characters in the buffer.
|
||||
while !self.input.buf_is_empty() && !is_breakz(self.input.peek()) {
|
||||
while !self.input.buf_is_empty() && !self.input.next_is_breakz() {
|
||||
string.push(self.input.peek());
|
||||
// We may technically skip non-blank characters. However, the only distinction is
|
||||
// to determine what is leading whitespace and what is not. Here, we read the
|
||||
|
@ -1752,7 +1753,7 @@ impl<T: Input> Scanner<T> {
|
|||
}
|
||||
|
||||
// If our current line is empty, skip over the break and continue looping.
|
||||
if is_break(self.input.peek()) {
|
||||
if self.input.next_is_break() {
|
||||
self.read_break(breaks);
|
||||
} else {
|
||||
// Otherwise, we have a content line. Return control.
|
||||
|
@ -1777,7 +1778,7 @@ impl<T: Input> Scanner<T> {
|
|||
max_indent = self.mark.col;
|
||||
}
|
||||
|
||||
if is_break(self.input.peek()) {
|
||||
if self.input.next_is_break() {
|
||||
// If our current line is empty, skip over the break and continue looping.
|
||||
self.input.lookahead(2);
|
||||
self.read_break(breaks);
|
||||
|
@ -1840,7 +1841,7 @@ impl<T: Input> Scanner<T> {
|
|||
));
|
||||
}
|
||||
|
||||
if is_z(self.input.peek()) {
|
||||
if self.input.next_is_z() {
|
||||
return Err(ScanError::new_str(
|
||||
start_mark,
|
||||
"while scanning a quoted scalar, found unexpected end of stream",
|
||||
|
@ -1869,8 +1870,8 @@ impl<T: Input> Scanner<T> {
|
|||
}
|
||||
|
||||
// Consume blank characters.
|
||||
while is_blank(self.input.peek()) || is_break(self.input.peek()) {
|
||||
if is_blank(self.input.peek()) {
|
||||
while self.input.next_is_blank() || self.input.next_is_break() {
|
||||
if self.input.next_is_blank() {
|
||||
// Consume a space or a tab character.
|
||||
if leading_blanks {
|
||||
if self.input.peek() == '\t' && (self.mark.col as isize) < self.indent {
|
||||
|
@ -2118,7 +2119,7 @@ impl<T: Input> Scanner<T> {
|
|||
));
|
||||
}
|
||||
|
||||
if !is_blank_or_breakz(self.input.peek())
|
||||
if !self.input.next_is_blank_or_breakz()
|
||||
&& self.input.next_can_be_plain_scalar(self.flow_level > 0)
|
||||
{
|
||||
if self.leading_whitespace {
|
||||
|
@ -2155,7 +2156,7 @@ impl<T: Input> Scanner<T> {
|
|||
// hence the `for` loop looping `self.input.bufmaxlen() - 1` times.
|
||||
self.input.lookahead(self.input.bufmaxlen());
|
||||
for _ in 0..self.input.bufmaxlen() - 1 {
|
||||
if is_blank_or_breakz(self.input.peek())
|
||||
if self.input.next_is_blank_or_breakz()
|
||||
|| !self.input.next_can_be_plain_scalar(self.flow_level > 0)
|
||||
{
|
||||
end = true;
|
||||
|
@ -2172,13 +2173,14 @@ impl<T: Input> Scanner<T> {
|
|||
// - We reach eof
|
||||
// - We reach ": "
|
||||
// - We find a flow character in a flow context
|
||||
if !(is_blank(self.input.peek()) || is_break(self.input.peek())) {
|
||||
if !(self.input.next_is_blank() || self.input.next_is_break()) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Process blank characters.
|
||||
while is_blank(self.input.look_ch()) || is_break(self.input.peek()) {
|
||||
if is_blank(self.input.peek()) {
|
||||
self.input.lookahead(1);
|
||||
while self.input.next_is_blank_or_break() {
|
||||
if self.input.next_is_blank() {
|
||||
if !self.leading_whitespace {
|
||||
whitespaces.push(self.input.peek());
|
||||
self.skip_blank();
|
||||
|
@ -2186,7 +2188,7 @@ impl<T: Input> Scanner<T> {
|
|||
// Tabs in an indentation columns are allowed if and only if the line is
|
||||
// empty. Skip to the end of the line.
|
||||
self.skip_ws_to_eol(SkipTabs::Yes)?;
|
||||
if !is_breakz(self.input.peek()) {
|
||||
if !self.input.next_is_breakz() {
|
||||
return Err(ScanError::new_str(
|
||||
start_mark,
|
||||
"while scanning a plain scalar, found a tab",
|
||||
|
@ -2196,7 +2198,6 @@ impl<T: Input> Scanner<T> {
|
|||
self.skip_blank();
|
||||
}
|
||||
} else {
|
||||
self.input.lookahead(2);
|
||||
// Check if it is a first line break
|
||||
if self.leading_whitespace {
|
||||
self.read_break(&mut trailing_breaks);
|
||||
|
@ -2206,6 +2207,7 @@ impl<T: Input> Scanner<T> {
|
|||
self.leading_whitespace = true;
|
||||
}
|
||||
}
|
||||
self.input.lookahead(1);
|
||||
}
|
||||
|
||||
// check indentation level
|
||||
|
@ -2309,7 +2311,7 @@ impl<T: Input> Scanner<T> {
|
|||
self.skip_non_blank();
|
||||
if self.input.look_ch() == '\t'
|
||||
&& !self.skip_ws_to_eol(SkipTabs::Yes)?.has_valid_yaml_ws()
|
||||
&& (self.input.peek() == '-' || is_alpha(self.input.peek()))
|
||||
&& (self.input.peek() == '-' || self.input.next_is_alpha())
|
||||
{
|
||||
return Err(ScanError::new_str(
|
||||
self.mark,
|
||||
|
|
Loading…
Reference in a new issue