pcomb 0.3.0

A tiny parser combinator library.
Documentation
use std::error::Error;
use std::io::stdin;

use pcomb::parse::{Match, ParseError, Parse};
use pcomb::parsers::str::integer;

#[derive(Debug, PartialEq, Eq)]
pub enum Token {
  Int(u64),
  Add,
  Sub,
  Mul,
  Div,
}

use Token::*;

pub fn lex_token<'a>(input: &'a str) -> Result<(&'a str, Token), ParseError> {
  integer.map(|n| Int(n))
    .or(
      Match("+").map(|_| Add)
    )
    .or(
      Match("-").map(|_| Sub)
    )
    .or(
      Match("*").map(|_| Mul)
    )
    .or(
      Match("/").map(|_| Div)
    )
    .parse(input)
}

pub fn lex_tokens(input: &str) -> Result<(&str, Vec<Token>), ParseError> {
  lex_token.repeat_greedy(Vec::new()).parse(input)
}

#[test]
fn lex_token_test() {
  assert_eq!(lex_token.parse("27a"), Ok(("a", Int(27))));
  assert_eq!(lex_token.parse("*"), Ok(("", Mul)));
  assert_eq!(
    lex_token.fuse(lex_token).parse("-2"),
    Ok(("", (Sub, Int(2))))
  );
}

#[test]
fn lex_tokens_const_test() {
  let parse6 = lex_token.repeat_const::<6>();

  assert_eq!(
    parse6.parse("-27+355*2"),
    Ok(("", [Sub, Int(27), Add, Int(355), Mul, Int(2)]))
  );
}

#[test]
fn lex_tokens_test() {
  assert_eq!(
    lex_tokens.parse("-27+355*2"),
    Ok(("", vec![Sub, Int(27), Add, Int(355), Mul, Int(2)]))
  );
}

fn main() -> Result<(), Box<dyn Error>> {
  println!("Type mathematical expressions one line at a time. An empty expression quits.");

  loop {
    let mut buf = String::new();
    stdin().read_line(&mut buf).map_err(|err| Box::new(err))?;

    let buf = buf.trim();

    if buf == "" { return Ok(()) }

    let tokens = lex_tokens.parse(buf);
    println!("{:?}\n", tokens);
  }
}