combpop 0.0.3

Type-based parser combinator
Documentation
use std::char;
use std::marker::PhantomData;
use {Consume, ParseError, ParseResult, Parser, ParserBase, ParserMut, ParserOnce, Stream};
use combinators::{any_token, AnyToken};

pub fn any_byte() -> AnyToken<u8> {
    any_token()
}

pub fn any_char() -> AnyChar {
    AnyChar(PhantomData)
}

pub struct AnyChar(PhantomData<()>);

impl ParserBase for AnyChar {
    type Input = u8;
    type Output = char;
}
impl<S: Stream<Item = u8> + ?Sized> ParserOnce<S> for AnyChar {
    delegate_parser_once!(char(|_| true));
    fn emit_expectations(&self, _stream: &mut S) {
        // TODO: "any char"
    }
}
impl<S: Stream<Item = u8> + ?Sized> ParserMut<S> for AnyChar {
    delegate_parser_mut!(&mut char(|_| true));
}
impl<S: Stream<Item = u8> + ?Sized> Parser<S> for AnyChar {
    delegate_parser!(&char(|_| true));
}

pub fn char_once<F: FnOnce(char) -> bool>(f: F) -> Char<F> {
    Char(f)
}

pub fn char_mut<F: FnMut(char) -> bool>(f: F) -> Char<F> {
    Char(f)
}

pub fn char<F: Fn(char) -> bool>(f: F) -> Char<F> {
    Char(f)
}

pub struct Char<F: FnOnce(char) -> bool>(F);

impl<F: FnOnce(char) -> bool> ParserBase for Char<F> {
    type Input = u8;
    type Output = char;
}
impl<F: FnOnce(char) -> bool, S: Stream<Item = u8> + ?Sized> ParserOnce<S> for Char<F> {
    fn parse_lookahead_once(self, stream: &mut S) -> ParseResult<Option<(char, Consume)>> {
        let b0 = match stream.lookahead(1) {
            Ok(()) => *stream.get(0),
            Err(ParseError::EOF) => return Ok(None),
            Err(e) => return Err(e),
        };
        macro_rules! get {
            ($i:expr, $min:expr, $max:expr) => {{
                let b = match stream.lookahead($i + 1) {
                    Ok(()) => *stream.get($i),
                    Err(ParseError::EOF) => return Ok(None),
                    Err(e) => return Err(e),
                };
                if !($min <= b && b < $max) {
                    return Err(ParseError::SyntaxError)
                };
                b
            }};
        }
        let (c, n) = if b0 < 0x80 {
            (b0 as char, 1)
        } else if b0 < 0xC2 {
            return Ok(None);
        } else if b0 < 0xE0 {
            let b0 = b0 as u32;
            let b1 = get!(1, 0x80, 0xC0) as u32;
            let c = ((b0 & 0x1F) << 6) | (b1 & 0x3F);
            (unsafe { char::from_u32_unchecked(c) }, 2)
        } else if b0 < 0xF0 {
            let b1lim = if b0 == 0xE0 { 0xA0 } else { 0x80 };
            let b0 = b0 as u32;
            let b1 = get!(1, b1lim, 0xC0) as u32;
            // Reject upper/lower surrogates (U+D800 to U+DFFF)
            if b0 == 0xED && b1 >= 0xA0 {
                return Ok(None);
            }
            let b2 = get!(2, 0x80, 0xC0) as u32;
            let c = ((b0 & 0x0F) << 12) | ((b1 & 0x3F) << 6) | (b2 & 0x3F);
            (unsafe { char::from_u32_unchecked(c) }, 3)
        } else if b0 < 0xF8 {
            let b1lim = if b0 == 0xF0 { 0x90 } else { 0x80 };
            let b0 = b0 as u32;
            let b1 = get!(1, b1lim, 0xC0) as u32;
            let b2 = get!(2, 0x80, 0xC0) as u32;
            let b3 = get!(3, 0x80, 0xC0) as u32;
            let c = ((b0 & 0x07) << 18) | ((b1 & 0x3F) << 12) | ((b2 & 0x3F) << 6) | (b3 & 0x3F);
            (unsafe { char::from_u32_unchecked(c) }, 4)
        } else {
            return Ok(None);
        };
        if !(self.0)(c) {
            return Ok(None);
        }
        stream.advance(n);
        Ok(Some((c, Consume::Consumed)))
    }
    fn emit_expectations(&self, _stream: &mut S) {
        // TODO: "a char"
    }
}
impl<F: FnMut(char) -> bool, S: Stream<Item = u8> + ?Sized> ParserMut<S> for Char<F> {
    fn parse_lookahead_mut(&mut self, stream: &mut S) -> ParseResult<Option<(char, Consume)>> {
        ParserOnce::parse_lookahead_once(char_once(&mut self.0), stream)
    }
}
impl<F: Fn(char) -> bool, S: Stream<Item = u8> + ?Sized> Parser<S> for Char<F> {
    fn parse_lookahead(&self, stream: &mut S) -> ParseResult<Option<(char, Consume)>> {
        ParserOnce::parse_lookahead_once(char_once(&self.0), stream)
    }
}

pub fn alpha() -> Alpha {
    Alpha(PhantomData)
}

pub struct Alpha(PhantomData<()>);

impl ParserBase for Alpha {
    type Input = u8;
    type Output = char;
}
impl<S: Stream<Item = u8> + ?Sized> ParserOnce<S> for Alpha {
    delegate_parser_once!(char(char::is_alphabetic));
    fn emit_expectations(&self, _stream: &mut S) {
        // TODO: "alphabetic character"
    }
}
impl<S: Stream<Item = u8> + ?Sized> ParserMut<S> for Alpha {
    delegate_parser_mut!(&mut char(char::is_alphabetic));
}
impl<S: Stream<Item = u8> + ?Sized> Parser<S> for Alpha {
    delegate_parser!(&char(char::is_alphabetic));
}

#[cfg(test)]
mod tests {
    use super::*;
    use stream::SliceStream;
    use ParserIteratorBase;

    #[test]
    fn test_alpha() {
        let p = alpha().many1().collect::<String>();
        assert_eq!(p.parse(&mut SliceStream::new(b"hoge")).unwrap(), "hoge");
        assert_eq!(
            p.parse(&mut SliceStream::new(b"hoge fuga")).unwrap(),
            "hoge"
        );
        assert!(p.parse(&mut SliceStream::new(b" hoge")).is_err());
        assert!(p.parse(&mut SliceStream::new(b"")).is_err());
    }
}