pcomb 0.3.0

A tiny parser combinator library.
Documentation
//! A standard set of string slice and character slice parsers.

use core::{num, str::FromStr};

extern crate alloc;
use alloc::string::String;

use crate::{parse::ParseError::{self, *}, slice::Slice, Parse};


/// Matches a line and strips the newline.
pub fn line(input: &str) -> Result<(&str, &str), ParseError> {
  if input == "" { return Err(Reject) }

  // fixme: handle all unicode characters https://www.unicode.org/standard/reports/tr13/tr13-5.html
  // todo: generalize this splitting about a delimiter for all T
  let (out, rest) = input.split_once('\n')
    .unwrap_or((input, ""));
  Ok((rest, out))
}

/// Matches a uppercase or lowercase letter
pub fn alpha(input: &str) -> Result<(&str, &str), ParseError> {
  let (char, rest) = Slice::split_at(&input, 1).ok_or(Reject)?;

  // todo: is there a unicode spec on this?
  if "a" <= char && char <= "z" || "A" <= char && char <= "Z" {
    Ok((rest, char))
  } else {
    Err(Reject)
  }
}

#[test]
fn alpha_test() {
  assert_eq!(alpha("t"), Ok(("", "t")));
  assert_eq!(alpha("F"), Ok(("", "F")));
  assert_eq!(alpha("1"), Err(Reject));
}


/// Matches a single numeric digit
pub fn digit(input: &str) -> Result<(&str, &str), ParseError> {
  let (char, rest) = Slice::split_at(&input, 1).ok_or(Reject)?;

  if "0" <= char && char <= "9" {
    Ok((rest, char))
  } else {
    Err(Reject)
  }
}

/// Matches a single numeric digit
pub fn digit_parse(input: &str) -> Result<(&str, u8), ParseError> {
  let (char, rest) = Slice::split_at(&input, 1).ok_or(Reject)?;

  if "0" <= char && char <= "9" {
    Ok((
      rest,
      char.parse::<u8>().map_err(|_| Reject)?
    ))
  } else {
    Err(Reject)
  }
}

#[test]
fn digit_test() {
  assert_eq!(digit("1"), Ok(("", "1")));
  assert_eq!(digit_parse("1"), Ok(("", 1)));
  assert_eq!(digit("953adf"), Ok(("53adf", "9")));
  assert_eq!(digit("d"), Err(Reject));
}


pub fn integer<N: FromStr<Err = num::ParseIntError>>(input: &str) -> Result<(&str, N), ParseError> {
  let (rest, digits) = digit
    .repeat_greedy(String::new())
    .parse(input)?;

  Ok((rest, digits.parse::<N>().map_err(|_| Reject)?))
}

#[test]
fn integer_test() {
  assert_eq!(integer.parse("1984"), Ok(("", 1984u32)));
}