use super::Parser;
use crate::Error;
impl<'a> Parser<'a> {
pub fn skip_whitespace(&mut self) -> crate::Result<&mut Self> {
let input_len = self.input.len();
if self.pos >= input_len {
return Err(self.err_unexpected_eof());
}
if self.input[self.pos] == b' ' {
while self.pos + 1 < input_len && self.input[self.pos + 1] == b' ' {
self.pos += 1;
}
self.pos += 1; Ok(self)
} else {
Err(self.err_expected(Error::EXPECTED_WHITESPACE))
}
}
pub fn skip_newlines_and_spaces(&mut self) {
let input_len = self.input.len();
while self.pos < input_len {
match self.input[self.pos] {
b'\n' => {
self.pos += 1;
self.line += 1;
}
b'\r' => {
self.pos += 1;
if self.pos < input_len && self.input[self.pos] == b'\n' {
self.pos += 1;
}
self.line += 1;
}
b' ' | b'\t' => {
self.pos += 1;
}
_ => break,
}
}
}
pub fn skip_to_end_of_line(&mut self) {
let input_len = self.input.len();
while self.pos < input_len {
let byte = self.input[self.pos];
match byte {
b'\n' => {
self.pos += 1;
self.line += 1;
break;
}
b'\r' => {
self.pos += 1;
if self.pos < input_len && self.input[self.pos] == b'\n' {
self.pos += 1;
}
self.line += 1;
break;
}
_ => {
self.pos += 1;
}
}
}
}
#[inline]
pub fn skip_whitespace_optional(&mut self) {
let _ = self.skip_whitespace();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn skip_whitespace_succeeds_with_space() {
let input = b" test";
let mut parser = Parser::new(input).unwrap();
let result = parser.skip_whitespace();
assert!(result.is_ok());
assert_eq!(parser.remaining(), b"test");
assert_eq!(parser.pos, 1);
}
#[test]
fn skip_whitespace_fails_with_tab() {
let input = b"\ttest";
let mut parser = Parser::new(input).unwrap();
let result = parser.skip_whitespace();
assert!(result.is_err());
match result.unwrap_err() {
Error::Expected { msg, line } => {
assert_eq!(msg, Error::EXPECTED_WHITESPACE);
assert_eq!(line, Some(1));
}
_ => panic!("Expected Error::Expected"),
}
}
#[test]
fn skip_whitespace_fails_with_newline() {
let input = b"\ntest";
let mut parser = Parser::new(input).unwrap();
let result = parser.skip_whitespace();
assert!(result.is_err());
match result.unwrap_err() {
Error::Expected { msg, line } => {
assert_eq!(msg, Error::EXPECTED_WHITESPACE);
assert_eq!(line, Some(1));
}
_ => panic!("Expected Error::Expected"),
}
}
#[test]
fn skip_whitespace_fails_with_carriage_return() {
let input = b"\rtest";
let mut parser = Parser::new(input).unwrap();
let result = parser.skip_whitespace();
assert!(result.is_err());
match result.unwrap_err() {
Error::Expected { msg, line } => {
assert_eq!(msg, Error::EXPECTED_WHITESPACE);
assert_eq!(line, Some(1));
}
_ => panic!("Expected Error::Expected"),
}
}
#[test]
fn skip_whitespace_fails_with_form_feed() {
let input = b"\x0ctest";
let mut parser = Parser::new(input).unwrap();
let result = parser.skip_whitespace();
assert!(result.is_err());
match result.unwrap_err() {
Error::Expected { msg, line } => {
assert_eq!(msg, Error::EXPECTED_WHITESPACE);
assert_eq!(line, Some(1));
}
_ => panic!("Expected Error::Expected"),
}
}
#[test]
fn skip_whitespace_fails_with_non_whitespace() {
let input = b"test";
let mut parser = Parser::new(input).unwrap();
let result = parser.skip_whitespace();
assert!(result.is_err());
match result.unwrap_err() {
Error::Expected { msg, line } => {
assert_eq!(msg, Error::EXPECTED_WHITESPACE);
assert_eq!(line, Some(1));
}
_ => panic!("Expected Error::Expected"),
}
assert_eq!(parser.remaining(), b"test");
assert_eq!(parser.pos, 0);
}
#[test]
fn skip_whitespace_fails_with_empty_input() {
let input = b" ";
let mut parser = Parser::new(input).unwrap();
parser.pos = input.len();
let result = parser.skip_whitespace();
assert!(result.is_err());
match result.unwrap_err() {
Error::UnexpectedEof { .. } => {}
_ => panic!("Expected Error::UnexpectedEof"),
}
}
#[test]
fn skip_whitespace_skips_multiple_spaces() {
let input = b" test";
let mut parser = Parser::new(input).unwrap();
let result = parser.skip_whitespace();
assert!(result.is_ok());
assert_eq!(parser.remaining(), b"test");
assert_eq!(parser.pos, 2);
}
#[test]
fn skip_whitespace_chaining_stops_on_error() {
let input = b" test";
let mut parser = Parser::new(input).unwrap();
let result = parser.skip_whitespace().and_then(|p| p.skip_whitespace());
assert!(result.is_err());
match result.unwrap_err() {
Error::Expected { msg, line } => {
assert_eq!(msg, Error::EXPECTED_WHITESPACE);
assert_eq!(line, Some(1));
}
_ => panic!("Expected Error::Expected"),
}
}
#[test]
fn line_number_increments_on_newline() {
let input = b"line1\nline2";
let mut parser = Parser::new(input).unwrap();
assert_eq!(parser.line(), 1);
parser.expect(b"line1").unwrap();
assert_eq!(parser.line(), 1);
parser.skip_newlines_and_spaces();
assert_eq!(parser.line(), 2);
}
#[test]
fn line_number_increments_on_carriage_return() {
let input = b"line1\rline2";
let mut parser = Parser::new(input).unwrap();
assert_eq!(parser.line(), 1);
parser.expect(b"line1").unwrap();
assert_eq!(parser.line(), 1);
parser.skip_newlines_and_spaces();
assert_eq!(parser.line(), 2);
}
#[test]
fn line_number_treats_crlf_as_single_newline() {
let input = b"line1\r\nline2";
let mut parser = Parser::new(input).unwrap();
assert_eq!(parser.line(), 1);
parser.expect(b"line1").unwrap();
assert_eq!(parser.line(), 1);
parser.skip_newlines_and_spaces();
assert_eq!(parser.line(), 2);
}
#[test]
fn line_number_counts_multiple_newlines() {
let input = b"line1\n\n\nline4";
let mut parser = Parser::new(input).unwrap();
assert_eq!(parser.line(), 1);
parser.expect(b"line1").unwrap();
assert_eq!(parser.line(), 1);
parser.skip_newlines_and_spaces();
assert_eq!(parser.line(), 4);
}
#[test]
fn skip_to_end_of_line_increments_line() {
let input = b"line1\nline2";
let mut parser = Parser::new(input).unwrap();
assert_eq!(parser.line(), 1);
parser.skip_to_end_of_line();
assert_eq!(parser.line(), 2);
}
#[test]
fn expect_increments_line_when_skipping_newlines() {
let input = b"test\nrest";
let mut parser = Parser::new(input).unwrap();
assert_eq!(parser.line(), 1);
parser.expect(b"test\n").unwrap();
assert_eq!(parser.line(), 2);
}
}