<commit_before>extern crate byteorder;

use std::error;
use std::fmt;
use std::io;
use std::str;

use self::byteorder::{ByteOrder, BigEndian, LittleEndian};

use super::{Catalog, Message};

/// Represents an error encountered while parsing an MO file.
#[derive(Debug)]
pub enum Error {
    /// An incorrect magic number has been encountered
    BadMagic,
    /// An invalid byte sequence for the given encoding has been encountered
    DecodingError,
    /// An unexpected EOF occured
    Eof,
    /// An I/O error occured
    Io(io::Error),
}
// Can not use use `Error::*` as per this issue:
// (https://github.com/rust-lang/rust/issues/4865)
use Error::{BadMagic, DecodingError, Eof, Io};

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            BadMagic => "bad magic number",
            DecodingError => "invalid byte sequence in a string",
            Eof => "unxpected end of file",
            Io(ref err) => err.description(),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let self_err: &error::Error = self;
        write!(fmt, "{}", self_err.description())
    }
}

impl From<io::Error> for Error {
    fn from(inner: io::Error) -> Error {
        Io(inner)
    }
}

/// According to the given magic number of a MO file,
/// returns the function which reads a `u32` in the relevant endianness.
fn get_read_u32_fn(magic: &[u8]) -> Option<fn(&[u8]) -> u32> {
    if magic == [0xde, 0x12, 0x04, 0x95] {
        Some(LittleEndian::read_u32)
    } else if magic == [0x95, 0x04, 0x12, 0xde] {
        Some(BigEndian::read_u32)
    } else {
        None
    }
}

fn from_utf8(bytes: &[u8]) -> Result<&str, Error> {
    str::from_utf8(bytes).map_err(|_| DecodingError)
}

pub fn parse_catalog<R: io::Read>(mut file: R) -> Result<Catalog, Error> {
    let mut contents = vec![];
    let n = try!(file.read_to_end(&mut contents));
    if n < 28 {
        return Err(Eof);
    }

    let read_u32 = match get_read_u32_fn(&contents[0..4]) {
        Some(f) => f,
        None => return Err(BadMagic),
    };

    // ignore hashing tables (bytes at 20..28)
    let num_strings = read_u32(&contents[8..12]) as usize;
    let mut off_otable = read_u32(&contents[12..16]) as usize;
    let mut off_ttable = read_u32(&contents[16..20]) as usize;
    if n < off_otable || n < off_ttable {
        return Err(Eof);
    }

    let mut catalog = Catalog::new();
    for _ in 0..num_strings {
        let id;
        let context;
        let translated: Vec<&str>;
        // Parse the original string
        {
            if n < off_otable + 8 {
                return Err(Eof);
            }
            let len = read_u32(&contents[off_otable..off_otable + 4]) as usize;
            let off = read_u32(&contents[off_otable + 4..off_otable + 8]) as usize;
            if n < off + len {
                return Err(Eof);
            }
            let mut original = &contents[off..off + len];
            // check for context
            context = match original.iter().position(|x| *x == 4) {
                Some(idx) => {
                    let ctx = &original[..idx];
                    original = &original[idx + 1..];
                    Some(try!(from_utf8(ctx)))
                }
                None => None,
            };
            // extract msg_id singular, ignoring the plural
            id = match original.iter().position(|x| *x == 0).map(|i| &original[..i]) {
                Some(b) => try!(from_utf8(b)),
                None => return Err(Eof),
            };
        }

        // Parse the translation strings
        {
            if n < off_ttable + 8 {
                return Err(Eof);
            }
            let len = read_u32(&contents[off_ttable..off_ttable + 4]) as usize;
            let off = read_u32(&contents[off_ttable + 4..off_ttable + 8]) as usize;
            if n < off + len {
                return Err(Eof);
            }
            let decode_results = (&contents[off..off + len])
                                     .split(|x| *x == 0)
                                     .map(from_utf8)
                                     .collect::<Vec<_>>();
            if decode_results.iter().any(|r| r.is_err()) {
                return Err(DecodingError);
            }
            translated = decode_results.into_iter().map(|r| r.unwrap()).collect();
        }

        catalog.insert(Message::new(id, context, translated));

        off_otable += 8;
        off_ttable += 8;
    }

    Ok(catalog)
}

#[test]
fn test_get_read_u32_fn() {
    use std::mem;

    assert!(get_read_u32_fn(&[]).is_none());
    assert!(get_read_u32_fn(&[0xde, 0x12, 0x04, 0x95, 0x00]).is_none());

    {
        let le_ptr: *const ();
        let ret_ptr;
        unsafe {
            le_ptr = mem::transmute(LittleEndian::read_u32);
            ret_ptr = mem::transmute(get_read_u32_fn(&[0xde, 0x12, 0x04, 0x95]).unwrap());
        }
        assert_eq!(le_ptr, ret_ptr);
    }

    {
        let be_ptr: *const ();
        let ret_ptr;
        unsafe {
            be_ptr = mem::transmute(BigEndian::read_u32);
            ret_ptr = mem::transmute(get_read_u32_fn(&[0x95, 0x04, 0x12, 0xde]).unwrap());
        }
        assert_eq!(be_ptr, ret_ptr);
    }
}

#[test]
fn test_parse_catalog() {
    macro_rules! assert_variant {
        ($value:expr, $variant:path) => {
            match $value {
                $variant => (),
                _ => panic!("Expected {:?}, got {:?}", $variant, $value),
            }
        };
    }

    let fluff = [0; 24]; // zeros to pad our magic test cases to satisfy the length requirements

    {
        let mut reader = vec![1u8, 2, 3];
        reader.extend(fluff.iter().cloned());
        let err = parse_catalog(&reader[..]).unwrap_err();
        assert_variant!(err, Eof);
    }

    {
        let mut reader = vec![1u8, 2, 3, 4];
        reader.extend(fluff.iter().cloned());
        let err = parse_catalog(&reader[..]).unwrap_err();
        assert_variant!(err, BadMagic);
    }

    {
        let mut reader = vec![0x95, 0x04, 0x12, 0xde];
        reader.extend(fluff.iter().cloned());
        assert!(parse_catalog(&reader[..]).is_ok());
    }

    {
        let mut reader = vec![0xde, 0x12, 0x04, 0x95];
        reader.extend(fluff.iter().cloned());
        assert!(parse_catalog(&reader[..]).is_ok());
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/1.mo");
        let catalog = parse_catalog(reader).unwrap();
        assert_eq!(catalog.strings.len(), 1);
        assert_eq!(catalog.strings["this is context\x04Text"],
                   Message::new("Text", Some("this is context"), vec!["Tekstas", "Tekstai"]));
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/2.mo");
        let catalog = parse_catalog(reader).unwrap();
        assert_eq!(catalog.strings.len(), 2);
        assert_eq!(catalog.strings["Image"],
                   Message::new("Image", None, vec!["Nuotrauka", "Nuotraukos"]));
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/invalid_utf8.mo");
        let err = parse_catalog(reader).unwrap_err();
        assert_variant!(err, DecodingError);
    }
}
<commit_msg>Fix the parsing of one-form strings<commit_after>extern crate byteorder;

use std::error;
use std::fmt;
use std::io;
use std::str;

use self::byteorder::{ByteOrder, BigEndian, LittleEndian};

use super::{Catalog, Message};

/// Represents an error encountered while parsing an MO file.
#[derive(Debug)]
pub enum Error {
    /// An incorrect magic number has been encountered
    BadMagic,
    /// An invalid byte sequence for the given encoding has been encountered
    DecodingError,
    /// An unexpected EOF occured
    Eof,
    /// An I/O error occured
    Io(io::Error),
}
// Can not use use `Error::*` as per this issue:
// (https://github.com/rust-lang/rust/issues/4865)
use Error::{BadMagic, DecodingError, Eof, Io};

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            BadMagic => "bad magic number",
            DecodingError => "invalid byte sequence in a string",
            Eof => "unxpected end of file",
            Io(ref err) => err.description(),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let self_err: &error::Error = self;
        write!(fmt, "{}", self_err.description())
    }
}

impl From<io::Error> for Error {
    fn from(inner: io::Error) -> Error {
        Io(inner)
    }
}

/// According to the given magic number of a MO file,
/// returns the function which reads a `u32` in the relevant endianness.
fn get_read_u32_fn(magic: &[u8]) -> Option<fn(&[u8]) -> u32> {
    if magic == [0xde, 0x12, 0x04, 0x95] {
        Some(LittleEndian::read_u32)
    } else if magic == [0x95, 0x04, 0x12, 0xde] {
        Some(BigEndian::read_u32)
    } else {
        None
    }
}

fn from_utf8(bytes: &[u8]) -> Result<&str, Error> {
    str::from_utf8(bytes).map_err(|_| DecodingError)
}

pub fn parse_catalog<R: io::Read>(mut file: R) -> Result<Catalog, Error> {
    let mut contents = vec![];
    let n = try!(file.read_to_end(&mut contents));
    if n < 28 {
        return Err(Eof);
    }

    let read_u32 = match get_read_u32_fn(&contents[0..4]) {
        Some(f) => f,
        None => return Err(BadMagic),
    };

    // ignore hashing tables (bytes at 20..28)
    let num_strings = read_u32(&contents[8..12]) as usize;
    let mut off_otable = read_u32(&contents[12..16]) as usize;
    let mut off_ttable = read_u32(&contents[16..20]) as usize;
    if n < off_otable || n < off_ttable {
        return Err(Eof);
    }

    let mut catalog = Catalog::new();
    for _ in 0..num_strings {
        let id;
        let context;
        let translated: Vec<&str>;
        // Parse the original string
        {
            if n < off_otable + 8 {
                return Err(Eof);
            }
            let len = read_u32(&contents[off_otable..off_otable + 4]) as usize;
            let off = read_u32(&contents[off_otable + 4..off_otable + 8]) as usize;
            // +1 compensates for the ending NUL byte which is not included in length
            if n < off + len + 1 {
                return Err(Eof);
            }
            let mut original = &contents[off..off + len + 1];
            // check for context
            context = match original.iter().position(|x| *x == 4) {
                Some(idx) => {
                    let ctx = &original[..idx];
                    original = &original[idx + 1..];
                    Some(try!(from_utf8(ctx)))
                }
                None => None,
            };
            // extract msg_id singular, ignoring the plural
            id = match original.iter().position(|x| *x == 0).map(|i| &original[..i]) {
                Some(b) => try!(from_utf8(b)),
                None => return Err(Eof),
            };
        }

        // Parse the translation strings
        {
            if n < off_ttable + 8 {
                return Err(Eof);
            }
            let len = read_u32(&contents[off_ttable..off_ttable + 4]) as usize;
            let off = read_u32(&contents[off_ttable + 4..off_ttable + 8]) as usize;
            // +1 compensates for the ending NUL byte which is not included in length
            if n < off + len + 1 {
                return Err(Eof);
            }
            let decode_results = (&contents[off..off + len + 1])
                                     .split(|x| *x == 0)
                                     .map(from_utf8)
                                     .collect::<Vec<_>>();
            if decode_results.iter().any(|r| r.is_err()) {
                return Err(DecodingError);
            }
            translated = decode_results.into_iter().map(|r| r.unwrap()).collect();
        }

        catalog.insert(Message::new(id, context, translated));

        off_otable += 8;
        off_ttable += 8;
    }

    Ok(catalog)
}

#[test]
fn test_get_read_u32_fn() {
    use std::mem;

    assert!(get_read_u32_fn(&[]).is_none());
    assert!(get_read_u32_fn(&[0xde, 0x12, 0x04, 0x95, 0x00]).is_none());

    {
        let le_ptr: *const ();
        let ret_ptr;
        unsafe {
            le_ptr = mem::transmute(LittleEndian::read_u32);
            ret_ptr = mem::transmute(get_read_u32_fn(&[0xde, 0x12, 0x04, 0x95]).unwrap());
        }
        assert_eq!(le_ptr, ret_ptr);
    }

    {
        let be_ptr: *const ();
        let ret_ptr;
        unsafe {
            be_ptr = mem::transmute(BigEndian::read_u32);
            ret_ptr = mem::transmute(get_read_u32_fn(&[0x95, 0x04, 0x12, 0xde]).unwrap());
        }
        assert_eq!(be_ptr, ret_ptr);
    }
}

#[test]
fn test_parse_catalog() {
    macro_rules! assert_variant {
        ($value:expr, $variant:path) => {
            match $value {
                $variant => (),
                _ => panic!("Expected {:?}, got {:?}", $variant, $value),
            }
        };
    }

    let fluff = [0; 24]; // zeros to pad our magic test cases to satisfy the length requirements

    {
        let mut reader = vec![1u8, 2, 3];
        reader.extend(fluff.iter().cloned());
        let err = parse_catalog(&reader[..]).unwrap_err();
        assert_variant!(err, Eof);
    }

    {
        let mut reader = vec![1u8, 2, 3, 4];
        reader.extend(fluff.iter().cloned());
        let err = parse_catalog(&reader[..]).unwrap_err();
        assert_variant!(err, BadMagic);
    }

    {
        let mut reader = vec![0x95, 0x04, 0x12, 0xde];
        reader.extend(fluff.iter().cloned());
        assert!(parse_catalog(&reader[..]).is_ok());
    }

    {
        let mut reader = vec![0xde, 0x12, 0x04, 0x95];
        reader.extend(fluff.iter().cloned());
        assert!(parse_catalog(&reader[..]).is_ok());
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/1.mo");
        let catalog = parse_catalog(reader).unwrap();
        assert_eq!(catalog.strings.len(), 1);
        assert_eq!(catalog.strings["this is context\x04Text"],
                   Message::new("Text", Some("this is context"), vec!["Tekstas", "Tekstai"]));
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/2.mo");
        let catalog = parse_catalog(reader).unwrap();
        assert_eq!(catalog.strings.len(), 2);
        assert_eq!(catalog.strings["Image"],
                   Message::new("Image", None, vec!["Nuotrauka", "Nuotraukos"]));
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/invalid_utf8.mo");
        let err = parse_catalog(reader).unwrap_err();
        assert_variant!(err, DecodingError);
    }
}
<|endoftext|>


<commit_before>use lexer::{LexedToken,Lexer,Token};

pub struct Parser {
    tokens: Vec<LexedToken>,
    current_index: usize
}

impl Parser {
    pub fn new(source: &str) -> Parser {
        let lexer = Lexer::new(source);
        Parser { tokens: lexer.tokens().collect(), current_index: 0 }
    }

    pub fn jump(&mut self, n: isize) {
        match self.index_with_offset(n) {
            Some(index) => self.current_index = index,
            None => panic!("Attempted to jump too far back")
        }
    }

    pub fn consume(&mut self, token: Token) -> Option<String> {
        self.token_at(self.current_index)
            .and_then(|&(ref token_type, ref value)| {
                if *token_type != token { return None; }
                Some(value.clone().into())
            })
            .and_then(|string| {
                self.current_index += 1;
                Some(string)
            })
    }

    pub fn expression(&mut self) -> Option<String> {
        self.type_at(self.current_index)
            .and_then(|token_type| {
                match token_type {
                    Token::Identifier => self.variable(),
                    Token::String | Token::Number => self.consume(token_type),
                    _ => panic!("Syntax Error")
                }
            })
    }

    pub fn is_current(&self, token: Token) -> bool {
        self.is_current_offset(token, 0)
    }

    pub fn is_current_offset(&self, token: Token, offset: isize) -> bool {
        self.index_with_offset(offset)
            .and_then(|index| self.is_token(index, token))
            .or_else(|| Some(false))
            .unwrap()
    }

    fn token_at(&self, index: usize) -> Option<&LexedToken> {
        self.tokens.get(index)
    }

    fn type_at(&self, index: usize) -> Option<Token> {
        self.token_at(index)
            .and_then(|&(ref token, _)| Some(token.clone()))
    }

    fn is_token(&self, index: usize, token: Token) -> Option<bool> {
        self.token_at(index)
            .and_then(|&(ref token_type, _)| Some(*token_type == token))
            .or_else(|| Some(false))
    }

    fn index_with_offset(&self, offset: isize) -> Option<usize> {
        let index = (self.current_index as isize).wrapping_add(offset);
        if index < 0 { return None; }

        Some(index as usize)
    }

    fn variable(&mut self) -> Option<String> {
        self.consume(Token::Identifier)
            .and_then(|mut value| {
                while self.is_current(Token::OpenSquare) {
                    value.push_str(&self.consume(Token::OpenSquare).unwrap());
                    value.push_str(&self.expression().unwrap());
                    value.push_str(&self.consume(Token::CloseSquare).unwrap());
                }

                if self.is_current(Token::Dot) {
                    value.push_str(&self.consume(Token::Dot).unwrap());
                    value.push_str(&self.variable().unwrap());
                }

                Some(value)
            })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use lexer::Token;

    #[test]
    fn jump_moves_the_current_index() {
        let mut parser = Parser::new("wat: 7");
        parser.jump(2);

        assert!(parser.is_current(Token::Number));
    }

    #[test]
    fn jump_can_move_backwards() {
        let mut parser = Parser::new("wat: 7");
        parser.jump(2);
        parser.jump(-1);

        assert!(parser.is_current(Token::Colon));
    }

    #[test]
    #[should_panic(expected="Attempted to jump too far back")]
    fn jump_panics_when_index_goes_below_zero() {
        let mut parser = Parser::new("wat: 7");
        parser.jump(-1)
    }

    #[test]
    fn consume_things() {
        let mut parser = Parser::new("wat: 7");
        assert_eq!("wat", parser.consume(Token::Identifier).unwrap());
        assert_eq!(":", parser.consume(Token::Colon).unwrap());
        assert_eq!("7", parser.consume(Token::Number).unwrap());
    }

    #[test]
    fn consume_returns_none_when_token_doesnt_match() {
        let mut parser = Parser::new("wat: 7");
        assert_eq!(None, parser.consume(Token::Number));
        assert_eq!(None, parser.consume(Token::Colon));
        assert!(parser.consume(Token::Identifier).is_some());
    }

    #[test]
    fn is_current_checks_token_type() {
        let mut parser = Parser::new("wat 6 Peter Hegemon");

        assert!(parser.is_current(Token::Identifier));
        parser.consume(Token::Identifier);

        assert_eq!(false, parser.is_current(Token::Comparison));
        assert!(parser.is_current(Token::Number));
        assert!(parser.is_current_offset(Token::Identifier, 1));
        assert_eq!(false, parser.is_current_offset(Token::Number, 1));
    }

    #[test]
    fn is_current_offset_returns_false_when_offset_is_not_valid() {
        let mut parser = Parser::new("wat 6 Peter Hegemon");
        parser.jump(1);

        assert!(parser.is_current_offset(Token::Number, 0));
        assert!(parser.is_current_offset(Token::Identifier, -1));
        assert_eq!(false, parser.is_current_offset(Token::Identifier, -2));
    }

    #[test]
    fn expression_parsing_identifiers_strings_and_numbers() {
        let mut parser = Parser::new("hi.there hi?[5].there? hi.there.bob");
        assert_eq!("hi.there", parser.expression().unwrap());
        assert_eq!("hi?[5].there?", parser.expression().unwrap());
        assert_eq!("hi.there.bob", parser.expression().unwrap());

        let mut parser = Parser::new("567 6.0 'lol' \"wut\"");
        assert_eq!("567", parser.expression().unwrap());
        assert_eq!("6.0", parser.expression().unwrap());
        assert_eq!("'lol'", parser.expression().unwrap());
        assert_eq!("\"wut\"", parser.expression().unwrap());
    }
}
<commit_msg>parsing ranges<commit_after>use lexer::{LexedToken,Lexer,Token};

pub struct Parser {
    tokens: Vec<LexedToken>,
    current_index: usize
}

impl Parser {
    pub fn new(source: &str) -> Parser {
        let lexer = Lexer::new(source);
        Parser { tokens: lexer.tokens().collect(), current_index: 0 }
    }

    pub fn jump(&mut self, n: isize) {
        match self.index_with_offset(n) {
            Some(index) => self.current_index = index,
            None => panic!("Attempted to jump too far back")
        }
    }

    pub fn consume(&mut self, token: Token) -> Option<String> {
        self.token_at(self.current_index)
            .and_then(|&(ref token_type, ref value)| {
                if *token_type != token { return None; }
                Some(value.clone().into())
            })
            .and_then(|string| {
                self.current_index += 1;
                Some(string)
            })
    }

    pub fn expression(&mut self) -> Option<String> {
        self.type_at(self.current_index)
            .and_then(|token_type| {
                match token_type {
                    Token::Identifier => self.variable(),
                    Token::OpenRound => self.range(),
                    Token::String | Token::Number => self.consume(token_type),
                    _ => panic!("Syntax Error")
                }
            })
    }

    pub fn is_current(&self, token: Token) -> bool {
        self.is_current_offset(token, 0)
    }

    pub fn is_current_offset(&self, token: Token, offset: isize) -> bool {
        self.index_with_offset(offset)
            .and_then(|index| self.is_token(index, token))
            .or_else(|| Some(false))
            .unwrap()
    }

    fn token_at(&self, index: usize) -> Option<&LexedToken> {
        self.tokens.get(index)
    }

    fn type_at(&self, index: usize) -> Option<Token> {
        self.token_at(index)
            .and_then(|&(ref token, _)| Some(token.clone()))
    }

    fn is_token(&self, index: usize, token: Token) -> Option<bool> {
        self.token_at(index)
            .and_then(|&(ref token_type, _)| Some(*token_type == token))
            .or_else(|| Some(false))
    }

    fn index_with_offset(&self, offset: isize) -> Option<usize> {
        let index = (self.current_index as isize).wrapping_add(offset);
        if index < 0 { return None; }

        Some(index as usize)
    }

    fn variable(&mut self) -> Option<String> {
        self.consume(Token::Identifier)
            .and_then(|mut value| {
                while self.is_current(Token::OpenSquare) {
                    value.push_str(&self.consume(Token::OpenSquare).unwrap());
                    value.push_str(&self.expression().unwrap());
                    value.push_str(&self.consume(Token::CloseSquare).unwrap());
                }

                if self.is_current(Token::Dot) {
                    value.push_str(&self.consume(Token::Dot).unwrap());
                    value.push_str(&self.variable().unwrap());
                }

                Some(value)
            })
    }

    fn range(&mut self) -> Option<String> {
        self.consume(Token::OpenRound)
            .and_then(|mut value| {
                value.push_str(&self.expression().unwrap());
                value.push_str(&self.consume(Token::Range).unwrap());
                value.push_str(&self.expression().unwrap());
                value.push_str(&self.consume(Token::CloseRound).unwrap());
                Some(value)
            })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use lexer::Token;

    #[test]
    fn jump_moves_the_current_index() {
        let mut parser = Parser::new("wat: 7");
        parser.jump(2);

        assert!(parser.is_current(Token::Number));
    }

    #[test]
    fn jump_can_move_backwards() {
        let mut parser = Parser::new("wat: 7");
        parser.jump(2);
        parser.jump(-1);

        assert!(parser.is_current(Token::Colon));
    }

    #[test]
    #[should_panic(expected="Attempted to jump too far back")]
    fn jump_panics_when_index_goes_below_zero() {
        let mut parser = Parser::new("wat: 7");
        parser.jump(-1)
    }

    #[test]
    fn consume_things() {
        let mut parser = Parser::new("wat: 7");
        assert_eq!("wat", parser.consume(Token::Identifier).unwrap());
        assert_eq!(":", parser.consume(Token::Colon).unwrap());
        assert_eq!("7", parser.consume(Token::Number).unwrap());
    }

    #[test]
    fn consume_returns_none_when_token_doesnt_match() {
        let mut parser = Parser::new("wat: 7");
        assert_eq!(None, parser.consume(Token::Number));
        assert_eq!(None, parser.consume(Token::Colon));
        assert!(parser.consume(Token::Identifier).is_some());
    }

    #[test]
    fn is_current_checks_token_type() {
        let mut parser = Parser::new("wat 6 Peter Hegemon");

        assert!(parser.is_current(Token::Identifier));
        parser.consume(Token::Identifier);

        assert_eq!(false, parser.is_current(Token::Comparison));
        assert!(parser.is_current(Token::Number));
        assert!(parser.is_current_offset(Token::Identifier, 1));
        assert_eq!(false, parser.is_current_offset(Token::Number, 1));
    }

    #[test]
    fn is_current_offset_returns_false_when_offset_is_not_valid() {
        let mut parser = Parser::new("wat 6 Peter Hegemon");
        parser.jump(1);

        assert!(parser.is_current_offset(Token::Number, 0));
        assert!(parser.is_current_offset(Token::Identifier, -1));
        assert_eq!(false, parser.is_current_offset(Token::Identifier, -2));
    }

    #[test]
    fn expression_parsing_identifiers_strings_and_numbers() {
        let mut parser = Parser::new("hi.there hi?[5].there? hi.there.bob");
        assert_eq!("hi.there", parser.expression().unwrap());
        assert_eq!("hi?[5].there?", parser.expression().unwrap());
        assert_eq!("hi.there.bob", parser.expression().unwrap());

        let mut parser = Parser::new("567 6.0 'lol' \"wut\"");
        assert_eq!("567", parser.expression().unwrap());
        assert_eq!("6.0", parser.expression().unwrap());
        assert_eq!("'lol'", parser.expression().unwrap());
        assert_eq!("\"wut\"", parser.expression().unwrap());
    }

    #[test]
    fn expression_parsing_ranges() {
        let mut parser = Parser::new("(5..7) (1.5..9.6) (young..old) (hi[5].wat..old)");
        assert_eq!("(5..7)", parser.expression().unwrap());
        assert_eq!("(1.5..9.6)", parser.expression().unwrap());
        assert_eq!("(young..old)", parser.expression().unwrap());
        assert_eq!("(hi[5].wat..old)", parser.expression().unwrap());
    }
}
<|endoftext|>


<commit_before>#![feature(core,collections)]

use nom::{IResult,Needed,not_line_ending};
use nom::IResult::*;
use std::str;

#[derive(Debug,PartialEq,Eq)]
pub struct Base {
  pub key: char,
  pub score: u8,
}

#[derive(Debug,PartialEq,Eq)]
pub struct Reading<'a> {
  pub id: &'a str,
  bases: Vec<Base>,
}

pub fn quality_scores(input:&[u8]) -> IResult<&[u8], &str> {
  chain!(input,
    tag!("+") ~
    tag!("\n") ~
    scores: map_res!(not_line_ending, str::from_utf8) ~
    tag!("\n")?,
    ||{scores}
  )
}

pub fn many_reads(input:&[u8]) -> IResult<&[u8], Vec<Reading>> {
  many1!(input,
    chain!(
      tag!("@") ~
      id: map_res!(not_line_ending, str::from_utf8) ~ tag!("\n") ~
      bases: map_res!(not_line_ending, str::from_utf8) ~ tag!("\n")? ~
      scores: opt!(quality_scores),
      ||{
         Reading{
           id: id,
           bases:
             bases.chars().zip(
               scores.unwrap().chars()
             ).map(|x| Base{key: x.0, score: ('~' as u8) - (x.1 as u8)})
             .collect::<Vec<Base>>()
         }
      }
    )
  )
}

<commit_msg>Created nucleobase enum<commit_after>#![feature(core,collections)]

use nom::{IResult,Needed,not_line_ending};
use nom::IResult::*;
use std::str;

#[derive(Debug,PartialEq,Eq)]
pub struct Base {
  pub key: Nucleobase,
  pub score: u8,
}

#[derive(Debug,PartialEq,Eq)]
pub struct Sequence<'a> {
  pub id: &'a str,
  bases: Vec<Base>,
}

#[derive(Debug,PartialEq,Eq)]
pub enum Nucleobase {
  A,
  C,
  G,
  T,
  U,
  N
}

pub fn quality_scores(input:&[u8]) -> IResult<&[u8], &str> {
  chain!(input,
    tag!("+") ~
    tag!("\n") ~
    scores: map_res!(not_line_ending, str::from_utf8) ~
    tag!("\n")?,
    ||{scores}
  )
}

pub fn many_reads(input:&[u8]) -> IResult<&[u8], Vec<Sequence>> {
  many1!(input,
    chain!(
      tag!("@") ~
      id: map_res!(not_line_ending, str::from_utf8) ~ tag!("\n") ~
      bases: map_res!(not_line_ending, str::from_utf8) ~ tag!("\n")? ~
      scores: opt!(quality_scores),
      ||{
         Sequence {
           id: id,
           bases:
             bases.chars().zip(
               scores.unwrap().chars()
             ).map(|x| Base{key:
               match x.0 {
                 'A' => Nucleobase::A,
                 'C' => Nucleobase::C,
                 'G' => Nucleobase::G,
                 'T' => Nucleobase::T,
                 'U' => Nucleobase::U,
                 _ => Nucleobase::N,
               }
             , score: ('~' as u8) - (x.1 as u8)})
             .collect::<Vec<Base>>()
         }
      }
    )
  )
}

<|endoftext|>


<commit_before>use lexicon::Token;
use lexicon::Token::*;
use tokenizer::Tokenizer;
use std::iter::Peekable;
use grammar::*;
use grammar::Statement::*;
use grammar::Expression::*;
use grammar::ClassMember::*;
use grammar::OperatorType::*;

/// If the next token matches `$p`, consume that token and return
/// true, else do nothing and return false
macro_rules! allow {
    ($parser:ident, $p:pat) => {
        match $parser.lookahead() {
            Some(&$p) => {
                $parser.consume();
                true
            },
            _ => false
        }
    };
    {$parser:ident $( $p:pat => $then:expr ),* } => ({
        match $parser.lookahead() {
            $(
                Some(&$p) => {
                    $parser.consume();
                    $then;
                }
            )*
            _ => {}
        }
    });
}

/// Expects next token to match `$p`, otherwise panics.
macro_rules! expect {
    ($parser:ident, $p:pat => $value:ident) => (
        match $parser.consume() {
            Some($p) => $value,
            None     => panic!("Unexpected end of program"),
            token    => unexpected_token!($parser, token),
        }
    );
    ($parser:ident, $p:pat) => (
        match $parser.consume() {
            Some($p) => {},
            None     => panic!("Unexpected end of program"),
            token    => unexpected_token!($parser, token),
        }
    )
}

macro_rules! unexpected_token {
    ($parser:ident) => ({
        if let Some(token) = $parser.consume() {
            unexpected_token!($parser, token);
        } else {
            panic!("Unexpected end of program");
        }
    });
    ($parser:ident, $token:expr) => {
        panic!("Unexpected token {:?}", $token)
    }
}

/// Evaluates the `$eval` expression, then expects a semicolon or
/// end of program. If neither is found, but a LineTermination
/// occured on previous token, parsing will continue as if a
/// semicolon was present. In other cases cause a panic.
macro_rules! statement {
    ($parser:ident, $eval:expr) => ({
        let value = $eval;

        let is_end = match $parser.lookahead() {
            Some(&Semicolon) => {
                $parser.consume();
                true
            },
            None => true,
            _    => false
        };

        if !is_end && !$parser.allow_asi {
            unexpected_token!($parser);
        };

        value
    })
}

/// Read a list of items with predefined `$start`, `$end` and
/// `$separator` tokens and an `$item` expression that is then
/// pushed onto a vector.
macro_rules! list {
    ($parser:ident, $item:expr, $start:pat, $end:pat) => ({
        expect!($parser, $start);

        let mut list = Vec::new();
        loop {
            if allow!($parser, $end) {
                break;
            }
            list.push($item);

            match $parser.consume() {
                Some(Comma) => allow!{ $parser $end => break },
                Some($end)  => break,
                _           => {},
            }
        }

        list
    });
    ($parser:ident ( $item:expr )) => {
        list!($parser, $item, ParenOn, ParenOff)
    };
    ($parser:ident [ $item:expr ]) => {
        list!($parser, $item, BracketOn, BracketOff)
    };
    ($parser:ident { $item:expr }) => {
        list!($parser, $item, BlockOn, BlockOff)
    };
}

macro_rules! surround {
    ($parser:ident ( $eval:expr )) => ({
        expect!($parser, ParenOn);
        let value = $eval;
        expect!($parser, ParenOff);
        value
    });
    ($parser:ident [ $eval:expr ]) => ({
        expect!($parser, BracketOn);
        let value = $eval;
        expect!($parser, BracketOff);
        value
    });
}

pub struct Parser<'a> {
    tokenizer: Peekable<Tokenizer<'a>>,
    allow_asi: bool,
}

impl<'a> Parser<'a> {
    pub fn new(source: &'a String) -> Self {
        Parser {
            tokenizer: Tokenizer::new(source).peekable(),
            allow_asi: false,
        }
    }

    #[inline(always)]
    fn handle_line_termination(&mut self) {
        while let Some(&LineTermination) = self.tokenizer.peek() {
            self.tokenizer.next();
            self.allow_asi = true;
        }
    }

    #[inline(always)]
    fn consume(&mut self) -> Option<Token> {
        self.handle_line_termination();
        let token = self.tokenizer.next();

        // println!("Consume {:?}", token);

        self.allow_asi = false;
        token
    }

    #[inline(always)]
    fn lookahead(&mut self) -> Option<&Token> {
        self.handle_line_termination();
        self.tokenizer.peek()
    }

    fn array_expression(&mut self) -> Expression {
        ArrayExpression(list!(self [ self.expression(0) ]))
    }

    #[inline(always)]
    fn object_member(&mut self) -> ObjectMember {
        match self.consume() {
            Some(Identifier(key)) | Some(Literal(LiteralString(key))) => {
                if allow!(self, Colon) {
                    ObjectMember::Literal {
                        key: key,
                        value: self.expression(0),
                    }
                } else {
                    ObjectMember::Shorthand {
                        key: key,
                    }
                }
            },
            Some(BracketOn) => {
                let key = self.expression(0);
                expect!(self, BracketOff);
                expect!(self, Colon);
                ObjectMember::Computed {
                    key: key,
                    value: self.expression(0),
                }
            },
            token => {
                panic!("Expected object key, got {:?}", token)
            }
        }
    }

    fn object_expression(&mut self) -> Expression {
        ObjectExpression(list!(self { self.object_member() }))
    }

    fn soft_block(&mut self) -> Statement {
        if let Some(&BlockOn) = self.lookahead() {
            BlockStatement {
                body: self.block()
            }
        } else {
            ExpressionStatement(self.expression(0))
        }
    }

    fn block(&mut self) -> Vec<Statement> {
        expect!(self, BlockOn);

        let mut body = Vec::new();
        loop {
            allow!{ self BlockOff => break };

            body.push(
                self.statement().expect("Unexpected end of statements block")
            )
        }

        body
    }

    fn arrow_function_expression(&mut self, p: Expression) -> Expression {
        let params: Vec<Parameter> = match p {
            IdentifierExpression(name) => {
                vec![Parameter { name: name }]
            },
            _ =>
                panic!("Can cast {:?} to parameters", p),
        };

        ArrowFunctionExpression {
            params: params,
            body: Box::new(self.soft_block())
        }
    }

    #[inline(always)]
    fn prefix_expression(&mut self) -> Expression {
        let operator = expect!(self, Operator(op) => op);
        let bp = operator.binding_power(true);

        if !operator.prefix() {
            panic!("Unexpected operator {:?}", operator);
        }

        PrefixExpression {
            operator: operator,
            operand: Box::new(self.expression(bp)),
        }
    }

    #[inline(always)]
    fn infix_expression(&mut self, left: Expression, bp: u8) -> Expression {
        let operator = expect!(self, Operator(op) => op);

        match operator {
            Increment | Decrement => PostfixExpression {
                operator: operator,
                operand: Box::new(left),
            },

            Accessor => MemberExpression {
                object: Box::new(left),
                property: Box::new(MemberKey::Literal(
                    expect!(self, Identifier(key) => key)
                )),
            },

            Conditional => ConditionalExpression {
                test: Box::new(left),
                consequent: Box::new(self.expression(bp)),
                alternate: {
                    expect!(self, Colon);
                    Box::new(self.expression(bp))
                }
            },

            FatArrow => self.arrow_function_expression(left),

            _ => {
                if !operator.infix() {
                    panic!("Unexpected operator {:?}", operator);
                }

                BinaryExpression {
                    left: Box::new(left),
                    operator: operator,
                    right: Box::new(
                        self.expression(bp)
                    )
                }
            }
        }
    }

    fn expression(&mut self, lbp: u8) -> Expression {
        let mut left = match self.lookahead() {
            Some(&Identifier(_)) => {
                IdentifierExpression(expect!(self, Identifier(v) => v))
            },
            Some(&Literal(_))    => {
                LiteralExpression(expect!(self, Literal(v) => v))
            },
            Some(&Operator(_)) => self.prefix_expression(),
            Some(&ParenOn)     => surround!(self ( self.expression(19) )),
            Some(&BracketOn)   => self.array_expression(),
            Some(&BlockOn)     => self.object_expression(),
            _                  => unexpected_token!(self)
        };

        'right: loop {
            let rbp = match self.lookahead() {
                Some(&Operator(ref op)) => op.binding_power(false),
                _                       => 0,
            };

            if lbp > rbp {
                break 'right;
            }

            left = match self.lookahead() {
                Some(&Operator(_)) => self.infix_expression(left, rbp),

                Some(&ParenOn)     => CallExpression {
                    callee: Box::new(left),
                    arguments: list!(self ( self.expression(0) ))
                },

                Some(&BracketOn)   => MemberExpression {
                    object: Box::new(left),
                    property: Box::new(MemberKey::Computed(
                        surround!(self [ self.expression(0) ])
                    ))
                },

                _                  => break 'right,
            }
        }

        left
    }

    fn variable_declaration_statement(
        &mut self, kind: VariableDeclarationKind
    ) -> Statement {
        let mut declarations = Vec::new();

        loop {
            let name = expect!(self, Identifier(name) => name);
            expect!(self, Operator(Assign));
            declarations.push((
                name,
                self.expression(0)
            ));

            allow!{ self Comma => continue };
            break;
        }

        statement!(self, VariableDeclarationStatement {
            kind: kind,
            declarations: declarations,
        })
    }

    fn expression_statement(&mut self) -> Statement {
        statement!(self, ExpressionStatement(
            self.expression(0)
        ))
    }

    fn return_statement(&mut self) -> Statement {
        statement!(self, ReturnStatement(
            self.expression(0)
        ))
    }

    fn if_statement(&mut self) -> Statement {
        let test = surround!(self ( self.expression(0) ));
        let consequent = Box::new(self.soft_block());
        let alternate = if allow!(self, Else) {
            if allow!(self, If) {
                Some(Box::new(self.if_statement()))
            } else {
                Some(Box::new(self.soft_block()))
            }
        } else {
            None
        };

        statement!(self, IfStatement {
            test: test,
            consequent: consequent,
            alternate: alternate,
        })
    }

    fn while_statement(&mut self) -> Statement {
        statement!(self, WhileStatement {
            test: surround!(self ( self.expression(0) )),
            body: Box::new(self.soft_block()),
        })
    }

    fn parameter(&mut self) -> Parameter {
        Parameter {
            name: expect!(self, Identifier(name) => name)
        }
    }

    fn function_statement(&mut self) -> Statement {
        FunctionStatement {
            name: expect!(self, Identifier(name) => name),
            params: list!(self ( self.parameter() )),
            body: self.block(),
        }
    }

    fn class_member(&mut self, name: String, is_static: bool) -> ClassMember {
        match self.lookahead() {
            Some(&ParenOn) => {
                if !is_static && name == "constructor" {
                    ClassConstructor {
                        params: list!(self ( self.parameter() )),
                        body: self.block(),
                    }
                } else {
                    ClassMethod {
                        is_static: is_static,
                        name: name,
                        params: list!(self ( self.parameter())),
                        body: self.block(),
                    }
                }
            },
            Some(&Operator(Assign)) => {
                self.consume();
                ClassProperty {
                    is_static: is_static,
                    name: name,
                    value: self.expression(0),
                }
            },
            _ => unexpected_token!(self),
        }
    }

    fn class_statement(&mut self) -> Statement {
        let name = expect!(self, Identifier(id) => id);
        let super_class = if allow!(self, Extends) {
            Some(expect!(self, Identifier(name) => name))
        } else {
            None
        };
        expect!(self, BlockOn);
        let mut members = Vec::new();
        'members: loop {
            members.push(match self.consume() {
                Some(Identifier(name)) => self.class_member(name, false),
                Some(Static)           => {
                    let name = expect!(self, Identifier(name) => name);
                    self.class_member(name, true)
                },
                Some(Semicolon)        => continue 'members,
                Some(BlockOff)         => break 'members,
                token                  => unexpected_token!(self, token)
            });
        }

        ClassStatement {
            name: name,
            extends: super_class,
            body: members,
        }
    }

    fn statement(&mut self) -> Option<Statement> {
        allow!{self
            Var       => return Some(self.variable_declaration_statement(
                VariableDeclarationKind::Var
            )),
            Let       => return Some(self.variable_declaration_statement(
                VariableDeclarationKind::Let
            )),
            Const     => return Some(self.variable_declaration_statement(
                VariableDeclarationKind::Const
            )),
            Return    => return Some(self.return_statement()),
            Function  => return Some(self.function_statement()),
            Class     => return Some(self.class_statement()),
            If        => return Some(self.if_statement()),
            While     => return Some(self.while_statement()),
            Semicolon => return self.statement()
        };

        if self.lookahead().is_some() {
            Some(self.expression_statement())
        } else {
            None
        }
    }
}

pub fn parse(source: String) -> Program {
    let mut parser = Parser::new(&source);
    let mut program = Program { body: Vec::new() };

    while let Some(statement) = parser.statement() {
        program.body.push(statement);
    }

    return program;
}
<commit_msg>More explicit naming<commit_after>use lexicon::Token;
use lexicon::Token::*;
use tokenizer::Tokenizer;
use std::iter::Peekable;
use grammar::*;
use grammar::Statement::*;
use grammar::Expression::*;
use grammar::ClassMember::*;
use grammar::OperatorType::*;

/// If the next token matches `$p`, consume that token and return
/// true, else do nothing and return false
macro_rules! allow {
    ($parser:ident, $p:pat) => {
        match $parser.lookahead() {
            Some(&$p) => {
                $parser.consume();
                true
            },
            _ => false
        }
    };
    {$parser:ident $( $p:pat => $then:expr ),* } => ({
        match $parser.lookahead() {
            $(
                Some(&$p) => {
                    $parser.consume();
                    $then;
                }
            )*
            _ => {}
        }
    });
}

/// Expects next token to match `$p`, otherwise panics.
macro_rules! expect {
    ($parser:ident, $p:pat => $value:ident) => (
        match $parser.consume() {
            Some($p) => $value,
            None     => panic!("Unexpected end of program"),
            token    => unexpected_token!($parser, token),
        }
    );
    ($parser:ident, $p:pat) => (
        match $parser.consume() {
            Some($p) => {},
            None     => panic!("Unexpected end of program"),
            token    => unexpected_token!($parser, token),
        }
    )
}

macro_rules! unexpected_token {
    ($parser:ident) => ({
        if let Some(token) = $parser.consume() {
            unexpected_token!($parser, token);
        } else {
            panic!("Unexpected end of program");
        }
    });
    ($parser:ident, $token:expr) => {
        panic!("Unexpected token {:?}", $token)
    }
}

/// Evaluates the `$eval` expression, then expects a semicolon or
/// end of program. If neither is found, but a LineTermination
/// occured on previous token, parsing will continue as if a
/// semicolon was present. In other cases cause a panic.
macro_rules! statement {
    ($parser:ident, $eval:expr) => ({
        let value = $eval;

        let is_end = match $parser.lookahead() {
            Some(&Semicolon) => {
                $parser.consume();
                true
            },
            None => true,
            _    => false
        };

        if !is_end && !$parser.allow_asi {
            unexpected_token!($parser);
        };

        value
    })
}

/// Read a list of items with predefined `$start`, `$end` and
/// `$separator` tokens and an `$item` expression that is then
/// pushed onto a vector.
macro_rules! list {
    ($parser:ident, $item:expr, $start:pat, $end:pat) => ({
        expect!($parser, $start);

        let mut list = Vec::new();
        loop {
            if allow!($parser, $end) {
                break;
            }
            list.push($item);

            match $parser.consume() {
                Some(Comma) => allow!{ $parser $end => break },
                Some($end)  => break,
                _           => {},
            }
        }

        list
    });
    ($parser:ident ( $item:expr )) => {
        list!($parser, $item, ParenOn, ParenOff)
    };
    ($parser:ident [ $item:expr ]) => {
        list!($parser, $item, BracketOn, BracketOff)
    };
    ($parser:ident { $item:expr }) => {
        list!($parser, $item, BlockOn, BlockOff)
    };
}

macro_rules! surround {
    ($parser:ident ( $eval:expr )) => ({
        expect!($parser, ParenOn);
        let value = $eval;
        expect!($parser, ParenOff);
        value
    });
    ($parser:ident [ $eval:expr ]) => ({
        expect!($parser, BracketOn);
        let value = $eval;
        expect!($parser, BracketOff);
        value
    });
}

pub struct Parser<'a> {
    tokenizer: Peekable<Tokenizer<'a>>,
    allow_asi: bool,
}

impl<'a> Parser<'a> {
    pub fn new(source: &'a String) -> Self {
        Parser {
            tokenizer: Tokenizer::new(source).peekable(),
            allow_asi: false,
        }
    }

    #[inline(always)]
    fn handle_line_termination(&mut self) {
        while let Some(&LineTermination) = self.tokenizer.peek() {
            self.tokenizer.next();
            self.allow_asi = true;
        }
    }

    #[inline(always)]
    fn consume(&mut self) -> Option<Token> {
        self.handle_line_termination();
        let token = self.tokenizer.next();

        // println!("Consume {:?}", token);

        self.allow_asi = false;
        token
    }

    #[inline(always)]
    fn lookahead(&mut self) -> Option<&Token> {
        self.handle_line_termination();
        self.tokenizer.peek()
    }

    fn array_expression(&mut self) -> Expression {
        ArrayExpression(list!(self [ self.expression(0) ]))
    }

    #[inline(always)]
    fn object_member(&mut self) -> ObjectMember {
        match self.consume() {
            Some(Identifier(key)) | Some(Literal(LiteralString(key))) => {
                if allow!(self, Colon) {
                    ObjectMember::Literal {
                        key: key,
                        value: self.expression(0),
                    }
                } else {
                    ObjectMember::Shorthand {
                        key: key,
                    }
                }
            },
            Some(BracketOn) => {
                let key = self.expression(0);
                expect!(self, BracketOff);
                expect!(self, Colon);
                ObjectMember::Computed {
                    key: key,
                    value: self.expression(0),
                }
            },
            token => {
                panic!("Expected object key, got {:?}", token)
            }
        }
    }

    fn object_expression(&mut self) -> Expression {
        ObjectExpression(list!(self { self.object_member() }))
    }

    fn block_or_statement(&mut self) -> Statement {
        if let Some(&BlockOn) = self.lookahead() {
            BlockStatement {
                body: self.block_body()
            }
        } else {
            ExpressionStatement(self.expression(0))
        }
    }

    fn block_body(&mut self) -> Vec<Statement> {
        expect!(self, BlockOn);

        let mut body = Vec::new();
        loop {
            allow!{ self BlockOff => break };

            body.push(
                self.statement().expect("Unexpected end of statements block")
            )
        }

        body
    }

    fn arrow_function_expression(&mut self, p: Expression) -> Expression {
        let params: Vec<Parameter> = match p {
            IdentifierExpression(name) => {
                vec![Parameter { name: name }]
            },
            _ =>
                panic!("Can cast {:?} to parameters", p),
        };

        ArrowFunctionExpression {
            params: params,
            body: Box::new(self.block_or_statement())
        }
    }

    #[inline(always)]
    fn prefix_expression(&mut self) -> Expression {
        let operator = expect!(self, Operator(op) => op);
        let bp = operator.binding_power(true);

        if !operator.prefix() {
            panic!("Unexpected operator {:?}", operator);
        }

        PrefixExpression {
            operator: operator,
            operand: Box::new(self.expression(bp)),
        }
    }

    #[inline(always)]
    fn infix_expression(&mut self, left: Expression, bp: u8) -> Expression {
        let operator = expect!(self, Operator(op) => op);

        match operator {
            Increment | Decrement => PostfixExpression {
                operator: operator,
                operand: Box::new(left),
            },

            Accessor => MemberExpression {
                object: Box::new(left),
                property: Box::new(MemberKey::Literal(
                    expect!(self, Identifier(key) => key)
                )),
            },

            Conditional => ConditionalExpression {
                test: Box::new(left),
                consequent: Box::new(self.expression(bp)),
                alternate: {
                    expect!(self, Colon);
                    Box::new(self.expression(bp))
                }
            },

            FatArrow => self.arrow_function_expression(left),

            _ => {
                if !operator.infix() {
                    panic!("Unexpected operator {:?}", operator);
                }

                BinaryExpression {
                    left: Box::new(left),
                    operator: operator,
                    right: Box::new(
                        self.expression(bp)
                    )
                }
            }
        }
    }

    fn expression(&mut self, lbp: u8) -> Expression {
        let mut left = match self.lookahead() {
            Some(&Identifier(_)) => {
                IdentifierExpression(expect!(self, Identifier(v) => v))
            },
            Some(&Literal(_))    => {
                LiteralExpression(expect!(self, Literal(v) => v))
            },
            Some(&Operator(_)) => self.prefix_expression(),
            Some(&ParenOn)     => surround!(self ( self.expression(19) )),
            Some(&BracketOn)   => self.array_expression(),
            Some(&BlockOn)     => self.object_expression(),
            _                  => unexpected_token!(self)
        };

        'right: loop {
            let rbp = match self.lookahead() {
                Some(&Operator(ref op)) => op.binding_power(false),
                _                       => 0,
            };

            if lbp > rbp {
                break 'right;
            }

            left = match self.lookahead() {
                Some(&Operator(_)) => self.infix_expression(left, rbp),

                Some(&ParenOn)     => CallExpression {
                    callee: Box::new(left),
                    arguments: list!(self ( self.expression(0) ))
                },

                Some(&BracketOn)   => MemberExpression {
                    object: Box::new(left),
                    property: Box::new(MemberKey::Computed(
                        surround!(self [ self.expression(0) ])
                    ))
                },

                _                  => break 'right,
            }
        }

        left
    }

    fn variable_declaration_statement(
        &mut self, kind: VariableDeclarationKind
    ) -> Statement {
        let mut declarations = Vec::new();

        loop {
            let name = expect!(self, Identifier(name) => name);
            expect!(self, Operator(Assign));
            declarations.push((
                name,
                self.expression(0)
            ));

            allow!{ self Comma => continue };
            break;
        }

        statement!(self, VariableDeclarationStatement {
            kind: kind,
            declarations: declarations,
        })
    }

    fn expression_statement(&mut self) -> Statement {
        statement!(self, ExpressionStatement(
            self.expression(0)
        ))
    }

    fn return_statement(&mut self) -> Statement {
        statement!(self, ReturnStatement(
            self.expression(0)
        ))
    }

    fn if_statement(&mut self) -> Statement {
        let test = surround!(self ( self.expression(0) ));
        let consequent = Box::new(self.block_or_statement());
        let alternate = if allow!(self, Else) {
            if allow!(self, If) {
                Some(Box::new(self.if_statement()))
            } else {
                Some(Box::new(self.block_or_statement()))
            }
        } else {
            None
        };

        statement!(self, IfStatement {
            test: test,
            consequent: consequent,
            alternate: alternate,
        })
    }

    fn while_statement(&mut self) -> Statement {
        statement!(self, WhileStatement {
            test: surround!(self ( self.expression(0) )),
            body: Box::new(self.block_or_statement()),
        })
    }

    fn parameter(&mut self) -> Parameter {
        Parameter {
            name: expect!(self, Identifier(name) => name)
        }
    }

    fn function_statement(&mut self) -> Statement {
        FunctionStatement {
            name: expect!(self, Identifier(name) => name),
            params: list!(self ( self.parameter() )),
            body: self.block_body(),
        }
    }

    fn class_member(&mut self, name: String, is_static: bool) -> ClassMember {
        match self.lookahead() {
            Some(&ParenOn) => {
                if !is_static && name == "constructor" {
                    ClassConstructor {
                        params: list!(self ( self.parameter() )),
                        body: self.block_body(),
                    }
                } else {
                    ClassMethod {
                        is_static: is_static,
                        name: name,
                        params: list!(self ( self.parameter())),
                        body: self.block_body(),
                    }
                }
            },
            Some(&Operator(Assign)) => {
                self.consume();
                ClassProperty {
                    is_static: is_static,
                    name: name,
                    value: self.expression(0),
                }
            },
            _ => unexpected_token!(self),
        }
    }

    fn class_statement(&mut self) -> Statement {
        let name = expect!(self, Identifier(id) => id);
        let super_class = if allow!(self, Extends) {
            Some(expect!(self, Identifier(name) => name))
        } else {
            None
        };
        expect!(self, BlockOn);
        let mut members = Vec::new();
        'members: loop {
            members.push(match self.consume() {
                Some(Identifier(name)) => self.class_member(name, false),
                Some(Static)           => {
                    let name = expect!(self, Identifier(name) => name);
                    self.class_member(name, true)
                },
                Some(Semicolon)        => continue 'members,
                Some(BlockOff)         => break 'members,
                token                  => unexpected_token!(self, token)
            });
        }

        ClassStatement {
            name: name,
            extends: super_class,
            body: members,
        }
    }

    fn statement(&mut self) -> Option<Statement> {
        allow!{self
            Var       => return Some(self.variable_declaration_statement(
                VariableDeclarationKind::Var
            )),
            Let       => return Some(self.variable_declaration_statement(
                VariableDeclarationKind::Let
            )),
            Const     => return Some(self.variable_declaration_statement(
                VariableDeclarationKind::Const
            )),
            Return    => return Some(self.return_statement()),
            Function  => return Some(self.function_statement()),
            Class     => return Some(self.class_statement()),
            If        => return Some(self.if_statement()),
            While     => return Some(self.while_statement()),
            Semicolon => return self.statement()
        };

        if self.lookahead().is_some() {
            Some(self.expression_statement())
        } else {
            None
        }
    }
}

pub fn parse(source: String) -> Program {
    let mut parser = Parser::new(&source);
    let mut program = Program { body: Vec::new() };

    while let Some(statement) = parser.statement() {
        program.body.push(statement);
    }

    return program;
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;

pub use self::Ast::*;

use lexer::Lexer;
use lexer::Token;
use self::rustc_serialize::json::{Json};

use std::iter::Peekable;

/// Parses a JMESPath expression into an AST
pub fn parse(expr: &str) -> Result<Ast, ParseError> {
    Parser::new(expr).parse()
}

/// Represents the abstract syntax tree of a JMESPath expression.
#[derive(Clone, PartialEq, Debug)]
pub enum Ast {
    Comparison(Comparator, Box<Ast>, Box<Ast>),
    CurrentNode,
    Expref(Box<Ast>),
    Flatten(Box<Ast>),
    Function(char, Vec<(Box<Ast>, Box<Ast>)>),
    Identifier(String),
    Index(i32),
    Literal(Box<Json>),
    MultiList(Vec<Box<Ast>>),
    MultiHash(Vec<Vec<(char, Box<Ast>)>>),
    ArrayProjection(Box<Ast>, Box<Ast>),
    ObjectProjection(Box<Ast>, Box<Ast>),
    Slice(Option<i32>, Option<i32>, Option<i32>),
    Subexpr(Box<Ast>, Box<Ast>),
    WildcardIndex,
    WildcardValues,
}

/// Comparators (i.e., less than, greater than, etc.)
#[derive(Clone, PartialEq, Debug)]
pub enum Comparator { Eq, Lt, Le, Ne, Ge, Gt }

/// Encountered when an invalid JMESPath expression is parsed.
#[derive(Clone, PartialEq, Debug)]
pub struct ParseError {
    /// The error message.
    msg: String,
    /// The line number of the error.
    line: usize,
    /// The column of the error.
    col: usize,
}

/// JMESPath parser. Returns an Ast
pub struct Parser<'a> {
    /// Peekable token stream
    stream: Peekable<Lexer<'a>>,
    /// Expression being parsed
    expr: String,
    /// The current token
    token: Token,
    /// The current character offset in the expression
    pos: usize,
}

impl<'a> Parser<'a> {
    // Constructs a new lexer using the given expression string.
    pub fn new(expr: &'a str) -> Parser<'a> {
        let mut stream = Lexer::new(expr).peekable();
        let tok0 = stream.next().unwrap();
        Parser {
            stream: stream,
            expr: expr.to_string(),
            token: tok0,
            pos: 0,
        }
    }

    /// Parses the expression into result containing an AST or ParseError.
    pub fn parse(&mut self) -> Result<Ast, ParseError> {
        let result = self.expr(0);
        let token = self.stream.next();
        // After parsing the expression, we should have reached the end of the
        // stream.
        if result.is_err()
        || token.is_none()
        || token.unwrap() == Token::Eof {
            result
        } else {
            return self.err("Did not reach token stream EOF".as_ref());
        }
    }

    /// Ensures that the next token in the token stream is one of the pipe
    /// separated token named provided as the edible argument (e.g.,
    /// "Identifier|Eof").
    fn expect(&mut self, edible: &str) -> Result<Ast, ParseError> {
        self.advance();
        // Get the string name of the token.
        let token_name = self.token.token_to_string();
        if edible.contains(&token_name) {
            return Ok(CurrentNode);
        }
        let msg = format!("Expected one of the following tokens: {:?}", edible);
        self.err(&msg)
    }

    /// Advances the cursor position, skipping any whitespace encountered.
    #[inline]
    fn advance(&mut self) {
        self.pos += self.token.size();
        loop {
            let tok = self.stream.next();
            match tok {
                None => break,
                Some(Token::Whitespace) => self.pos += self.token.size(),
                _ => {
                    self.token = tok.unwrap();
                    break
                }
            }
        }
    }

    /// Main parse function of the Pratt parser that parses while RBP < LBP
    pub fn expr(&mut self, rbp: usize) -> Result<Ast, ParseError> {
        // Parse the NUD token.
        let mut left = match self.token.clone() {
            Token::At               => self.nud_at(),
            Token::Identifier(s, _) => self.nud_identifier(s),
            Token::Star             => self.nud_star(),
            Token::Lbracket         => self.nud_lbracket(),
            Token::Flatten          => self.nud_flatten(),
            // Token::Literal(_, _)    => self.nud_literal(),
            // Token::Ampersand        => self.nud_ampersand(),
            // Token::Lbrace           => self.nud_lbrace(),
            // Token::Filter           => self.nud_filter(),
            _ => { return self.err(&"Unexpected NUD token"); }
        };

        // Parse any LED tokens with a higher binding power.
        while rbp < self.token.lbp() {
            left = match self.token {
                Token::Dot      => self.led_dot(left.unwrap()),
                Token::Lbracket => self.led_lbracket(left.unwrap()),
                Token::Flatten  => self.led_flatten(left.unwrap()),
                _ => {
                    self.err(&"Unexpected LED token");
                    break;
                }
            };
        }

        left
    }

    /// Returns a formatted ParseError with the given message.
    fn err(&self, msg: &str) -> Result<Ast, ParseError> {
        // Find each new line and create a formatted error message.
        let mut line = 0;
        let mut col = self.pos;
        Err(ParseError {
            msg: format!("Error at {:?} token, {}: {}",
                         self.token, self.pos, msg),
            col: line,
            line: col
        })
    }

    /// Examples: "@"
    fn nud_at(&mut self) -> Result<Ast, ParseError> {
        self.advance();
        Ok(CurrentNode)
    }

    /// Examples: "Foo"
    fn nud_identifier(&mut self, s: String) -> Result<Ast, ParseError> {
        self.advance();
        Ok(Identifier(s))
    }

    /// Examples: "[0]", "[*]", "[a, b]", "[0:1]", etc...
    fn nud_lbracket(&mut self) -> Result<Ast, ParseError> {
        self.advance();
        match self.token {
            Token::Number(_, _) | Token::Colon => self.parse_array_index(),
            Token::Star => {
                if self.stream.peek() != Some(&Token::Rbracket) {
                    return self.parse_multi_list();
                }
                try!(self.expect("Star"));
                self.parse_wildcard_index()
            },
            _ => self.parse_multi_list()
        }
    }

    /// Examples: foo[*], foo[0], foo[:-1], etc.
    fn led_lbracket(&mut self, lhs: Ast) -> Result<Ast, ParseError> {
        try!(self.expect("Number|Colon|Star"));
        match self.token {
            Token::Number(_, _) | Token::Colon => self.parse_array_index(),
            _ => self.parse_wildcard_index()
        }
    }

    /// Examples: "*" (e.g., "* | *" would be a pipe containing two nud stars)
    fn nud_star(&mut self) -> Result<Ast, ParseError> {
        self.advance();
        self.parse_wildcard_values(CurrentNode)
    }

    /// Examples: "[]". Turns it into a LED flatten (i.e., "@[]").
    fn nud_flatten(&mut self) -> Result<Ast, ParseError> {
        self.led_flatten(CurrentNode)
    }

    /// Creates a Projection AST node for a flatten token.
    fn led_flatten(&mut self, lhs: Ast) -> Result<Ast, ParseError> {
        let rhs = try!(self.projection_rhs(Token::Flatten.lbp()));
        Ok(ArrayProjection(
            Box::new(Flatten(Box::new(lhs))),
            Box::new(rhs)
        ))
    }

    fn led_dot(&mut self, left: Ast) -> Result<Ast, ParseError> {
        let rhs = try!(self.parse_dot(Token::Dot.lbp()));
        Ok(Ast::Subexpr(Box::new(left), Box::new(rhs)))
    }

    /// Parses the right hand side of a dot expression.
    fn parse_dot(&mut self, lbp: usize) -> Result<Ast, ParseError> {
        try!(self.expect("Identifier|Star|Lbrace|Lbracket|Ampersand|Filter"));
        match self.token {
            Token::Lbracket => { self.advance(); self.parse_multi_list() },
            _ => self.expr(lbp)
        }
    }

    /// Parses the right hand side of a projection, using the given LBP to
    /// determine when to stop consuming tokens.
    fn projection_rhs(&mut self, lbp: usize) -> Result<Ast, ParseError> {
        let lbp = self.token.lbp();
        match self.token {
            Token::Dot      => self.parse_dot(lbp),
            Token::Lbracket => self.expr(lbp),
            Token::Filter   => self.expr(lbp),
            _ if lbp < 10   => Ok(CurrentNode),
            _               => self.err("Syntax error found in projection")
        }
    }

    /// Creates a projection for "[*]"
    fn parse_wildcard_index(&mut self) -> Result<Ast, ParseError> {
        try!(self.expect("Rbracket"));
        let lhs = Box::new(CurrentNode);
        let rhs = try!(self.projection_rhs(Token::Star.lbp()));
        Ok(ArrayProjection(lhs, Box::new(rhs)))
    }

    /// Creates a projection for "*"
    fn parse_wildcard_values(&mut self, lhs: Ast) -> Result<Ast, ParseError> {
        let rhs = try!(self.projection_rhs(Token::Star.lbp()));
        Ok(ObjectProjection(Box::new(lhs), Box::new(rhs)))
    }

    /// Parses [0], [::-1], [0:-1], [0:1], etc...
    fn parse_array_index(&mut self) -> Result<Ast, ParseError> {
        let mut parts = [None, None, None];
        let mut pos = 0;
        loop {
            match self.token {
                Token::Colon => {
                    pos += 1;
                    if pos > 2 {
                        return self.err("Too many colons in slice expr");
                    }
                    try!(self.expect("Number|Colon|Rbracket"));
                },
                Token::Number(value, _) => {
                    parts[pos] = Some(value);
                    try!(self.expect("Colon|Rbracket"));
                },
                Token::Rbracket => { self.advance(); break; },
                _ => { return self.err("Unexpected token"); },
            }
        }

        if pos == 0 {
            // No colons were found, so this is a simple index extraction.
            Ok(Index(parts[0].unwrap()))
        } else {
            // Sliced array from start (e.g., [2:])
            let lhs = Slice(parts[0], parts[1], parts[2]);
            let rhs = try!(self.projection_rhs(Token::Star.lbp()));
            Ok(ArrayProjection(Box::new(lhs), Box::new(rhs)))
        }
    }

    /// Parses multi-select lists (e.g., "[foo, bar, baz]")
    fn parse_multi_list(&mut self) -> Result<Ast, ParseError> {
        let mut nodes = vec!();
        loop {
            nodes.push(Box::new(try!(self.expr(0))));
            match self.token {
                // Skip comma tokens
                Token::Comma => {
                    self.advance();
                    // The closing "Rbracket" token cannot follow a comma.
                    if self.token.token_to_string() == "Rbracket" {
                        return self.err("Unexpected token after comma");
                    }
                },
                // Terminal conditon
                Token::Rbracket => break,
                // Got to EOF without closing
                Token::Eof => return self.err("Unclosed multi-select"),
                _ => {}
            }
        }

        Ok(MultiList(nodes))
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test] fn indentifier_test() {
        assert_eq!(parse("foo").unwrap(), Identifier("foo".to_string()));
    }

    #[test] fn current_node_test() {
        assert_eq!(parse("@").unwrap(), CurrentNode);
    }

    #[test] fn wildcard_values_test() {
        assert_eq!(parse("*").unwrap(),
                   ObjectProjection(Box::new(CurrentNode),
                                    Box::new(CurrentNode)));
    }

    #[test] fn dot_test() {
        assert!(parse("@.b").unwrap() == Subexpr(Box::new(CurrentNode),
                                                 Box::new(Identifier("b".to_string()))));
    }

    #[test] fn ensures_nud_token_is_valid_test() {

    }

    #[test] fn multi_list_test() {
        let l = MultiList(vec![Box::new(Identifier("a".to_string())),
                               Box::new(Identifier("b".to_string()))]);
        assert_eq!(parse("[a, b]").unwrap(), l);
    }

    #[test] fn multi_list_after_dot_test() {
        let l = MultiList(vec![Box::new(Identifier("a".to_string())),
                               Box::new(Identifier("b".to_string()))]);
        assert_eq!(parse("@.[a, b]").unwrap(), Subexpr(Box::new(CurrentNode), Box::new(l)));
    }

    #[test] fn parses_simple_index_extractions_test() {
        assert_eq!(parse("[0]").unwrap(), Index(0));
    }

    #[test] fn parses_single_element_slice_test() {
        assert_eq!(parse("[-1:]").unwrap(),
                   ArrayProjection(Box::new(Slice(Some(-1), None, None)),
                                   Box::new(CurrentNode)));
    }

    #[test] fn parses_double_element_slice_test() {
        assert_eq!(parse("[1:-1].a").unwrap(),
                   ArrayProjection(Box::new(Slice(Some(1), Some(-1), None)),
                                   Box::new(Identifier("a".to_string()))));
    }

    #[test] fn parses_revese_slice_test() {
        assert_eq!(parse("[::-1].a").unwrap(),
                   ArrayProjection(Box::new(Slice(None, None, Some(-1))),
                                   Box::new(Identifier("a".to_string()))));
    }
}
<commit_msg>Adding pipe and or parsing<commit_after>extern crate rustc_serialize;

pub use self::Ast::*;

use lexer::Lexer;
use lexer::Token;
use self::rustc_serialize::json::{Json};

use std::iter::Peekable;

/// Parses a JMESPath expression into an AST
pub fn parse(expr: &str) -> Result<Ast, ParseError> {
    Parser::new(expr).parse()
}

/// Represents the abstract syntax tree of a JMESPath expression.
#[derive(Clone, PartialEq, Debug)]
pub enum Ast {
    Comparison(Comparator, Box<Ast>, Box<Ast>),
    CurrentNode,
    Expref(Box<Ast>),
    Flatten(Box<Ast>),
    Function(char, Vec<(Box<Ast>, Box<Ast>)>),
    Identifier(String),
    Index(i32),
    Literal(Box<Json>),
    MultiList(Vec<Box<Ast>>),
    MultiHash(Vec<Vec<(char, Box<Ast>)>>),
    ArrayProjection(Box<Ast>, Box<Ast>),
    ObjectProjection(Box<Ast>, Box<Ast>),
    Or(Box<Ast>, Box<Ast>),
    Slice(Option<i32>, Option<i32>, Option<i32>),
    Subexpr(Box<Ast>, Box<Ast>),
    WildcardIndex,
    WildcardValues,
}

/// Comparators (i.e., less than, greater than, etc.)
#[derive(Clone, PartialEq, Debug)]
pub enum Comparator { Eq, Lt, Le, Ne, Ge, Gt }

/// Encountered when an invalid JMESPath expression is parsed.
#[derive(Clone, PartialEq, Debug)]
pub struct ParseError {
    /// The error message.
    msg: String,
    /// The line number of the error.
    line: usize,
    /// The column of the error.
    col: usize,
}

/// JMESPath parser. Returns an Ast
pub struct Parser<'a> {
    /// Peekable token stream
    stream: Peekable<Lexer<'a>>,
    /// Expression being parsed
    expr: String,
    /// The current token
    token: Token,
    /// The current character offset in the expression
    pos: usize,
}

impl<'a> Parser<'a> {
    // Constructs a new lexer using the given expression string.
    pub fn new(expr: &'a str) -> Parser<'a> {
        let mut stream = Lexer::new(expr).peekable();
        let tok0 = stream.next().unwrap();
        Parser {
            stream: stream,
            expr: expr.to_string(),
            token: tok0,
            pos: 0,
        }
    }

    /// Parses the expression into result containing an AST or ParseError.
    pub fn parse(&mut self) -> Result<Ast, ParseError> {
        let result = self.expr(0);
        let token = self.stream.next();
        // After parsing the expression, we should have reached the end of the
        // stream.
        if result.is_err()
        || token.is_none()
        || token.unwrap() == Token::Eof {
            result
        } else {
            return self.err("Did not reach token stream EOF".as_ref());
        }
    }

    /// Ensures that the next token in the token stream is one of the pipe
    /// separated token named provided as the edible argument (e.g.,
    /// "Identifier|Eof").
    fn expect(&mut self, edible: &str) -> Result<Ast, ParseError> {
        self.advance();
        // Get the string name of the token.
        let token_name = self.token.token_to_string();
        if edible.contains(&token_name) {
            return Ok(CurrentNode);
        }
        let msg = format!("Expected one of the following tokens: {:?}", edible);
        self.err(&msg)
    }

    /// Advances the cursor position, skipping any whitespace encountered.
    #[inline]
    fn advance(&mut self) {
        self.pos += self.token.size();
        loop {
            let tok = self.stream.next();
            match tok {
                None => break,
                Some(Token::Whitespace) => self.pos += self.token.size(),
                _ => {
                    self.token = tok.unwrap();
                    break
                }
            }
        }
    }

    /// Main parse function of the Pratt parser that parses while RBP < LBP
    pub fn expr(&mut self, rbp: usize) -> Result<Ast, ParseError> {
        // Parse the NUD token.
        let mut left = match self.token.clone() {
            Token::At               => self.nud_at(),
            Token::Identifier(s, _) => self.nud_identifier(s),
            Token::Star             => self.nud_star(),
            Token::Lbracket         => self.nud_lbracket(),
            Token::Flatten          => self.nud_flatten(),
            // Token::Literal(_, _)    => self.nud_literal(),
            // Token::Ampersand        => self.nud_ampersand(),
            // Token::Lbrace           => self.nud_lbrace(),
            // Token::Filter           => self.nud_filter(),
            _ => { return self.err(&"Unexpected NUD token"); }
        };

        // Parse any LED tokens with a higher binding power.
        while rbp < self.token.lbp() {
            left = match self.token {
                Token::Dot      => self.led_dot(left.unwrap()),
                Token::Lbracket => self.led_lbracket(left.unwrap()),
                Token::Flatten  => self.led_flatten(left.unwrap()),
                Token::Or       => self.led_or(left.unwrap()),
                Token::Pipe     => self.led_pipe(left.unwrap()),
                _ => {
                    self.err(&"Unexpected LED token");
                    break;
                }
            };
        }

        left
    }

    /// Returns a formatted ParseError with the given message.
    fn err(&self, msg: &str) -> Result<Ast, ParseError> {
        // Find each new line and create a formatted error message.
        let mut line = 0;
        let mut col = self.pos;
        Err(ParseError {
            msg: format!("Error at {:?} token, {}: {}",
                         self.token, self.pos, msg),
            col: line,
            line: col
        })
    }

    /// Examples: "@"
    fn nud_at(&mut self) -> Result<Ast, ParseError> {
        self.advance();
        Ok(CurrentNode)
    }

    /// Examples: "Foo"
    fn nud_identifier(&mut self, s: String) -> Result<Ast, ParseError> {
        self.advance();
        Ok(Identifier(s))
    }

    /// Examples: "[0]", "[*]", "[a, b]", "[0:1]", etc...
    fn nud_lbracket(&mut self) -> Result<Ast, ParseError> {
        self.advance();
        match self.token {
            Token::Number(_, _) | Token::Colon => self.parse_array_index(),
            Token::Star => {
                if self.stream.peek() != Some(&Token::Rbracket) {
                    return self.parse_multi_list();
                }
                try!(self.expect("Star"));
                self.parse_wildcard_index()
            },
            _ => self.parse_multi_list()
        }
    }

    /// Examples: foo[*], foo[0], foo[:-1], etc.
    fn led_lbracket(&mut self, lhs: Ast) -> Result<Ast, ParseError> {
        try!(self.expect("Number|Colon|Star"));
        match self.token {
            Token::Number(_, _) | Token::Colon => self.parse_array_index(),
            _ => self.parse_wildcard_index()
        }
    }

    /// Examples: "*" (e.g., "* | *" would be a pipe containing two nud stars)
    fn nud_star(&mut self) -> Result<Ast, ParseError> {
        self.advance();
        self.parse_wildcard_values(CurrentNode)
    }

    /// Examples: "[]". Turns it into a LED flatten (i.e., "@[]").
    fn nud_flatten(&mut self) -> Result<Ast, ParseError> {
        self.led_flatten(CurrentNode)
    }

    /// Creates a Projection AST node for a flatten token.
    fn led_flatten(&mut self, lhs: Ast) -> Result<Ast, ParseError> {
        let rhs = try!(self.projection_rhs(Token::Flatten.lbp()));
        Ok(ArrayProjection(
            Box::new(Flatten(Box::new(lhs))),
            Box::new(rhs)
        ))
    }

    fn led_dot(&mut self, left: Ast) -> Result<Ast, ParseError> {
        let rhs = try!(self.parse_dot(Token::Dot.lbp()));
        Ok(Ast::Subexpr(Box::new(left), Box::new(rhs)))
    }

    fn led_or(&mut self, left: Ast) -> Result<Ast, ParseError> {
        self.advance();
        let rhs = try!(self.expr(Token::Or.lbp()));
        Ok(Or(Box::new(left), Box::new(rhs)))
    }

    fn led_pipe(&mut self, left: Ast) -> Result<Ast, ParseError> {
        self.advance();
        let rhs = try!(self.expr(Token::Pipe.lbp()));
        Ok(Subexpr(Box::new(left), Box::new(rhs)))
    }

    /// Parses the right hand side of a dot expression.
    fn parse_dot(&mut self, lbp: usize) -> Result<Ast, ParseError> {
        try!(self.expect("Identifier|Star|Lbrace|Lbracket|Ampersand|Filter"));
        match self.token {
            Token::Lbracket => { self.advance(); self.parse_multi_list() },
            _ => self.expr(lbp)
        }
    }

    /// Parses the right hand side of a projection, using the given LBP to
    /// determine when to stop consuming tokens.
    fn projection_rhs(&mut self, lbp: usize) -> Result<Ast, ParseError> {
        let lbp = self.token.lbp();
        match self.token {
            Token::Dot      => self.parse_dot(lbp),
            Token::Lbracket => self.expr(lbp),
            Token::Filter   => self.expr(lbp),
            _ if lbp < 10   => Ok(CurrentNode),
            _               => self.err("Syntax error found in projection")
        }
    }

    /// Creates a projection for "[*]"
    fn parse_wildcard_index(&mut self) -> Result<Ast, ParseError> {
        try!(self.expect("Rbracket"));
        let lhs = Box::new(CurrentNode);
        let rhs = try!(self.projection_rhs(Token::Star.lbp()));
        Ok(ArrayProjection(lhs, Box::new(rhs)))
    }

    /// Creates a projection for "*"
    fn parse_wildcard_values(&mut self, lhs: Ast) -> Result<Ast, ParseError> {
        let rhs = try!(self.projection_rhs(Token::Star.lbp()));
        Ok(ObjectProjection(Box::new(lhs), Box::new(rhs)))
    }

    /// Parses [0], [::-1], [0:-1], [0:1], etc...
    fn parse_array_index(&mut self) -> Result<Ast, ParseError> {
        let mut parts = [None, None, None];
        let mut pos = 0;
        loop {
            match self.token {
                Token::Colon => {
                    pos += 1;
                    if pos > 2 {
                        return self.err("Too many colons in slice expr");
                    }
                    try!(self.expect("Number|Colon|Rbracket"));
                },
                Token::Number(value, _) => {
                    parts[pos] = Some(value);
                    try!(self.expect("Colon|Rbracket"));
                },
                Token::Rbracket => { self.advance(); break; },
                _ => { return self.err("Unexpected token"); },
            }
        }

        if pos == 0 {
            // No colons were found, so this is a simple index extraction.
            Ok(Index(parts[0].unwrap()))
        } else {
            // Sliced array from start (e.g., [2:])
            let lhs = Slice(parts[0], parts[1], parts[2]);
            let rhs = try!(self.projection_rhs(Token::Star.lbp()));
            Ok(ArrayProjection(Box::new(lhs), Box::new(rhs)))
        }
    }

    /// Parses multi-select lists (e.g., "[foo, bar, baz]")
    fn parse_multi_list(&mut self) -> Result<Ast, ParseError> {
        let mut nodes = vec!();
        loop {
            nodes.push(Box::new(try!(self.expr(0))));
            match self.token {
                // Skip comma tokens
                Token::Comma => {
                    self.advance();
                    // The closing "Rbracket" token cannot follow a comma.
                    if self.token.token_to_string() == "Rbracket" {
                        return self.err("Unexpected token after comma");
                    }
                },
                // Terminal conditon
                Token::Rbracket => break,
                // Got to EOF without closing
                Token::Eof => return self.err("Unclosed multi-select"),
                _ => {}
            }
        }

        Ok(MultiList(nodes))
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test] fn indentifier_test() {
        assert_eq!(parse("foo").unwrap(), Identifier("foo".to_string()));
    }

    #[test] fn current_node_test() {
        assert_eq!(parse("@").unwrap(), CurrentNode);
    }

    #[test] fn wildcard_values_test() {
        assert_eq!(parse("*").unwrap(),
                   ObjectProjection(Box::new(CurrentNode),
                                    Box::new(CurrentNode)));
    }

    #[test] fn dot_test() {
        assert!(parse("@.b").unwrap() == Subexpr(Box::new(CurrentNode),
                                                 Box::new(Identifier("b".to_string()))));
    }

    #[test] fn ensures_nud_token_is_valid_test() {

    }

    #[test] fn multi_list_test() {
        let l = MultiList(vec![Box::new(Identifier("a".to_string())),
                               Box::new(Identifier("b".to_string()))]);
        assert_eq!(parse("[a, b]").unwrap(), l);
    }

    #[test] fn multi_list_after_dot_test() {
        let l = MultiList(vec![Box::new(Identifier("a".to_string())),
                               Box::new(Identifier("b".to_string()))]);
        assert_eq!(parse("@.[a, b]").unwrap(), Subexpr(Box::new(CurrentNode), Box::new(l)));
    }

    #[test] fn parses_simple_index_extractions_test() {
        assert_eq!(parse("[0]").unwrap(), Index(0));
    }

    #[test] fn parses_single_element_slice_test() {
        assert_eq!(parse("[-1:]").unwrap(),
                   ArrayProjection(Box::new(Slice(Some(-1), None, None)),
                                   Box::new(CurrentNode)));
    }

    #[test] fn parses_double_element_slice_test() {
        assert_eq!(parse("[1:-1].a").unwrap(),
                   ArrayProjection(Box::new(Slice(Some(1), Some(-1), None)),
                                   Box::new(Identifier("a".to_string()))));
    }

    #[test] fn parses_revese_slice_test() {
        assert_eq!(parse("[::-1].a").unwrap(),
                   ArrayProjection(Box::new(Slice(None, None, Some(-1))),
                                   Box::new(Identifier("a".to_string()))));
    }

    #[test] fn parses_or_test() {
        assert_eq!(parse("a || b").unwrap(),
                   Or(Box::new(Identifier("a".to_string())),
                      Box::new(Identifier("b".to_string()))));
    }

    #[test] fn parses_pipe_test() {
        assert_eq!(parse("a | b").unwrap(),
                   Subexpr(Box::new(Identifier("a".to_string())),
                      Box::new(Identifier("b".to_string()))));
    }
}
<|endoftext|>


<commit_before>pub use amq_protocol::types::{Boolean,FieldTable,AMQPValue,ShortUInt,LongUInt,LongLongUInt,ShortString,LongString};

<commit_msg>async: reexport more types from amq_protocol<commit_after>pub use amq_protocol::types::{AMQPType,AMQPValue};
pub use amq_protocol::types::{ShortShortUInt,ShortUInt,LongUInt,LongLongUInt};
pub use amq_protocol::types::{ShortShortInt,ShortInt,LongInt,LongLongInt};
pub use amq_protocol::types::{Float,Double,DecimalValue};
pub use amq_protocol::types::{Boolean,Timestamp,Void};
pub use amq_protocol::types::{ByteArray,ShortString,LongString};
pub use amq_protocol::types::{FieldArray,FieldTable};
<|endoftext|>


<commit_before>use xplane_plugin::*;
use xpgl::gl;
use xplm;

use xplm::ui::*;
use xplm::graphics::*;
use xplm::graphics::window::*;

use mapcore::map::Map;
use mapcore::layer::Layer;
use mapcore::{LatLon, LatLonRect};
use mapcore::projection::Projection;
use mapcore::equirectangular::EquirectangularProjection;

use std::rc::Rc;
use std::cell::RefCell;
use std::mem;

/// The graphics state used for 2D drawing
const GRAPHICS_STATE_2D : GraphicsState = GraphicsState {
    fog: false,
    lighting: false,
    alpha_testing: false,
    alpha_blending: true,
    depth_testing: false,
    depth_writing: false,
    textures: 0,
};

pub struct TerrainDisplayPlugin {
    /// The window that displays graphics
    window: Option<Rc<RefCell<Window>>>,
    /// The map view
    map: Option<Rc<Map>>,
}

impl Plugin for TerrainDisplayPlugin {
    fn start() -> Option<Self> {
        // Load OpenGL symbols
        gl::load_with(|name| {
            unsafe { mem::transmute(xplm::find_symbol(name)) }
        });

        Some(TerrainDisplayPlugin {
            window: None,
            map: None,
        })
    }
    fn enable(&mut self) {
        self.window = Some(Window::new(&Rect { left: 100, top: 1000, right: 400, bottom: 600 }));
        let mut map = Map::new(EquirectangularProjection);
        map.add_layer(TestLayer);
        self.map = Some(Rc::new(map));
        {
            let map_ref = self.map.as_ref().unwrap().clone();
            let local_draw_window = move |window: &mut Window| {

                let rect = window.get_geometry();

                set_state(&GRAPHICS_STATE_2D);
                unsafe {
                    gl::Color3f(0.0, 0.5, 0.0);
                    gl::Begin(gl::QUADS);
                    gl::Vertex2i(rect.left, rect.bottom);
                    gl::Vertex2i(rect.left, rect.top);
                    gl::Vertex2i(rect.right, rect.top);
                    gl::Vertex2i(rect.right, rect.bottom);
                    gl::End();
                }
                map_ref.draw(rect.left, rect.top, (rect.right - rect.left), (rect.bottom - rect.top));
            };

            let mut window = self.window.as_mut().unwrap().borrow_mut();
            window.set_draw_callback(local_draw_window);
            window.set_visible(true);
        }
    }
    fn disable(&mut self) {
        self.window = None;
        self.map = None;
    }

    fn info<'a, 'b, 'c>(&self) -> PluginInfo<'a, 'b, 'c> {
        PluginInfo {
            name: "Terrain Display",
            signature: "org.samcrow.dev.terrain_display",
            description: "Draws a display of the terrain around the aircraft",
        }
    }

    fn stop(&mut self) {

    }
}

struct TestLayer;

impl Layer for TestLayer {
    fn draw(&self, projection: &Projection, x: i32, y: i32, width: i32, height: i32) {
        let height = height / 2;
        set_state(&GRAPHICS_STATE_2D);
        unsafe {
            gl::Color3f(0.8, 0.3, 0.0);
            gl::Begin(gl::QUADS);
            gl::Vertex2i(x, y + height);
            gl::Vertex2i(x , y );
            gl::Vertex2i(x + width, y );
            gl::Vertex2i(x + width, y + height);
            gl::End();
        }
    }

    fn bounds(&self) -> Option<LatLonRect> {
        None
    }
}
<commit_msg>Simplified Map usage<commit_after>use xplane_plugin::*;
use xpgl::gl;
use xplm;

use xplm::ui::*;
use xplm::graphics::*;
use xplm::graphics::window::*;

use mapcore::map::Map;
use mapcore::layer::Layer;
use mapcore::{LatLon, LatLonRect};
use mapcore::projection::Projection;
use mapcore::equirectangular::EquirectangularProjection;

use std::rc::Rc;
use std::cell::RefCell;
use std::mem;

/// The graphics state used for 2D drawing
const GRAPHICS_STATE_2D : GraphicsState = GraphicsState {
    fog: false,
    lighting: false,
    alpha_testing: false,
    alpha_blending: true,
    depth_testing: false,
    depth_writing: false,
    textures: 0,
};

pub struct TerrainDisplayPlugin {
    /// The window that displays graphics
    window: Option<Rc<RefCell<Window>>>,
}

impl Plugin for TerrainDisplayPlugin {
    fn start() -> Option<Self> {
        // Load OpenGL symbols
        gl::load_with(|name| {
            unsafe { mem::transmute(xplm::find_symbol(name)) }
        });

        Some(TerrainDisplayPlugin {
            window: None,
        })
    }
    fn enable(&mut self) {
        self.window = Some(Window::new(&Rect { left: 100, top: 1000, right: 400, bottom: 600 }));
        let mut map = Map::new(EquirectangularProjection);
        map.add_layer(TestLayer);
        {
            let local_draw_window = move |window: &mut Window| {

                let rect = window.get_geometry();

                set_state(&GRAPHICS_STATE_2D);
                unsafe {
                    gl::Color3f(0.0, 0.5, 0.0);
                    gl::Begin(gl::QUADS);
                    gl::Vertex2i(rect.left, rect.bottom);
                    gl::Vertex2i(rect.left, rect.top);
                    gl::Vertex2i(rect.right, rect.top);
                    gl::Vertex2i(rect.right, rect.bottom);
                    gl::End();
                }
                map.draw(rect.left, rect.top, (rect.right - rect.left), (rect.bottom - rect.top));
            };

            let mut window = self.window.as_mut().unwrap().borrow_mut();
            window.set_draw_callback(local_draw_window);
            window.set_visible(true);
        }
    }
    fn disable(&mut self) {
        self.window = None;
    }

    fn info<'a, 'b, 'c>(&self) -> PluginInfo<'a, 'b, 'c> {
        PluginInfo {
            name: "Terrain Display",
            signature: "org.samcrow.dev.terrain_display",
            description: "Draws a display of the terrain around the aircraft",
        }
    }

    fn stop(&mut self) {

    }
}

struct TestLayer;

impl Layer for TestLayer {
    fn draw(&self, projection: &Projection, x: i32, y: i32, width: i32, height: i32) {
        let height = height / 2;
        set_state(&GRAPHICS_STATE_2D);
        unsafe {
            gl::Color3f(0.8, 0.3, 0.0);
            gl::Begin(gl::QUADS);
            gl::Vertex2i(x, y + height);
            gl::Vertex2i(x , y );
            gl::Vertex2i(x + width, y );
            gl::Vertex2i(x + width, y + height);
            gl::End();
        }
    }

    fn bounds(&self) -> Option<LatLonRect> {
        None
    }
}
<|endoftext|>