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