#[macro_use] extern crate chomp; use chomp::prelude::*; use std::rc::Rc; #[derive(Debug, Eq, PartialEq)] struct Name { first: B, last: B, } fn name(i: I) -> SimpleResult> { parse!{i; let first = take_while1(|c| c != b' '); token(b' '); // skipping this char let last = take_while1(|c| c != b'\n'); ret Name{ first: first, last: last, } } } #[derive(Clone)] struct ParseState { buffer: Rc>, index: usize, a: A } impl ParseState { fn new(a: A, buffer: String) -> ParseState { let buffer: Vec = buffer.chars().collect(); ParseState { buffer: Rc::new(buffer), index: 0, a: a } } fn next(&self) -> (ParseState,Option) { if self.index < self.buffer.len() { let new_char = self.buffer[self.index]; let new_index = self.index + 1; (ParseState { buffer: Rc::clone(&self.buffer), index: new_index, a: self.a.clone() }, Some(new_char)) } else { (ParseState { buffer: Rc::clone(&self.buffer), index: self.index, a: self.a.clone() },None) } } } #[derive(Debug)] struct ParseRCon(A,Result,String>); #[derive(Debug)] enum ParseOutput { Success(A), Failure(String) } fn parse(p: &P, st: &ParseState) -> ParseOutput where P: Fn(ParseState) -> ParseRCon,A> { match p(st.clone()) { ParseRCon(_,Ok(Some(a))) => ParseOutput::Success(a), ParseRCon(_,Ok(None)) => ParseOutput::Failure("expected input".to_string()), ParseRCon(_,Err(err)) => ParseOutput::Failure(err) } } fn parse_mzero(st: ParseState) -> ParseRCon,A> { ParseRCon(st,Err("mzero failed".to_string())) } fn parse_return(a: A) -> impl (Fn(ParseState) -> ParseRCon,A>) { move |st| { ParseRCon(st,Ok(Some(a.clone()))) } } fn parse_token(t: T) -> impl (Fn(ParseState) -> ParseRCon,A>) where T: 'static + Fn(char) -> Option { move |st: ParseState| { let (next_state,next_char) = st.clone().next(); match next_char { Some(c) => ParseRCon(next_state,Ok(t(c))), None => ParseRCon(st,Err("end of input".to_string())) } } } fn parse_satisfy(t: T) -> impl (Fn(ParseState) -> ParseRCon,char>) where T: 'static + Fn(char) -> bool { parse_token(move |c| if t(c) {Some(c)} else {None}) } fn parse_bind(p1: P1, b1: B1) -> impl Fn(ParseState) -> ParseRCon,B> where P1: Fn(ParseState) -> ParseRCon,A>, P2: Fn(ParseState) -> ParseRCon,B>, B1: Fn(A) -> P2 { move |st| { match p1(st) { ParseRCon(nst,Ok(Some(a))) => b1(a)(nst), ParseRCon(nst,Ok(None)) => ParseRCon(nst,Err("bind failed".to_string())), ParseRCon(nst,Err(err)) => ParseRCon(nst,Err(err)) } } } fn parse_sequence(p1: P1, p2: P2) -> impl Fn(ParseState) -> ParseRCon,B> where P1: Fn(ParseState) -> ParseRCon,A>, P2: Fn(ParseState) -> ParseRCon,B> { move |st| { match p1(st) { ParseRCon(nst,Ok(_)) => p2(nst), ParseRCon(nst,Err(err)) => ParseRCon(nst,Err(err)) } } } fn parse_or(p1: P1, p2: P2) -> impl Fn(ParseState) -> ParseRCon,A> where P1: Fn(ParseState) -> ParseRCon,A>, P2: Fn(ParseState) -> ParseRCon,A> { move |st| { match p1(st.clone()) { ParseRCon(nst,Ok(Some(a))) => ParseRCon(nst,Ok(Some(a))), ParseRCon(_,Ok(None)) => p2(st), ParseRCon(nst,Err(err)) => ParseRCon(nst,Err(err)) } } } fn compose(f: F, g: G) -> impl Fn(A) -> C where F: 'static + Fn(A) -> B, G: 'static + Fn(B) -> C { move |x| g(f(x)) } fn main() { let fa = |x| x+1; let fb = |y| y*2; let fc = |z| z/3; let g = compose(compose(fa,fb),fc); println!("g(1) = {}", g(1)); println!("g(12) = {}", g(12)); println!("g(123) = {}", g(123)); let parse_result = parse_only(name, "Martin Wernstål\n".as_bytes()).unwrap(); println!("first:{} last:{}", String::from_utf8_lossy(parse_result.first), String::from_utf8_lossy(parse_result.last)); let input1 = ParseState::new((), "1 + 2 * 3".to_string()); let input2 = ParseState::new((), "3 / 2 - 1".to_string()); let p1 = parse_mzero::<(),()>; println!("p1 input1: {:?}", parse(&p1,&input1)); println!("p1 input2: {:?}", parse(&p1,&input2)); let p2 = parse_return(123); println!("p2 input1: {:?}", parse(&p2,&input1)); println!("p2 input2: {:?}", parse(&p2,&input2)); let p3 = parse_satisfy(|c| c=='1'); println!("p3 input1: {:?}", parse(&p3,&input1)); println!("p3 input2: {:?}", parse(&p3,&input2)); let digit = parse_satisfy(|c| c.is_digit(10)); println!("digit input1: {:?}", parse(&digit,&input1)); println!("digit input2: {:?}", parse(&digit,&input2)); let space = parse_satisfy(|c| c==' '); println!("space input1: {:?}", parse(&space,&input1)); println!("space input2: {:?}", parse(&space,&input2)); let operator = parse_satisfy(|c| c=='+' || c=='-' || c=='*' || c=='/'); println!("operator input1: {:?}", parse(&operator,&input1)); println!("operator input2: {:?}", parse(&operator,&input2)); let ps1 = parse_sequence(digit,space); let ps2 = parse_sequence(ps1,operator); println!("digit,space,operator input1: {:?}", parse(&ps2,&input1)); println!("digit,space,operator input2: {:?}", parse(&ps2,&input2)); }