use crate::parser::{code, predicate, Input, ParseError, ParseResult};
use super::{char, CharacterError};
pub fn alpha0(input: Input<'_>) -> ParseResult<&str> {
let mut cursor = input;
let output = cursor.advance_while(predicate::is_ascii_alpha);
Ok((output, cursor))
}
pub fn alpha1(input: Input<'_>) -> ParseResult<&str> {
if let Some(ch) = input.current() {
if !predicate::is_ascii_alpha(ch) {
return Err(ParseError::new(
input,
code::ERR_ALPHA,
CharacterError::Alpha,
));
}
alpha0(input)
} else {
Err(ParseError::eof(input).and(input, code::ERR_ALPHA, CharacterError::Alpha))
}
}
pub fn alphanum0(input: Input<'_>) -> ParseResult<&str> {
let mut cursor = input;
let output = cursor.advance_while(predicate::is_ascii_alphanum);
Ok((output, cursor))
}
pub fn alphanum1(input: Input<'_>) -> ParseResult<&str> {
if let Some(ch) = input.current() {
if !predicate::is_ascii_alphanum(ch) {
return Err(ParseError::new(
input,
code::ERR_ALPHANUM,
CharacterError::AlphaNum,
));
}
alphanum0(input)
} else {
Err(ParseError::eof(input).and(input, code::ERR_ALPHANUM, CharacterError::AlphaNum))
}
}
pub fn digit0(input: Input<'_>) -> ParseResult<&str> {
let mut cursor = input;
let output = cursor.advance_while(predicate::is_digit);
Ok((output, cursor))
}
pub fn digit1(input: Input<'_>) -> ParseResult<&str> {
if let Some(ch) = input.current() {
if !predicate::is_digit(ch) {
return Err(ParseError::new(
input,
code::ERR_DIGIT,
CharacterError::Digit,
));
}
digit0(input)
} else {
Err(ParseError::eof(input).and(input, code::ERR_DIGIT, CharacterError::Digit))
}
}
pub fn bin_digit0(input: Input<'_>) -> ParseResult<&str> {
let mut cursor = input;
let output = cursor.advance_while(predicate::is_bin_digit);
Ok((output, cursor))
}
pub fn bin_digit1(input: Input<'_>) -> ParseResult<&str> {
if let Some(ch) = input.current() {
if !predicate::is_bin_digit(ch) {
return Err(ParseError::new(
input,
code::ERR_BIN_DIGIT,
CharacterError::BinDigit,
));
}
bin_digit0(input)
} else {
Err(ParseError::eof(input).and(input, code::ERR_BIN_DIGIT, CharacterError::BinDigit))
}
}
pub fn oct_digit0(input: Input<'_>) -> ParseResult<&str> {
let mut cursor = input;
let output = cursor.advance_while(predicate::is_oct_digit);
Ok((output, cursor))
}
pub fn oct_digit1(input: Input<'_>) -> ParseResult<&str> {
if let Some(ch) = input.current() {
if !predicate::is_oct_digit(ch) {
return Err(ParseError::new(
input,
code::ERR_OCT_DIGIT,
CharacterError::OctDigit,
));
}
oct_digit0(input)
} else {
Err(ParseError::eof(input).and(input, code::ERR_OCT_DIGIT, CharacterError::OctDigit))
}
}
pub fn hex_digit0(input: Input<'_>) -> ParseResult<&str> {
let mut cursor = input;
let output = cursor.advance_while(predicate::is_hex_digit);
Ok((output, cursor))
}
pub fn hex_digit1(input: Input<'_>) -> ParseResult<&str> {
if let Some(ch) = input.current() {
if !predicate::is_hex_digit(ch) {
return Err(ParseError::new(
input,
code::ERR_HEX_DIGIT,
CharacterError::HexDigit,
));
}
hex_digit0(input)
} else {
Err(ParseError::eof(input).and(input, code::ERR_HEX_DIGIT, CharacterError::HexDigit))
}
}
pub fn whitespace0(input: Input<'_>) -> ParseResult<&str> {
let mut cursor = input;
let output = cursor.advance_while(predicate::is_ascii_whitespace);
Ok((output, cursor))
}
pub fn whitespace1(input: Input<'_>) -> ParseResult<&str> {
if let Some(ch) = input.current() {
if !predicate::is_ascii_whitespace(ch) {
return Err(ParseError::new(
input,
code::ERR_WHITESPACE,
CharacterError::Whitespace,
));
}
whitespace0(input)
} else {
Err(ParseError::eof(input).and(input, code::ERR_WHITESPACE, CharacterError::Whitespace))
}
}
pub fn space0(input: Input<'_>) -> ParseResult<&str> {
let mut cursor = input;
let output = cursor.advance_while(predicate::is_ascii_space);
Ok((output, cursor))
}
pub fn space1(input: Input<'_>) -> ParseResult<&str> {
if let Some(ch) = input.current() {
if !predicate::is_ascii_space(ch) {
return Err(ParseError::new(
input,
code::ERR_SPACE,
CharacterError::Space,
));
}
space0(input)
} else {
Err(ParseError::eof(input).and(input, code::ERR_SPACE, CharacterError::Space))
}
}
pub fn graphic0(input: Input<'_>) -> ParseResult<&str> {
let mut cursor = input;
let output = cursor.advance_while(|ch| ch.is_ascii_graphic());
Ok((output, cursor))
}
pub fn graphic1(input: Input<'_>) -> ParseResult<&str> {
if let Some(ch) = input.current() {
if !predicate::is_ascii_printable(ch) {
return Err(ParseError::new(
input,
code::ERR_GRAPHIC,
CharacterError::Graphic,
));
}
graphic0(input)
} else {
Err(ParseError::eof(input).and(input, code::ERR_GRAPHIC, CharacterError::Graphic))
}
}
pub fn line_ending(input: Input<'_>) -> ParseResult<&str> {
let mut cursor = input;
match cursor.current() {
Some('\r') => {
if cursor.advance() == Some('\n') {
cursor.advance();
Ok(("\r\n", cursor))
} else {
Err(ParseError::new(
input,
code::ERR_LINE_ENDING,
CharacterError::LineEnding,
))
}
}
Some('\n') => {
cursor.advance();
Ok(("\n", cursor))
}
Some(_) => Err(ParseError::new(
input,
code::ERR_LINE_ENDING,
CharacterError::LineEnding,
)),
None => Err(ParseError::eof(input).and(
input,
code::ERR_LINE_ENDING,
CharacterError::LineEnding,
)),
}
}
pub fn crlf(input: Input<'_>) -> ParseResult<&str> {
let mut cursor = input;
match (cursor.current(), cursor.advance()) {
(Some('\r'), Some('\n')) => {
cursor.advance();
Ok(("\r\n", cursor))
}
(Some('\r'), None) | (None, _) => {
Err(ParseError::eof(input).and(input, code::ERR_LINE_ENDING, CharacterError::Crlf))
}
(Some(_), _) => Err(ParseError::new(
input,
code::ERR_LINE_ENDING,
CharacterError::Crlf,
)),
}
}
#[inline]
pub fn newline(input: Input<'_>) -> ParseResult<char> {
char('\n')(input).map_err(|error| error.and(input, code::ERR_NEWLINE, CharacterError::Newline))
}
#[inline]
pub fn tab(input: Input<'_>) -> ParseResult<char> {
char('\t')(input).map_err(|error| error.and(input, code::ERR_TAB, CharacterError::Tab))
}
#[cfg(test)]
mod tests {
use crate::Position;
use super::*;
#[test]
fn alpha_chars() {
let (output, input) = alpha0(Input::from("abc123")).expect("valid output");
assert_eq!(output, "abc");
assert_eq!(input, Input::from("123"));
let (output, input) = alpha0(Input::from("123abc")).expect("valid output");
assert_eq!(output, "");
assert_eq!(input, Input::from("123abc"));
let (output, input) = alpha1(Input::from("abc123")).expect("valid output");
assert_eq!(output, "abc");
assert_eq!(input, Input::from("123"));
let error = alpha1(Input::from("123abc")).expect_err("error output");
assert_eq!(
error,
ParseError::new(
Position::new(0, 1, 1),
code::ERR_ALPHA,
CharacterError::Alpha
)
);
let error = alpha1(Input::from("")).expect_err("error output");
assert!(error.is_eof());
assert_eq!(
error,
ParseError::eof(Position::new(0, 1, 1)).and(
Position::new(0, 1, 1),
code::ERR_ALPHA,
CharacterError::Alpha
)
);
}
#[test]
fn alphanum_chars() {
let (output, input) = alphanum0(Input::from("abc123")).expect("valid output");
assert_eq!(output, "abc123");
assert_eq!(input, Input::from(""));
let (output, input) = alphanum0(Input::from("123abc")).expect("valid output");
assert_eq!(output, "123abc");
assert_eq!(input, Input::from(""));
let (output, input) = alphanum1(Input::from("abc123")).expect("valid output");
assert_eq!(output, "abc123");
assert_eq!(input, Input::from(""));
let error = alphanum1(Input::from("_123abc")).expect_err("error output");
assert_eq!(
error,
ParseError::new(
Position::new(0, 1, 1),
code::ERR_ALPHANUM,
CharacterError::AlphaNum
)
);
let error = alphanum1(Input::from("")).expect_err("error output");
assert!(error.is_eof());
assert_eq!(
error,
ParseError::eof(Position::new(0, 1, 1)).and(
Position::new(0, 1, 1),
code::ERR_ALPHANUM,
CharacterError::AlphaNum
)
);
}
#[test]
fn bin_digits() {
let (output, input) = bin_digit0(Input::from("0101")).expect("valid output");
assert_eq!(output, "0101");
assert_eq!(input, Input::from(""));
assert_eq!(input.current(), None);
assert_eq!(input.position(), Position::new(4, 1, 5));
let (output, input) = bin_digit0(Input::from("20101")).expect("valid output");
assert_eq!(output, "");
assert_eq!(input, Input::from("20101"));
assert_eq!(input.current(), Some('2'));
assert_eq!(input.position(), Position::new(0, 1, 1));
let (output, input) = bin_digit0(Input::from("a0101")).expect("valid output");
assert_eq!(output, "");
assert_eq!(input, Input::from("a0101"));
assert_eq!(input.current(), Some('a'));
assert_eq!(input.position(), Position::new(0, 1, 1));
let (output, input) = bin_digit1(Input::from("0101")).expect("valid output");
assert_eq!(output, "0101");
assert_eq!(input, Input::from(""));
assert_eq!(input.current(), None);
assert_eq!(input.position(), Position::new(4, 1, 5));
let error = bin_digit1(Input::from("20101")).expect_err("error output");
assert_eq!(
error,
ParseError::new(
Position::new(0, 1, 1),
code::ERR_BIN_DIGIT,
CharacterError::BinDigit
)
);
let error = bin_digit1(Input::from("a0101")).expect_err("error output");
assert_eq!(
error,
ParseError::new(
Position::new(0, 1, 1),
code::ERR_BIN_DIGIT,
CharacterError::BinDigit
)
);
let error = bin_digit1(Input::from("")).expect_err("error output");
assert!(error.is_eof());
assert_eq!(
error,
ParseError::eof(Position::new(0, 1, 1)).and(
Position::new(0, 1, 1),
code::ERR_BIN_DIGIT,
CharacterError::BinDigit
)
);
}
#[test]
fn oct_digits() {
let (output, input) = oct_digit0(Input::from("01234567")).expect("valid output");
assert_eq!(output, "01234567");
assert_eq!(input, Input::from(""));
assert_eq!(input.current(), None);
assert_eq!(input.position(), Position::new(8, 1, 9));
let (output, input) = oct_digit0(Input::from("801234567")).expect("valid output");
assert_eq!(output, "");
assert_eq!(input, Input::from("801234567"));
assert_eq!(input.current(), Some('8'));
assert_eq!(input.position(), Position::new(0, 1, 1));
let (output, input) = oct_digit0(Input::from("a01234567")).expect("valid output");
assert_eq!(output, "");
assert_eq!(input, Input::from("a01234567"));
assert_eq!(input.current(), Some('a'));
assert_eq!(input.position(), Position::new(0, 1, 1));
let (output, input) = oct_digit1(Input::from("01234567")).expect("valid output");
assert_eq!(output, "01234567");
assert_eq!(input, Input::from(""));
assert_eq!(input.current(), None);
assert_eq!(input.position(), Position::new(8, 1, 9));
let error = oct_digit1(Input::from("801234567")).expect_err("error output");
assert_eq!(
error,
ParseError::new(
Position::new(0, 1, 1),
code::ERR_OCT_DIGIT,
CharacterError::OctDigit
)
);
let error = oct_digit1(Input::from("a01234567")).expect_err("error output");
assert_eq!(
error,
ParseError::new(
Position::new(0, 1, 1),
code::ERR_OCT_DIGIT,
CharacterError::OctDigit
)
);
let error = oct_digit1(Input::from("")).expect_err("error output");
assert!(error.is_eof());
assert_eq!(
error,
ParseError::eof(Position::new(0, 1, 1)).and(
Position::new(0, 1, 1),
code::ERR_OCT_DIGIT,
CharacterError::OctDigit
)
);
}
#[test]
fn digits() {
let (output, input) = digit0(Input::from("0123456789")).expect("valid output");
assert_eq!(output, "0123456789");
assert_eq!(input, Input::from(""));
assert_eq!(input.current(), None);
assert_eq!(input.position(), Position::new(10, 1, 11));
let (output, input) = digit0(Input::from("a0123456789")).expect("valid output");
assert_eq!(output, "");
assert_eq!(input, Input::from("a0123456789"));
assert_eq!(input.current(), Some('a'));
assert_eq!(input.position(), Position::new(0, 1, 1));
let (output, input) = digit1(Input::from("0123456789")).expect("valid output");
assert_eq!(output, "0123456789");
assert_eq!(input, Input::from(""));
assert_eq!(input.current(), None);
assert_eq!(input.position(), Position::new(10, 1, 11));
let error = digit1(Input::from("a0123456789")).expect_err("error output");
assert_eq!(
error,
ParseError::new(
Position::new(0, 1, 1),
code::ERR_DIGIT,
CharacterError::Digit
)
);
let error = digit1(Input::from("")).expect_err("error output");
assert!(error.is_eof());
assert_eq!(
error,
ParseError::eof(Position::new(0, 1, 1)).and(
Position::new(0, 1, 1),
code::ERR_DIGIT,
CharacterError::Digit
)
);
}
#[test]
fn hex_digits() {
let (output, input) = hex_digit0(Input::from("0123456789abcdef")).expect("valid output");
assert_eq!(output, "0123456789abcdef");
assert_eq!(input, Input::from(""));
assert_eq!(input.current(), None);
assert_eq!(input.position(), Position::new(16, 1, 17));
let (output, input) = hex_digit0(Input::from("g0123456789abcdef")).expect("valid output");
assert_eq!(output, "");
assert_eq!(input, Input::from("g0123456789abcdef"));
assert_eq!(input.current(), Some('g'));
assert_eq!(input.position(), Position::new(0, 1, 1));
let (output, input) = hex_digit1(Input::from("0123456789abcdef")).expect("valid output");
assert_eq!(output, "0123456789abcdef");
assert_eq!(input, Input::from(""));
assert_eq!(input.current(), None);
assert_eq!(input.position(), Position::new(16, 1, 17));
let error = hex_digit1(Input::from("g0123456789abcdef")).expect_err("error output");
assert_eq!(
error,
ParseError::new(
Position::new(0, 1, 1),
code::ERR_HEX_DIGIT,
CharacterError::HexDigit
)
);
let error = hex_digit1(Input::from("")).expect_err("error output");
assert!(error.is_eof());
assert_eq!(
error,
ParseError::eof(Position::new(0, 1, 1)).and(
Position::new(0, 1, 1),
code::ERR_HEX_DIGIT,
CharacterError::HexDigit
)
);
}
#[test]
fn whitespaces() {
let (output, input) = whitespace0(Input::from(" \t\n\r")).expect("valid output");
assert_eq!(output, " \t\n\r");
assert_eq!(input, Input::from(""));
assert_eq!(input.current(), None);
assert_eq!(input.position(), Position::new(4, 2, 1));
let (output, input) = whitespace0(Input::from("a \t\n\r")).expect("valid output");
assert_eq!(output, "");
assert_eq!(input, Input::from("a \t\n\r"));
assert_eq!(input.current(), Some('a'));
assert_eq!(input.position(), Position::new(0, 1, 1));
let (output, input) = whitespace1(Input::from(" \t\n\r")).expect("valid output");
assert_eq!(output, " \t\n\r");
assert_eq!(input, Input::from(""));
assert_eq!(input.current(), None);
assert_eq!(input.position(), Position::new(4, 2, 1));
let error = whitespace1(Input::from("a \t\n\r")).expect_err("error output");
assert_eq!(
error,
ParseError::new(
Position::new(0, 1, 1),
code::ERR_WHITESPACE,
CharacterError::Whitespace
)
);
let error = whitespace1(Input::from("")).expect_err("error output");
assert!(error.is_eof());
assert_eq!(
error,
ParseError::eof(Position::new(0, 1, 1)).and(
Position::new(0, 1, 1),
code::ERR_WHITESPACE,
CharacterError::Whitespace
)
);
}
#[test]
fn spaces() {
let (output, input) = space0(Input::from(" \t")).expect("valid output");
assert_eq!(output, " \t");
assert_eq!(input, Input::from(""));
assert_eq!(input.current(), None);
assert_eq!(input.position(), Position::new(2, 1, 3));
let (output, input) = space0(Input::from("a \t")).expect("valid output");
assert_eq!(output, "");
assert_eq!(input, Input::from("a \t"));
assert_eq!(input.current(), Some('a'));
assert_eq!(input.position(), Position::new(0, 1, 1));
let (output, input) = space1(Input::from(" \t")).expect("valid output");
assert_eq!(output, " \t");
assert_eq!(input, Input::from(""));
assert_eq!(input.current(), None);
assert_eq!(input.position(), Position::new(2, 1, 3));
let error = space1(Input::from("a \t")).expect_err("error output");
assert_eq!(
error,
ParseError::new(
Position::new(0, 1, 1),
code::ERR_SPACE,
CharacterError::Space
)
);
let error = space1(Input::from("")).expect_err("error output");
assert!(error.is_eof());
assert_eq!(
error,
ParseError::eof(Position::new(0, 1, 1)).and(
Position::new(0, 1, 1),
code::ERR_SPACE,
CharacterError::Space
)
);
}
#[test]
fn graphics() {
let (output, input) = graphic0(Input::from("abc")).expect("valid output");
assert_eq!(output, "abc");
assert_eq!(input, Input::from(""));
assert_eq!(input.current(), None);
assert_eq!(input.position(), Position::new(3, 1, 4));
let (output, input) = graphic0(Input::from(" abc")).expect("valid output");
assert_eq!(output, "");
assert_eq!(input, Input::from(" abc"));
assert_eq!(input.current(), Some(' '));
assert_eq!(input.position(), Position::new(0, 1, 1));
let (output, input) = graphic1(Input::from("abc")).expect("valid output");
assert_eq!(output, "abc");
assert_eq!(input, Input::from(""));
assert_eq!(input.current(), None);
assert_eq!(input.position(), Position::new(3, 1, 4));
let error = graphic1(Input::from(" abc")).expect_err("error output");
assert_eq!(
error,
ParseError::new(
Position::new(0, 1, 1),
code::ERR_GRAPHIC,
CharacterError::Graphic
)
);
let error = graphic1(Input::from("")).expect_err("error output");
assert!(error.is_eof());
assert_eq!(
error,
ParseError::eof(Position::new(0, 1, 1)).and(
Position::new(0, 1, 1),
code::ERR_GRAPHIC,
CharacterError::Graphic
)
);
}
#[test]
fn line_endings() {
let (output, input) = line_ending(Input::from("\r\n")).expect("valid output");
assert_eq!(output, "\r\n");
assert_eq!(input, Input::from(""));
assert_eq!(input.current(), None);
assert_eq!(input.position(), Position::new(2, 2, 1));
let (output, input) = line_ending(Input::from("\n")).expect("valid output");
assert_eq!(output, "\n");
assert_eq!(input, Input::from(""));
assert_eq!(input.current(), None);
assert_eq!(input.position(), Position::new(1, 2, 1));
let error = line_ending(Input::from("\r")).expect_err("error output");
assert_eq!(
error,
ParseError::new(
Position::new(0, 1, 1),
code::ERR_LINE_ENDING,
CharacterError::LineEnding
)
);
let error = line_ending(Input::from("\r\r")).expect_err("error output");
assert_eq!(
error,
ParseError::new(
Position::new(0, 1, 1),
code::ERR_LINE_ENDING,
CharacterError::LineEnding
)
);
let error = line_ending(Input::from("")).expect_err("error output");
assert!(error.is_eof());
assert_eq!(
error,
ParseError::eof(Position::new(0, 1, 1)).and(
Position::new(0, 1, 1),
code::ERR_LINE_ENDING,
CharacterError::LineEnding
)
);
}
#[test]
fn crlfs() {
let (output, input) = crlf(Input::from("\r\n")).expect("valid output");
assert_eq!(output, "\r\n");
assert_eq!(input, Input::from(""));
assert_eq!(input.current(), None);
assert_eq!(input.position(), Position::new(2, 2, 1));
let error = crlf(Input::from("\n")).expect_err("error output");
assert_eq!(
error,
ParseError::new(
Position::new(0, 1, 1),
code::ERR_LINE_ENDING,
CharacterError::Crlf
)
);
let error = crlf(Input::from("\ra")).expect_err("error output");
assert_eq!(
error,
ParseError::new(
Position::new(0, 1, 1),
code::ERR_LINE_ENDING,
CharacterError::Crlf
)
);
let error = crlf(Input::from("\r")).expect_err("error output");
assert_eq!(
error,
ParseError::new(
Position::new(0, 1, 1),
code::ERR_LINE_ENDING,
CharacterError::Crlf
)
);
}
}