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);
}
}