<commit_before>use self::streamql::statement;
pub use self::streamql::ParseError;
use super::row_builder::RowBuilder;
use super::schema::Type;
use super::value::Value;

mod integration_tests;

peg_file! streamql("streamql.rustpeg");

pub fn parse_statement(query: &str) -> Result<Statement, ParseError> {
    statement(query)
}

#[derive(Debug)]
pub enum Statement {
    // Stream & Keys
    Insert(String, RowBuilder),
    // name
    DeclareStream(String, Vec<ColumnSpec>),
    DropStream,
    UseDatabase,
    // Stream
    Select(String),
    Subscribe,
}

// infix operators
// used for 2 expressions
// 2 expressions must evaluate to a bool
enum Operator {
    Equal,
    NotEqual,
    GreaterThan,
    GreaterThanEqual,
    LessThan,
    LessThanEqual,
    And,
    Or
}

pub enum Expression {
    Value(Value),
    Comparison(Operator, Box<Expression>, Box<Expression>),
    Function(String, Vec<Expression> ),
    Field(String), // field name
    None,
}

#[derive(Debug)]
pub struct ColumnSpec {
    pub name: String,
    pub ftype: Type,
}

impl ColumnSpec {
    fn new(name: String, ftype: Type) -> ColumnSpec {
        ColumnSpec{name: name,
                   ftype: ftype}
    }
}

#[cfg(test)]
mod test {
    use super::parse_statement;
    use super::Statement;
    use super::streamql::*;
    use db::value::Value;

    #[test]
    fn test_basic_insert() {

        let result = parse_statement("INSERT INTO test set k=1;").unwrap();

        if let Statement::Insert(stream, builder) = result {
            assert_eq!(stream, String::from("test"));
        } else {
            panic!("")
        }
        let x = "INSERT INTO test set k=1, v=2;";
        let result = parse_statement(x).unwrap();

    }

    #[test]
    fn test_parsing_with_quoted_string() {
        let result = parse_statement("INSERT INTO test set k='test';").unwrap();
        let result = parse_statement("INSERT INTO test set k='test my ''friend''';").unwrap();

    }

    #[test]
    fn test_int_parsing() {
        let tmp = int_value("42").unwrap();
    }

    #[test]
    fn test_basic_string_parsing() {
        string("hello this is a test").unwrap();
    }

    #[test]
    fn test_escaped_string() {
        let x = string("hello this is a ''test''").unwrap();
        assert_eq!(x, "hello this is a 'test'");
    }

    #[test]
    fn test_quoted_string() {
        let x = "'it''s mine'";
        let p = quoted_string(x).unwrap();
        assert_eq!(p, "it's mine");
    }

    #[test]
    fn value_string_parsing() {
        let x = "'hello'";
        if Value::from(x) == value(x).unwrap() {
            assert_eq!(x, "hello");
        }

    }

    #[test]
    fn declare_stream_parsing() {
        let x = "declare stream readings ( ts int, val int, s text );";
        let p = parse_statement(x).unwrap();
    }

    #[test]
    fn test_basic_parse_column_specification() {
        let x = "ts int";
        let p = column_spec(x).unwrap();

        let x = "ts text";
        let p = column_spec(x).unwrap();
    }

    #[test]
    fn test_column_spec_list() {
        let x = "ts int, val int, s text ";
        let p = column_spec_list(x).unwrap();

        assert_eq!(p.len(), 3);

        assert_eq!(p[0].name, "ts");
        assert_eq!(p[1].name, "val");
        assert_eq!(p[2].name, "s");
    }

    #[test]
    fn test_select_queries() {
        let queries = ["select * from test",
                        "select name, age from users",
                        "select name from cities where state = 'CA'"];
        for q in queries.into_iter() {
            parse_statement(&q).expect(q);
        }

    }

    #[test]
    fn test_field_list() {
        let queries = ["name, email",
            "*", "stuff"];
        for q in queries.into_iter() {
            field_list(q).expect(q);
        }
    }

    #[test]
    fn test_where_clause() {
        let queries = ["where name = 'jon'",
        "where id = 5",
        "where name = 'bill' and age > 35"];
        for q in queries.into_iter() {
            field_list(q).expect(q);
        }

    }

    // expression testing
    #[test]
    fn test_value_expression() {
        let tmp = expression_value("1").expect("1");
    }
    #[test]
    fn test_field_expression() {
        let tmp = expression_field("name")
                   .expect("name didn't parse");
    }

    #[test]
    fn test_operators() {
        expression_operator("name > 5")
            .expect("Expecting name > 5");

        let x = "age > 10 and city = 'Boston'";
        // technically is this:
        // let x = "((age > 10) and (city = 'Boston'))";
        // need to rewrite as a bunch of nested binary ops
        // do i need a second parser just to rewrite?
        expression(x).expect(x);
    }

    #[test]
    fn test_grouping() {
        expression_grouped("(fname > 0)")
            .expect("Expecting name > 5");
        expression("(fname > 0)")
            .expect("Expecting name > 5");

    }

    #[test]
    fn test_and() {
        //expression_and()
    }

}

<commit_msg>another test for grouping and chaining<commit_after>use self::streamql::statement;
pub use self::streamql::ParseError;
use super::row_builder::RowBuilder;
use super::schema::Type;
use super::value::Value;

mod integration_tests;

peg_file! streamql("streamql.rustpeg");

pub fn parse_statement(query: &str) -> Result<Statement, ParseError> {
    statement(query)
}

#[derive(Debug)]
pub enum Statement {
    // Stream & Keys
    Insert(String, RowBuilder),
    // name
    DeclareStream(String, Vec<ColumnSpec>),
    DropStream,
    UseDatabase,
    // Stream
    Select(String),
    Subscribe,
}

// infix operators
// used for 2 expressions
// 2 expressions must evaluate to a bool
enum Operator {
    Equal,
    NotEqual,
    GreaterThan,
    GreaterThanEqual,
    LessThan,
    LessThanEqual,
    And,
    Or
}

pub enum Expression {
    Value(Value),
    Comparison(Operator, Box<Expression>, Box<Expression>),
    Function(String, Vec<Expression> ),
    Field(String), // field name
    None,
}

#[derive(Debug)]
pub struct ColumnSpec {
    pub name: String,
    pub ftype: Type,
}

impl ColumnSpec {
    fn new(name: String, ftype: Type) -> ColumnSpec {
        ColumnSpec{name: name,
                   ftype: ftype}
    }
}

#[cfg(test)]
mod test {
    use super::parse_statement;
    use super::Statement;
    use super::streamql::*;
    use db::value::Value;

    #[test]
    fn test_basic_insert() {

        let result = parse_statement("INSERT INTO test set k=1;").unwrap();

        if let Statement::Insert(stream, builder) = result {
            assert_eq!(stream, String::from("test"));
        } else {
            panic!("")
        }
        let x = "INSERT INTO test set k=1, v=2;";
        let result = parse_statement(x).unwrap();

    }

    #[test]
    fn test_parsing_with_quoted_string() {
        let result = parse_statement("INSERT INTO test set k='test';").unwrap();
        let result = parse_statement("INSERT INTO test set k='test my ''friend''';").unwrap();

    }

    #[test]
    fn test_int_parsing() {
        let tmp = int_value("42").unwrap();
    }

    #[test]
    fn test_basic_string_parsing() {
        string("hello this is a test").unwrap();
    }

    #[test]
    fn test_escaped_string() {
        let x = string("hello this is a ''test''").unwrap();
        assert_eq!(x, "hello this is a 'test'");
    }

    #[test]
    fn test_quoted_string() {
        let x = "'it''s mine'";
        let p = quoted_string(x).unwrap();
        assert_eq!(p, "it's mine");
    }

    #[test]
    fn value_string_parsing() {
        let x = "'hello'";
        if Value::from(x) == value(x).unwrap() {
            assert_eq!(x, "hello");
        }

    }

    #[test]
    fn declare_stream_parsing() {
        let x = "declare stream readings ( ts int, val int, s text );";
        let p = parse_statement(x).unwrap();
    }

    #[test]
    fn test_basic_parse_column_specification() {
        let x = "ts int";
        let p = column_spec(x).unwrap();

        let x = "ts text";
        let p = column_spec(x).unwrap();
    }

    #[test]
    fn test_column_spec_list() {
        let x = "ts int, val int, s text ";
        let p = column_spec_list(x).unwrap();

        assert_eq!(p.len(), 3);

        assert_eq!(p[0].name, "ts");
        assert_eq!(p[1].name, "val");
        assert_eq!(p[2].name, "s");
    }

    #[test]
    fn test_select_queries() {
        let queries = ["select * from test",
                        "select name, age from users",
                        "select name from cities where state = 'CA'"];
        for q in queries.into_iter() {
            parse_statement(&q).expect(q);
        }

    }

    #[test]
    fn test_field_list() {
        let queries = ["name, email",
            "*", "stuff"];
        for q in queries.into_iter() {
            field_list(q).expect(q);
        }
    }

    #[test]
    fn test_where_clause() {
        let queries = ["where name = 'jon'",
        "where id = 5",
        "where name = 'bill' and age > 35"];
        for q in queries.into_iter() {
            field_list(q).expect(q);
        }

    }

    // expression testing
    #[test]
    fn test_value_expression() {
        let tmp = expression_value("1").expect("1");
    }
    #[test]
    fn test_field_expression() {
        let tmp = expression_field("name")
                   .expect("name didn't parse");
    }

    #[test]
    fn test_operators() {
        expression_operator("name > 5")
            .expect("Expecting name > 5");

        let x = "age > 10 and city = 'Boston'";
        // technically is this:
        // let x = "((age > 10) and (city = 'Boston'))";
        // need to rewrite as a bunch of nested binary ops
        // do i need a second parser just to rewrite?
        expression(x).expect(x);

        // same as above but needed to be safe
        let x = "(age > 10) and city = 'Boston'";
        expression(x).expect(x);
    }

    #[test]
    fn test_grouping() {
        expression_grouped("(fname > 0)")
            .expect("Expecting name > 5");
        expression("(fname > 0)")
            .expect("Expecting name > 5");

    }

    #[test]
    fn test_and() {
        //expression_and()
    }

}

<|endoftext|>


<commit_before>use std::fmt::{Display, Debug, Formatter, Result as FmtResult};
use std::str::FromStr;
use url::Host;
use serde::{Deserialize, Deserializer};
use serde::{Serialize, Serializer};

#[derive(Clone,PartialEq,Eq)]
pub struct EmailAddress {
    serialization: String,
    local_end: usize,
}

impl FromStr for EmailAddress {
    type Err = ();

    fn from_str(input: &str) -> Result<EmailAddress, ()> {
        let local_end = input.find('@').ok_or(())?;
        // Transform local part to lowercase, according to unicode
        let local = input[..local_end].to_lowercase();
        // Verify and normalize domain to lowercase ASCII, according to WHATWG
        let host = Host::parse(&input[local_end + 1..]).map_err(|_| ())?;
        if let Host::Domain(domain) = host {
            Ok(EmailAddress::from_parts(&local, &domain))
        } else {
            Err(())
        }
    }
}

impl AsRef<str> for EmailAddress {
    /// Return the serialization of this email address.
    fn as_ref(&self) -> &str {
        &self.serialization
    }
}

impl Serialize for EmailAddress {
    /// Serialize this email address as a string.
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
            where S: Serializer {
        self.as_str().serialize(serializer)
    }
}

impl EmailAddress {
    /// Create an email address from trusted local and domain parts.
    fn from_parts(local: &str, domain: &str) -> EmailAddress {
        EmailAddress {
            serialization: format!("{}@{}", local, domain),
            local_end: local.len(),
        }
    }

    /// Create an EmailAddress from trusted input.
    ///
    /// The input is the already serialized form, preferably extracted from an
    /// EmailAddress parsed earlier.
    pub fn from_trusted(input: &str) -> EmailAddress {
        EmailAddress {
            serialization: input.to_owned(),
            local_end: input.find('@').expect("no @ found in input"),
        }
    }

    /// Deserialize implementation for trusted input.
    ///
    /// Because this assumes input is valid, it must be explicitely selected using
    /// `#[serde(deserialize_with = "EmailAddress::deserialize_trusted")]`
    pub fn deserialize_trusted<'de, D>(deserializer: D) -> Result<EmailAddress, D::Error>
            where D: Deserializer<'de> {
        <&str>::deserialize(deserializer).map(|s| EmailAddress::from_trusted(s))
    }

    /// Return the serialization.
    pub fn as_str(&self) -> &str {
        &self.serialization
    }

    /// Return the normalized local part.
    pub fn local(&self) -> &str {
        &self.serialization[..self.local_end]
    }

    /// Return the ASCII normalized domain.
    pub fn domain(&self) -> &str {
        &self.serialization[self.local_end + 1..]
    }

    /// Return the normalized local and domain parts as a tuple.
    pub fn parts(&self) -> (&str, &str) {
        (self.local(), self.domain())
    }

    /// Normalize a Google email address.
    ///
    /// This method can also be used to normalize G Suite addresses.
    pub fn normalize_google(&self) -> EmailAddress {
        let (local, domain) = self.parts();

        // Normalize googlemail.com to gmail.com
        let domain = match domain {
            "googlemail.com" => "gmail.com",
            domain => domain,
        };

        // Trim plus addresses
        let local = match self.local().find('+') {
            Some(pos) => &local[..pos],
            None => local,
        };

        // Ignore dots
        let local = local.replace(".", "");

        EmailAddress::from_parts(&local, domain)
    }
}

/// Display the serialization of this email address.
impl Display for EmailAddress {
    fn fmt(&self, formatter: &mut Formatter) -> FmtResult {
        Display::fmt(&self.serialization, formatter)
    }
}

/// Debug the serialization of this email address.
impl Debug for EmailAddress {
    fn fmt(&self, formatter: &mut Formatter) -> FmtResult {
        Debug::fmt(&self.serialization, formatter)
    }
}

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

    #[test]
    fn test_normal() {
        fn parse(input: &str, output: &str) {
            assert_eq!(
                input.parse::<EmailAddress>().unwrap(),
                EmailAddress::from_trusted(output)
            )
        }
        parse("example.foo+bar@example.com",
              "example.foo+bar@example.com");
        parse("EXAMPLE.FOO+BAR@EXAMPLE.COM",
              "example.foo+bar@example.com");
        parse("BJÖRN@göteborg.test",
              "björn@xn--gteborg-90a.test");
    }

    #[test]
    fn test_google() {
        fn parse(input: &str, output: &str) {
            assert_eq!(
                input.parse::<EmailAddress>().unwrap().normalize_google(),
                EmailAddress::from_trusted(output)
            )
        }
        parse("example@gmail.com",
              "example@gmail.com");
        parse("example@googlemail.com",
              "example@gmail.com");
        parse("example.foo@gmail.com",
              "examplefoo@gmail.com");
        parse("example+bar@gmail.com",
              "example@gmail.com");
        parse("example.foo+bar@googlemail.com",
              "examplefoo@gmail.com");
        parse("EXAMPLE@GOOGLEMAIL.COM",
              "example@gmail.com");
        parse("EXAMPLE.FOO+BAR@GOOGLEMAIL.COM",
              "examplefoo@gmail.com");
    }
}
<commit_msg>Add special casing test<commit_after>use std::fmt::{Display, Debug, Formatter, Result as FmtResult};
use std::str::FromStr;
use url::Host;
use serde::{Deserialize, Deserializer};
use serde::{Serialize, Serializer};

#[derive(Clone,PartialEq,Eq)]
pub struct EmailAddress {
    serialization: String,
    local_end: usize,
}

impl FromStr for EmailAddress {
    type Err = ();

    fn from_str(input: &str) -> Result<EmailAddress, ()> {
        let local_end = input.find('@').ok_or(())?;
        // Transform local part to lowercase, according to unicode
        let local = input[..local_end].to_lowercase();
        // Verify and normalize domain to lowercase ASCII, according to WHATWG
        let host = Host::parse(&input[local_end + 1..]).map_err(|_| ())?;
        if let Host::Domain(domain) = host {
            Ok(EmailAddress::from_parts(&local, &domain))
        } else {
            Err(())
        }
    }
}

impl AsRef<str> for EmailAddress {
    /// Return the serialization of this email address.
    fn as_ref(&self) -> &str {
        &self.serialization
    }
}

impl Serialize for EmailAddress {
    /// Serialize this email address as a string.
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
            where S: Serializer {
        self.as_str().serialize(serializer)
    }
}

impl EmailAddress {
    /// Create an email address from trusted local and domain parts.
    fn from_parts(local: &str, domain: &str) -> EmailAddress {
        EmailAddress {
            serialization: format!("{}@{}", local, domain),
            local_end: local.len(),
        }
    }

    /// Create an EmailAddress from trusted input.
    ///
    /// The input is the already serialized form, preferably extracted from an
    /// EmailAddress parsed earlier.
    pub fn from_trusted(input: &str) -> EmailAddress {
        EmailAddress {
            serialization: input.to_owned(),
            local_end: input.find('@').expect("no @ found in input"),
        }
    }

    /// Deserialize implementation for trusted input.
    ///
    /// Because this assumes input is valid, it must be explicitely selected using
    /// `#[serde(deserialize_with = "EmailAddress::deserialize_trusted")]`
    pub fn deserialize_trusted<'de, D>(deserializer: D) -> Result<EmailAddress, D::Error>
            where D: Deserializer<'de> {
        <&str>::deserialize(deserializer).map(|s| EmailAddress::from_trusted(s))
    }

    /// Return the serialization.
    pub fn as_str(&self) -> &str {
        &self.serialization
    }

    /// Return the normalized local part.
    pub fn local(&self) -> &str {
        &self.serialization[..self.local_end]
    }

    /// Return the ASCII normalized domain.
    pub fn domain(&self) -> &str {
        &self.serialization[self.local_end + 1..]
    }

    /// Return the normalized local and domain parts as a tuple.
    pub fn parts(&self) -> (&str, &str) {
        (self.local(), self.domain())
    }

    /// Normalize a Google email address.
    ///
    /// This method can also be used to normalize G Suite addresses.
    pub fn normalize_google(&self) -> EmailAddress {
        let (local, domain) = self.parts();

        // Normalize googlemail.com to gmail.com
        let domain = match domain {
            "googlemail.com" => "gmail.com",
            domain => domain,
        };

        // Trim plus addresses
        let local = match self.local().find('+') {
            Some(pos) => &local[..pos],
            None => local,
        };

        // Ignore dots
        let local = local.replace(".", "");

        EmailAddress::from_parts(&local, domain)
    }
}

/// Display the serialization of this email address.
impl Display for EmailAddress {
    fn fmt(&self, formatter: &mut Formatter) -> FmtResult {
        Display::fmt(&self.serialization, formatter)
    }
}

/// Debug the serialization of this email address.
impl Debug for EmailAddress {
    fn fmt(&self, formatter: &mut Formatter) -> FmtResult {
        Debug::fmt(&self.serialization, formatter)
    }
}

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

    #[test]
    fn test_normal() {
        fn parse(input: &str, output: &str) {
            assert_eq!(
                input.parse::<EmailAddress>().unwrap(),
                EmailAddress::from_trusted(output)
            )
        }
        parse("example.foo+bar@example.com",
              "example.foo+bar@example.com");
        parse("EXAMPLE.FOO+BAR@EXAMPLE.COM",
              "example.foo+bar@example.com");
        parse("BJÖRN@göteborg.test",
              "björn@xn--gteborg-90a.test");
        parse("İⅢ@İⅢ.example",
              "i̇ⅲ@xn--iiii-qwc.example");
    }

    #[test]
    fn test_google() {
        fn parse(input: &str, output: &str) {
            assert_eq!(
                input.parse::<EmailAddress>().unwrap().normalize_google(),
                EmailAddress::from_trusted(output)
            )
        }
        parse("example@gmail.com",
              "example@gmail.com");
        parse("example@googlemail.com",
              "example@gmail.com");
        parse("example.foo@gmail.com",
              "examplefoo@gmail.com");
        parse("example+bar@gmail.com",
              "example@gmail.com");
        parse("example.foo+bar@googlemail.com",
              "examplefoo@gmail.com");
        parse("EXAMPLE@GOOGLEMAIL.COM",
              "example@gmail.com");
        parse("EXAMPLE.FOO+BAR@GOOGLEMAIL.COM",
              "examplefoo@gmail.com");
    }
}
<|endoftext|>


<commit_before>#[macro_export]
macro_rules! char_class {
    ($c: expr, [$head:expr]) => ($c == $head);
    ($c: expr, [$head:expr $(, $cs:expr)+]) => ($c == $head || $crate::char_class!($c, [$($cs),*]));
}

#[macro_export]
macro_rules! alpha_char {
    ($c: expr) => {
        match $c {
            'a'..='z' => true,
            'A'..='Z' => true,
            '_' => true,
            '\u{00A0}'..='\u{00BF}' => true,
            '\u{00C0}'..='\u{00D6}' => true,
            '\u{00D8}'..='\u{00F6}' => true,
            '\u{00F8}'..='\u{00FF}' => true,
            '\u{0100}'..='\u{FFFF}' => true, /* skip some control
 characters but admit the remaining code points as alphabetic
 characters. */
            _ => false,
        }
    };
}

#[macro_export]
macro_rules! alpha_numeric_char {
    ($c: expr) => {
        $crate::alpha_char!($c) || $crate::decimal_digit_char!($c)
    };
}

#[macro_export]
macro_rules! backslash_char {
    ($c: expr) => {
        $c == '\\'
    };
}

#[macro_export]
macro_rules! back_quote_char {
    ($c: expr) => {
        $c == '`'
    };
}

#[macro_export]
macro_rules! octet_char {
    ($c: expr) => {
        ('\u{0000}'..='\u{00FF}').contains(&$c)
    };
}

#[macro_export]
macro_rules! capital_letter_char {
    ($c: expr) => {
        ('A'..='Z').contains(&$c)
    };
}

#[macro_export]
macro_rules! comment_1_char {
    ($c: expr) => {
        $c == '/'
    };
}

#[macro_export]
macro_rules! comment_2_char {
    ($c: expr) => {
        $c == '*'
    };
}

#[macro_export]
macro_rules! cut_char {
    ($c: expr) => {
        $c == '!'
    };
}

#[macro_export]
macro_rules! decimal_digit_char {
    ($c: expr) => {
        ('0'..='9').contains(&$c)
    };
}

#[macro_export]
macro_rules! decimal_point_char {
    ($c: expr) => {
        $c == '.'
    };
}

#[macro_export]
macro_rules! double_quote_char {
    ($c: expr) => {
        $c == '"'
    };
}

#[macro_export]
macro_rules! end_line_comment_char {
    ($c: expr) => {
        $c == '%'
    };
}

#[macro_export]
macro_rules! exponent_char {
    ($c: expr) => {
        $c == 'e' || $c == 'E'
    };
}

#[macro_export]
macro_rules! graphic_char {
    ($c: expr) => ($crate::char_class!($c, ['#', '$', '&', '*', '+', '-', '.', '/', ':',
                                    '<', '=', '>', '?', '@', '^', '~']))
}

#[macro_export]
macro_rules! graphic_token_char {
    ($c: expr) => {
        $crate::graphic_char!($c) || $crate::backslash_char!($c)
    };
}

#[macro_export]
macro_rules! hexadecimal_digit_char {
    ($c: expr) => {
        ('0'..='9').contains(&$c) || ('A'..='F').contains(&$c) || ('a'..='f').contains(&$c)
    };
}

#[macro_export]
macro_rules! layout_char {
    ($c: expr) => {
        $crate::char_class!($c, [' ', '\n', '\t', '\u{0B}', '\u{0C}'])
    };
}

#[macro_export]
macro_rules! meta_char {
    ($c: expr) => {
        $crate::char_class!($c, ['\\', '\'', '"', '`'])
    };
}

#[macro_export]
macro_rules! new_line_char {
    ($c: expr) => {
        $c == '\n'
    };
}

#[macro_export]
macro_rules! octal_digit_char {
    ($c: expr) => {
        ('0'..='7').contains(&$c)
    };
}

#[macro_export]
macro_rules! binary_digit_char {
    ($c: expr) => {
        $c >= '0' && $c <= '1'
    };
}

#[macro_export]
macro_rules! prolog_char {
    ($c: expr) => {
        $crate::graphic_char!($c)
            || $crate::alpha_numeric_char!($c)
            || $crate::solo_char!($c)
            || $crate::layout_char!($c)
            || $crate::meta_char!($c)
    };
}

#[macro_export]
macro_rules! semicolon_char {
    ($c: expr) => {
        $c == ';'
    };
}

#[macro_export]
macro_rules! sign_char {
    ($c: expr) => {
        $c == '-' || $c == '+'
    };
}

#[macro_export]
macro_rules! single_quote_char {
    ($c: expr) => {
        $c == '\''
    };
}

#[macro_export]
macro_rules! small_letter_char {
    ($c: expr) => {
        ('a'..='z').contains(&$c)
    };
}

#[macro_export]
macro_rules! solo_char {
    ($c: expr) => {
        $crate::char_class!($c, ['!', '(', ')', ',', ';', '[', ']', '{', '}', '|', '%'])
    };
}

#[macro_export]
macro_rules! space_char {
    ($c: expr) => {
        $c == ' '
    };
}

#[macro_export]
macro_rules! symbolic_control_char {
    ($c: expr) => {
        $crate::char_class!($c, ['a', 'b', 'f', 'n', 'r', 't', 'v', '0'])
    };
}

#[macro_export]
macro_rules! symbolic_hexadecimal_char {
    ($c: expr) => {
        $c == 'x'
    };
}

#[macro_export]
macro_rules! variable_indicator_char {
    ($c: expr) => {
        $c == '_'
    };
}
<commit_msg>use Rust's native UTF-8 functions (#1355)<commit_after>#[macro_export]
macro_rules! char_class {
    ($c: expr, [$head:expr]) => ($c == $head);
    ($c: expr, [$head:expr $(, $cs:expr)+]) => ($c == $head || $crate::char_class!($c, [$($cs),*]));
}

#[macro_export]
macro_rules! alpha_char {
    ($c: expr) => {
        $c.is_alphabetic() || $c == '_'
    };
}

#[macro_export]
macro_rules! alpha_numeric_char {
    ($c: expr) => {
        $crate::alpha_char!($c) || $crate::decimal_digit_char!($c)
    };
}

#[macro_export]
macro_rules! backslash_char {
    ($c: expr) => {
        $c == '\\'
    };
}

#[macro_export]
macro_rules! back_quote_char {
    ($c: expr) => {
        $c == '`'
    };
}

#[macro_export]
macro_rules! octet_char {
    ($c: expr) => {
        ('\u{0000}'..='\u{00FF}').contains(&$c)
    };
}

#[macro_export]
macro_rules! capital_letter_char {
    ($c: expr) => {
        $c.is_uppercase()
    };
}

#[macro_export]
macro_rules! comment_1_char {
    ($c: expr) => {
        $c == '/'
    };
}

#[macro_export]
macro_rules! comment_2_char {
    ($c: expr) => {
        $c == '*'
    };
}

#[macro_export]
macro_rules! cut_char {
    ($c: expr) => {
        $c == '!'
    };
}

#[macro_export]
macro_rules! decimal_digit_char {
    ($c: expr) => {
        ('0'..='9').contains(&$c)
    };
}

#[macro_export]
macro_rules! decimal_point_char {
    ($c: expr) => {
        $c == '.'
    };
}

#[macro_export]
macro_rules! double_quote_char {
    ($c: expr) => {
        $c == '"'
    };
}

#[macro_export]
macro_rules! end_line_comment_char {
    ($c: expr) => {
        $c == '%'
    };
}

#[macro_export]
macro_rules! exponent_char {
    ($c: expr) => {
        $c == 'e' || $c == 'E'
    };
}

#[macro_export]
macro_rules! graphic_char {
    ($c: expr) => ($crate::char_class!($c, ['#', '$', '&', '*', '+', '-', '.', '/', ':',
                                            '<', '=', '>', '?', '@', '^', '~']))
}

#[macro_export]
macro_rules! graphic_token_char {
    ($c: expr) => {
        $crate::graphic_char!($c) || $crate::backslash_char!($c)
    };
}

#[macro_export]
macro_rules! hexadecimal_digit_char {
    ($c: expr) => {
        ('0'..='9').contains(&$c) || ('A'..='F').contains(&$c) || ('a'..='f').contains(&$c)
    };
}

#[macro_export]
macro_rules! layout_char {
    ($c: expr) => {
        $crate::char_class!($c, [' ', '\n', '\t', '\u{0B}', '\u{0C}'])
    };
}

#[macro_export]
macro_rules! meta_char {
    ($c: expr) => {
        $crate::char_class!($c, ['\\', '\'', '"', '`'])
    };
}

#[macro_export]
macro_rules! new_line_char {
    ($c: expr) => {
        $c == '\n'
    };
}

#[macro_export]
macro_rules! octal_digit_char {
    ($c: expr) => {
        ('0'..='7').contains(&$c)
    };
}

#[macro_export]
macro_rules! binary_digit_char {
    ($c: expr) => {
        $c == '0' || $c == '1'
    };
}

#[macro_export]
macro_rules! prolog_char {
    ($c: expr) => {
        $crate::graphic_char!($c)
            || $crate::alpha_numeric_char!($c)
            || $crate::solo_char!($c)
            || $crate::layout_char!($c)
            || $crate::meta_char!($c)
    };
}

#[macro_export]
macro_rules! semicolon_char {
    ($c: expr) => {
        $c == ';'
    };
}

#[macro_export]
macro_rules! sign_char {
    ($c: expr) => {
        $c == '-' || $c == '+'
    };
}

#[macro_export]
macro_rules! single_quote_char {
    ($c: expr) => {
        $c == '\''
    };
}

#[macro_export]
macro_rules! small_letter_char {
    ($c: expr) => {
        $c.is_lowercase()
    };
}

#[macro_export]
macro_rules! solo_char {
    ($c: expr) => {
        $crate::char_class!($c, ['!', '(', ')', ',', ';', '[', ']', '{', '}', '|', '%'])
    };
}

#[macro_export]
macro_rules! space_char {
    ($c: expr) => {
        $c == ' '
    };
}

#[macro_export]
macro_rules! symbolic_control_char {
    ($c: expr) => {
        $crate::char_class!($c, ['a', 'b', 'f', 'n', 'r', 't', 'v', '0'])
    };
}

#[macro_export]
macro_rules! symbolic_hexadecimal_char {
    ($c: expr) => {
        $c == 'x'
    };
}

#[macro_export]
macro_rules! variable_indicator_char {
    ($c: expr) => {
        $c == '_'
    };
}
<|endoftext|>


<commit_before>use combine::{eof, value, satisfy_map, token, between, many, many1, try, Parser, Stream,
              ParseError};
use combine::char::{string, spaces};
use combine::primitives::Error;

use api::{Api, ParamType, ParamListEntry, Array};
// use errors::*;
use paramset::ParamSet;
use super::lexer::Tokens;

pub fn parse<I: Stream<Item = Tokens>, A: Api>
    (input: I,
     api: &A)
     -> ::std::result::Result<(Vec<()>, I), ParseError<I>> {
    // TODO remove all the error conversions once https://github.com/brson/error-chain/issues/134 is fixed
    let attribute_begin = token(Tokens::ATTRIBUTEBEGIN).and_then(|_| api.attribute_begin().map_err(|e| Error::Message(e.description().to_owned().into())));
    let attribute_end = token(Tokens::ATTRIBUTEEND).and_then(|_| api.attribute_end().map_err(|e| Error::Message(e.description().to_owned().into())));
    let world_begin = token(Tokens::WORLDBEGIN).and_then(|_| {
                                                             api.world_begin()
                                                   .map_err(|e| {
                                                                Error::Message(e.description()
                                                                                .to_owned()
                                                                                .into())
                                                            })
                                                         });
    let world_end = token(Tokens::WORLDEND).and_then(|_| {
                                                         api.world_end()
                                                 .map_err(|e| {
                                                              Error::Message(e.description()
                                                                                .to_owned()
                                                                                .into())
                                                          })
                                                     });
    let look_at =
        (token(Tokens::LOOKAT), num(), num(), num(), num(), num(), num(), num(), num(), num())
            .and_then(|(_, ex, ey, ez, lx, ly, lz, ux, uy, uz)| {
                          api.look_at(ex, ey, ez, lx, ly, lz, ux, uy, uz)
                              .map_err(|e| Error::Message(e.description().to_owned().into()))
                      });
    let camera =
        (token(Tokens::CAMERA), string_(), param_list()).and_then(|(_, name, mut params)| {
                                                                      api.camera(name, &mut params)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                                                                  });
    let film = (token(Tokens::FILM), string_(), param_list())
        .and_then(|(_, name, mut params)| {
                      api.film(name, &mut params)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                  });
    let integrator = (token(Tokens::INTEGRATOR), string_(), param_list())
        .and_then(|(_, name, mut params)| {
                      api.integrator(name, &mut params)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                  });
    let arealightsource = (token(Tokens::AREALIGHTSOURCE), string_(), param_list())
        .and_then(|(_, name, mut params)| {
                      api.arealightsource(name, &mut params)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                  });
    let lightsource = (token(Tokens::LIGHTSOURCE), string_(), param_list())
        .and_then(|(_, name, mut params)| {
                      api.lightsource(name, &mut params)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                  });
    let material = (token(Tokens::MATERIAL), string_(), param_list()).and_then(|(_, name, mut params)| {
                                                                              api.material(name,
                                                                                &mut params).map_err(|e| Error::Message(e.description().to_owned().into()))
                                                                          });
    let make_named_material = (token(Tokens::MAKENAMEDMATERIAL), string_(), param_list())
        .and_then(|(_, name, mut params)| {
                      api.make_named_material(name, &mut params)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                  });
    let sampler = (token(Tokens::SAMPLER), string_(), param_list()).and_then(|(_, name, mut params)| {
                                                                        api.sampler(name, &mut params).map_err(|e| Error::Message(e.description().to_owned().into()))
                                                                    });
    let shape = (token(Tokens::SHAPE), string_(), param_list()).and_then(|(_, name, mut params)| {
                                                                        api.shape(name, &mut params).map_err(|e| Error::Message(e.description().to_owned().into()))
                                                                    });
    let filter =
        (token(Tokens::PIXELFILTER), string_(), param_list())
            .and_then(|(_, name, mut params)| {
                          api.pixel_filter(name, &mut params)
                              .map_err(|e| Error::Message(e.description().to_owned().into()))
                      });
    let scale = (token(Tokens::SCALE), num(), num(), num()).and_then(|(_, sx, sy, sz)| {
                                                                         api.scale(sx, sy, sz)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                                                                     });
    let rotate =
        (token(Tokens::ROTATE), num(), num(), num(), num()).and_then(|(_, angle, dx, dy, dz)| {
                                                                    api.rotate(angle, dx, dy, dz).map_err(|e| Error::Message(e.description().to_owned().into()))
                                                                });
    let translate = (token(Tokens::TRANSLATE), num(), num(), num())
        .and_then(|(_, dx, dy, dz)| {
                      api.translate(dx, dy, dz)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                  });

    let parsers = many1::<Vec<_>, _>(choice!(try(attribute_begin),
                                             try(attribute_end),
                                             try(world_begin),
                                             try(world_end),
                                             try(look_at),
                                             try(camera),
                                             try(film),
                                             try(filter),
                                             try(integrator),
                                             try(arealightsource),
                                             try(lightsource),
                                             try(material),
                                             try(make_named_material),
                                             try(sampler),
                                             try(shape),
                                             try(scale),
                                             try(rotate),
                                             try(translate)));
    (parsers, eof()).map(|(res, _)| res).parse(input)
}

fn param_list<'a, I: Stream<Item = Tokens> + 'a>
    ()
    -> Box<Parser<Input = I, Output = ParamSet> + 'a>
{
    many(param_list_entry())
        .map(|x| {
                 let mut ps = ParamSet::default();
                 ps.init(x);
                 ps
             })
        .boxed()
}

fn param_type<'a, I: Stream<Item = char> + 'a>
    ()
    -> Box<Parser<Input = I, Output = ParamType> + 'a>
{
    choice!(try(string("integer").with(value(ParamType::Int))),
            try(string("bool").with(value(ParamType::Bool))),
            try(string("float").with(value(ParamType::Float))),
            try(string("point2").with(value(ParamType::Point2))),
            try(string("vector2").with(value(ParamType::Vector2))),
            try(string("point3").with(value(ParamType::Point3))),
            try(string("vector3").with(value(ParamType::Vector3))),
            try(string("point").with(value(ParamType::Point3))),
            try(string("vector").with(value(ParamType::Vector3))),
            try(string("normal").with(value(ParamType::Normal))),
            try(string("rgb").with(value(ParamType::Rgb))),
            try(string("xyz").with(value(ParamType::Xyz))),
            try(string("blackbody").with(value(ParamType::Blackbody))),
            try(string("spectrum").with(value(ParamType::Spectrum))),
            try(string("string").with(value(ParamType::String))),
            try(string("texture").with(value(ParamType::Texture))))
            .boxed()
}

fn param_list_entry_header<'a, I: Stream<Item = Tokens> + 'a>
    ()
    -> Box<Parser<Input = I, Output = (ParamType, String)> + 'a>
{
    string_()
        .and_then(|s| match param_type().skip(spaces()).parse(&s[..]) {
                      Ok((t, n)) => Ok((t, n.to_owned())),
                      Err(error) => {
                          Err(Error::Message(format!("Invalid param list entry: {}", error).into()))
                      }
                  })
        .boxed()
}

fn param_list_entry<'a, I: Stream<Item = Tokens> + 'a>
    ()
    -> Box<Parser<Input = I, Output = ParamListEntry> + 'a>
{
    (param_list_entry_header(), array())
        .map(|(header, array)| ParamListEntry::new(header.0, header.1, array))
        .boxed()
}

fn array<'a, I: Stream<Item = Tokens> + 'a>() -> Box<Parser<Input = I, Output = Array> + 'a> {
    choice!(try(string_array().map(Array::StrArray)),
            try(num_array().map(Array::NumArray)))
            .boxed()
}

fn string_array<'a, I: Stream<Item = Tokens> + 'a>
    ()
    -> Box<Parser<Input = I, Output = Vec<String>> + 'a>
{
    choice!(try(between(token(Tokens::LBRACK),
                        token(Tokens::RBRACK),
                        many1::<Vec<_>, _>(string_()))),
            try(string_().map(|x| vec![x])))
            .boxed()
}

fn num_array<'a, I: Stream<Item = Tokens> + 'a>
    ()
    -> Box<Parser<Input = I, Output = Vec<f32>> + 'a>
{
    choice!(try(between(token(Tokens::LBRACK),
                        token(Tokens::RBRACK),
                        many1::<Vec<_>, _>(num()))),
            try(num().map(|x| vec![x])))
            .boxed()
}

fn num<'a, I: Stream<Item = Tokens> + 'a>() -> Box<Parser<Input = I, Output = f32> + 'a> {
    satisfy_map(|t| match t {
                    Tokens::NUMBER(n) => Some(n),
                    _ => None,
                })
            .boxed()
}

fn string_<'a, I: Stream<Item = Tokens> + 'a>() -> Box<Parser<Input = I, Output = String> + 'a> {
    satisfy_map(|t| match t {
                    Tokens::STR(s) => Some(s),
                    _ => None,
                })
            .boxed()
}

// #[test]
// fn test_parse() {
//     let tokens = vec![Tokens::ATTRIBUTEBEGIN, Tokens::ATTRIBUTEEND];
//     let api = ::api::RealApi::default();
//     api.init().unwrap();
//     parse(&tokens[..], &api).unwrap();
// }

#[test]
fn test_array() {
    let p = vec![Tokens::LBRACK,
                 Tokens::NUMBER(50.0),
                 Tokens::NUMBER(12.0),
                 Tokens::RBRACK];
    let foo = vec![];

    assert_eq!(array().parse(&p[..]),
               Ok((Array::NumArray(vec![50.0, 12.0]), &foo[..])));
}

#[test]
fn test_num_array() {
    let p = vec![Tokens::LBRACK, Tokens::NUMBER(50.0), Tokens::RBRACK];
    let foo = vec![];

    assert_eq!(num_array().parse(&p[..]), Ok((vec![50.0], &foo[..])));
}

#[test]
fn test_param_list_entry() {
    let p = vec![Tokens::STR("float fov".to_owned()),
                 Tokens::LBRACK,
                 Tokens::NUMBER(50.0),
                 Tokens::RBRACK];

    param_list_entry().parse(&p[..]).unwrap();
}

#[test]
fn test_param_type() {
    let p = "float";
    assert_eq!(param_type().parse(&p[..]), Ok((ParamType::Float, "")));

    let q = "floatxxx";
    assert_eq!(param_type().parse(&q[..]), Ok((ParamType::Float, "xxx")));
}

#[test]
fn test_param_list_entry_header() {
    let p = vec![Tokens::STR("float fov".to_owned())];
    let foo = vec![];

    assert_eq!(param_list_entry_header().parse(&p[..]),
               Ok(((ParamType::Float, "fov".to_owned()), &foo[..])));
}
<commit_msg>"color" is an alias for "rgb"<commit_after>use combine::{eof, value, satisfy_map, token, between, many, many1, try, Parser, Stream,
              ParseError};
use combine::char::{string, spaces};
use combine::primitives::Error;

use api::{Api, ParamType, ParamListEntry, Array};
// use errors::*;
use paramset::ParamSet;
use super::lexer::Tokens;

pub fn parse<I: Stream<Item = Tokens>, A: Api>
    (input: I,
     api: &A)
     -> ::std::result::Result<(Vec<()>, I), ParseError<I>> {
    // TODO remove all the error conversions once https://github.com/brson/error-chain/issues/134 is fixed
    let attribute_begin = token(Tokens::ATTRIBUTEBEGIN).and_then(|_| api.attribute_begin().map_err(|e| Error::Message(e.description().to_owned().into())));
    let attribute_end = token(Tokens::ATTRIBUTEEND).and_then(|_| api.attribute_end().map_err(|e| Error::Message(e.description().to_owned().into())));
    let world_begin = token(Tokens::WORLDBEGIN).and_then(|_| {
                                                             api.world_begin()
                                                   .map_err(|e| {
                                                                Error::Message(e.description()
                                                                                .to_owned()
                                                                                .into())
                                                            })
                                                         });
    let world_end = token(Tokens::WORLDEND).and_then(|_| {
                                                         api.world_end()
                                                 .map_err(|e| {
                                                              Error::Message(e.description()
                                                                                .to_owned()
                                                                                .into())
                                                          })
                                                     });
    let look_at =
        (token(Tokens::LOOKAT), num(), num(), num(), num(), num(), num(), num(), num(), num())
            .and_then(|(_, ex, ey, ez, lx, ly, lz, ux, uy, uz)| {
                          api.look_at(ex, ey, ez, lx, ly, lz, ux, uy, uz)
                              .map_err(|e| Error::Message(e.description().to_owned().into()))
                      });
    let camera =
        (token(Tokens::CAMERA), string_(), param_list()).and_then(|(_, name, mut params)| {
                                                                      api.camera(name, &mut params)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                                                                  });
    let film = (token(Tokens::FILM), string_(), param_list())
        .and_then(|(_, name, mut params)| {
                      api.film(name, &mut params)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                  });
    let integrator = (token(Tokens::INTEGRATOR), string_(), param_list())
        .and_then(|(_, name, mut params)| {
                      api.integrator(name, &mut params)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                  });
    let arealightsource = (token(Tokens::AREALIGHTSOURCE), string_(), param_list())
        .and_then(|(_, name, mut params)| {
                      api.arealightsource(name, &mut params)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                  });
    let lightsource = (token(Tokens::LIGHTSOURCE), string_(), param_list())
        .and_then(|(_, name, mut params)| {
                      api.lightsource(name, &mut params)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                  });
    let material = (token(Tokens::MATERIAL), string_(), param_list()).and_then(|(_, name, mut params)| {
                                                                              api.material(name,
                                                                                &mut params).map_err(|e| Error::Message(e.description().to_owned().into()))
                                                                          });
    let make_named_material = (token(Tokens::MAKENAMEDMATERIAL), string_(), param_list())
        .and_then(|(_, name, mut params)| {
                      api.make_named_material(name, &mut params)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                  });
    let sampler = (token(Tokens::SAMPLER), string_(), param_list()).and_then(|(_, name, mut params)| {
                                                                        api.sampler(name, &mut params).map_err(|e| Error::Message(e.description().to_owned().into()))
                                                                    });
    let shape = (token(Tokens::SHAPE), string_(), param_list()).and_then(|(_, name, mut params)| {
                                                                        api.shape(name, &mut params).map_err(|e| Error::Message(e.description().to_owned().into()))
                                                                    });
    let filter =
        (token(Tokens::PIXELFILTER), string_(), param_list())
            .and_then(|(_, name, mut params)| {
                          api.pixel_filter(name, &mut params)
                              .map_err(|e| Error::Message(e.description().to_owned().into()))
                      });
    let scale = (token(Tokens::SCALE), num(), num(), num()).and_then(|(_, sx, sy, sz)| {
                                                                         api.scale(sx, sy, sz)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                                                                     });
    let rotate =
        (token(Tokens::ROTATE), num(), num(), num(), num()).and_then(|(_, angle, dx, dy, dz)| {
                                                                    api.rotate(angle, dx, dy, dz).map_err(|e| Error::Message(e.description().to_owned().into()))
                                                                });
    let translate = (token(Tokens::TRANSLATE), num(), num(), num())
        .and_then(|(_, dx, dy, dz)| {
                      api.translate(dx, dy, dz)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                  });

    let parsers = many1::<Vec<_>, _>(choice!(try(attribute_begin),
                                             try(attribute_end),
                                             try(world_begin),
                                             try(world_end),
                                             try(look_at),
                                             try(camera),
                                             try(film),
                                             try(filter),
                                             try(integrator),
                                             try(arealightsource),
                                             try(lightsource),
                                             try(material),
                                             try(make_named_material),
                                             try(sampler),
                                             try(shape),
                                             try(scale),
                                             try(rotate),
                                             try(translate)));
    (parsers, eof()).map(|(res, _)| res).parse(input)
}

fn param_list<'a, I: Stream<Item = Tokens> + 'a>
    ()
    -> Box<Parser<Input = I, Output = ParamSet> + 'a>
{
    many(param_list_entry())
        .map(|x| {
                 let mut ps = ParamSet::default();
                 ps.init(x);
                 ps
             })
        .boxed()
}

fn param_type<'a, I: Stream<Item = char> + 'a>
    ()
    -> Box<Parser<Input = I, Output = ParamType> + 'a>
{
    choice!(try(string("integer").with(value(ParamType::Int))),
            try(string("bool").with(value(ParamType::Bool))),
            try(string("float").with(value(ParamType::Float))),
            try(string("point2").with(value(ParamType::Point2))),
            try(string("vector2").with(value(ParamType::Vector2))),
            try(string("point3").with(value(ParamType::Point3))),
            try(string("vector3").with(value(ParamType::Vector3))),
            try(string("point").with(value(ParamType::Point3))),
            try(string("vector").with(value(ParamType::Vector3))),
            try(string("normal").with(value(ParamType::Normal))),
            try(string("color").with(value(ParamType::Rgb))),
            try(string("rgb").with(value(ParamType::Rgb))),
            try(string("xyz").with(value(ParamType::Xyz))),
            try(string("blackbody").with(value(ParamType::Blackbody))),
            try(string("spectrum").with(value(ParamType::Spectrum))),
            try(string("string").with(value(ParamType::String))),
            try(string("texture").with(value(ParamType::Texture))))
            .boxed()
}

fn param_list_entry_header<'a, I: Stream<Item = Tokens> + 'a>
    ()
    -> Box<Parser<Input = I, Output = (ParamType, String)> + 'a>
{
    string_()
        .and_then(|s| match param_type().skip(spaces()).parse(&s[..]) {
                      Ok((t, n)) => Ok((t, n.to_owned())),
                      Err(error) => {
                          Err(Error::Message(format!("Invalid param list entry: {}", error).into()))
                      }
                  })
        .boxed()
}

fn param_list_entry<'a, I: Stream<Item = Tokens> + 'a>
    ()
    -> Box<Parser<Input = I, Output = ParamListEntry> + 'a>
{
    (param_list_entry_header(), array())
        .map(|(header, array)| ParamListEntry::new(header.0, header.1, array))
        .boxed()
}

fn array<'a, I: Stream<Item = Tokens> + 'a>() -> Box<Parser<Input = I, Output = Array> + 'a> {
    choice!(try(string_array().map(Array::StrArray)),
            try(num_array().map(Array::NumArray)))
            .boxed()
}

fn string_array<'a, I: Stream<Item = Tokens> + 'a>
    ()
    -> Box<Parser<Input = I, Output = Vec<String>> + 'a>
{
    choice!(try(between(token(Tokens::LBRACK),
                        token(Tokens::RBRACK),
                        many1::<Vec<_>, _>(string_()))),
            try(string_().map(|x| vec![x])))
            .boxed()
}

fn num_array<'a, I: Stream<Item = Tokens> + 'a>
    ()
    -> Box<Parser<Input = I, Output = Vec<f32>> + 'a>
{
    choice!(try(between(token(Tokens::LBRACK),
                        token(Tokens::RBRACK),
                        many1::<Vec<_>, _>(num()))),
            try(num().map(|x| vec![x])))
            .boxed()
}

fn num<'a, I: Stream<Item = Tokens> + 'a>() -> Box<Parser<Input = I, Output = f32> + 'a> {
    satisfy_map(|t| match t {
                    Tokens::NUMBER(n) => Some(n),
                    _ => None,
                })
            .boxed()
}

fn string_<'a, I: Stream<Item = Tokens> + 'a>() -> Box<Parser<Input = I, Output = String> + 'a> {
    satisfy_map(|t| match t {
                    Tokens::STR(s) => Some(s),
                    _ => None,
                })
            .boxed()
}

// #[test]
// fn test_parse() {
//     let tokens = vec![Tokens::ATTRIBUTEBEGIN, Tokens::ATTRIBUTEEND];
//     let api = ::api::RealApi::default();
//     api.init().unwrap();
//     parse(&tokens[..], &api).unwrap();
// }

#[test]
fn test_array() {
    let p = vec![Tokens::LBRACK,
                 Tokens::NUMBER(50.0),
                 Tokens::NUMBER(12.0),
                 Tokens::RBRACK];
    let foo = vec![];

    assert_eq!(array().parse(&p[..]),
               Ok((Array::NumArray(vec![50.0, 12.0]), &foo[..])));
}

#[test]
fn test_num_array() {
    let p = vec![Tokens::LBRACK, Tokens::NUMBER(50.0), Tokens::RBRACK];
    let foo = vec![];

    assert_eq!(num_array().parse(&p[..]), Ok((vec![50.0], &foo[..])));
}

#[test]
fn test_param_list_entry() {
    let p = vec![Tokens::STR("float fov".to_owned()),
                 Tokens::LBRACK,
                 Tokens::NUMBER(50.0),
                 Tokens::RBRACK];

    param_list_entry().parse(&p[..]).unwrap();
}

#[test]
fn test_param_type() {
    let p = "float";
    assert_eq!(param_type().parse(&p[..]), Ok((ParamType::Float, "")));

    let q = "floatxxx";
    assert_eq!(param_type().parse(&q[..]), Ok((ParamType::Float, "xxx")));
}

#[test]
fn test_param_list_entry_header() {
    let p = vec![Tokens::STR("float fov".to_owned())];
    let foo = vec![];

    assert_eq!(param_list_entry_header().parse(&p[..]),
               Ok(((ParamType::Float, "fov".to_owned()), &foo[..])));
}
<|endoftext|>


<commit_before>use time;
use std::io::timer::sleep;

use GameWindow;
use keyboard;
use mouse;
use event;

use std::cmp;

/// Render argument.
#[deriving(Clone)]
pub struct RenderArgs {
    /// Extrapolated time in seconds, used to do smooth animation.
    pub ext_dt: f64,
    /// The width of rendered area.
    pub width: u32,
    /// The height of rendered area.
    pub height: u32,
}

/// Update argument.
#[deriving(Clone)]
pub struct UpdateArgs {
    /// Delta time in seconds.
    pub dt: f64,
}

/// Key press arguments.
#[deriving(Clone)]
pub struct KeyPressArgs {
    /// Keyboard key.
    pub key: keyboard::Key,
}

/// Key release arguments.
#[deriving(Clone)]
pub struct KeyReleaseArgs {
    /// Keyboard key.
    pub key: keyboard::Key,
}

/// Mouse press arguments.
#[deriving(Clone)]
pub struct MousePressArgs {
    /// Mouse button.
    pub button: mouse::Button,
}

/// Mouse release arguments.
#[deriving(Clone)]
pub struct MouseReleaseArgs {
    /// Mouse button.
    pub button: mouse::Button,
}

/// Mouse move arguments.
#[deriving(Clone)]
pub struct MouseMoveArgs {
    /// x.
    pub x: f64,
    /// y.
    pub y: f64,
}

/// Mouse relative move arguments.
#[deriving(Clone)]
pub struct MouseRelativeMoveArgs {
    /// Delta x.
    pub dx: f64,
    /// Delta y.
    pub dy: f64,
}

/// Mouse scroll arguments.
#[deriving(Clone)]
pub struct MouseScrollArgs {
    /// x.
    pub x: f64,
    /// y.
    pub y: f64,
}

/// Contains the different game events.
#[deriving(Clone)]
pub enum GameEvent {
    /// Render graphics.
    Render(RenderArgs),
    /// Update physical state of the game.
    Update(UpdateArgs),
    /// Pressed a keyboard key.
    KeyPress(KeyPressArgs),
    /// Released a keyboard key.
    KeyRelease(KeyReleaseArgs),
    /// Pressed a mouse button.
    MousePress(MousePressArgs),
    /// Released a mouse button.
    MouseRelease(MouseReleaseArgs),
    /// Moved mouse cursor.
    MouseMove(MouseMoveArgs),
    /// Moved mouse relative, not bounded by cursor.
    MouseRelativeMove(MouseRelativeMoveArgs),
    /// Scrolled mouse.
    MouseScroll(MouseScrollArgs)
}

#[deriving(Show)]
enum GameIteratorState {
    RenderState,
    SwapBuffersState,
    UpdateLoopState,
    HandleEventsState,
    MouseRelativeMoveState(f64, f64),
    UpdateState,
}

/// Settings for the game loop behavior.
#[deriving(Clone)]
pub struct GameIteratorSettings {
    /// The number of updates per second (UPS).
    pub updates_per_second: u64,
    /// The maximum number of frames per second (FPS target).
    pub max_frames_per_second: u64,
}

/// A game loop iterator.
///
/// Example:
///
/// ```Rust
/// let game_iter_settings = GameIteratorSettings {
///     updates_per_second: 120,
///     max_frames_per_second: 60,
/// };
/// let ref mut gl = Gl::new();
/// for e in GameIterator::new(&mut window, &game_iter_settings) {
///     match e {
///         Render(args) => {
///             // Set the viewport in window to render graphics.
///             gl.viewport(0, 0, args.width as i32, args.height as i32);
///             // Create graphics context with absolute coordinates.
///             let c = Context::abs(args.width as f64, args.height as f64);
///             // Do rendering here.
///         },
///     }
/// }
/// ```
pub struct GameIterator<'a, W> {
    /// The game window used by iterator.
    pub game_window: &'a mut W,
    state: GameIteratorState,
    last_update: u64,
    last_frame: u64,
    dt_update_in_ns: u64,
    dt_frame_in_ns: u64,
    dt: f64,
}

static billion: u64 = 1_000_000_000;

impl<'a, W: GameWindow> GameIterator<'a, W> {
    /// Creates a new game iterator.
    pub fn new(
        game_window: &'a mut W,
        settings: &GameIteratorSettings
    ) -> GameIterator<'a, W> {
        let updates_per_second: u64 = settings.updates_per_second;
        let max_frames_per_second: u64 = settings.max_frames_per_second;

        let start = time::precise_time_ns();
        GameIterator {
            game_window: game_window,
            state: RenderState,
            last_update: start,
            last_frame: start,
            dt_update_in_ns: billion / updates_per_second,
            dt_frame_in_ns: billion / max_frames_per_second,
            dt: 1.0 / updates_per_second as f64,
        }
    }
}

impl<'a, W: GameWindow>
Iterator<GameEvent>
for GameIterator<'a, W> {
    /// Returns the next game event.
    fn next(&mut self) -> Option<GameEvent> {
        loop {
            match self.state {
                RenderState => {
                    if self.game_window.should_close() { return None; }

                    let start_render = time::precise_time_ns();
                    self.last_frame = start_render;

                    let (w, h) = self.game_window.get_size();
                    if w != 0 && h != 0 {
                        // Swap buffers next time.
                        self.state = SwapBuffersState;
                        return Some(Render(RenderArgs {
                                // Extrapolate time forward to allow smooth motion.
                                ext_dt: (start_render - self.last_update) as f64 / billion as f64,
                                width: w,
                                height: h,
                            }
                        ));
                    }

                    self.state = UpdateLoopState;
                },
                SwapBuffersState => {
                    self.game_window.swap_buffers();
                    self.state = UpdateLoopState;
                },
                UpdateLoopState => {
                    let current_time = time::precise_time_ns();
                    let next_frame = self.last_frame + self.dt_frame_in_ns;
                    let next_update = self.last_update + self.dt_update_in_ns;
                    let next_event = cmp::min(next_frame, next_update);
                    if next_event > current_time {
                        sleep( (next_event - current_time) / 1_000_000 );
                    } else if next_event == next_frame {
                        self.state = RenderState;
                    } else {
                        self.state = HandleEventsState;
                    }
                },
                HandleEventsState => {
                    // Handle all events before updating.
                    return match self.game_window.poll_event() {
                        event::KeyPressed(key) => {
                            Some(KeyPress(KeyPressArgs {
                                key: key,
                            }))
                        },
                        event::KeyReleased(key) => {
                            Some(KeyRelease(KeyReleaseArgs {
                                key: key,
                            }))
                        },
                        event::MouseButtonPressed(mouse_button) => {
                            Some(MousePress(MousePressArgs {
                                button: mouse_button,
                            }))
                        },
                        event::MouseButtonReleased(mouse_button) => {
                            Some(MouseRelease(MouseReleaseArgs {
                                button: mouse_button,
                            }))
                        },
                        event::MouseMoved(x, y, relative_move) => {
                            match relative_move {
                                Some((dx, dy)) =>
                                    self.state = MouseRelativeMoveState(dx, dy),
                                None => {},
                            };
                            Some(MouseMove(MouseMoveArgs {
                                x: x,
                                y: y,
                            }))
                        },
                        event::MouseScrolled(x, y) => {
                            Some(MouseScroll(MouseScrollArgs {
                                x: x,
                                y: y
                            }))
                        },
                        event::NoEvent => {
                            self.state = UpdateState;
                            continue;
                        },
                    }
                },
                MouseRelativeMoveState(dx, dy) => {
                    self.state = HandleEventsState;
                    return Some(MouseRelativeMove(MouseRelativeMoveArgs {
                        dx: dx,
                        dy: dy,
                    }));
                },
                UpdateState => {
                    self.state = UpdateLoopState;
                    self.last_update += self.dt_update_in_ns;
                    return Some(Update(UpdateArgs{
                        dt: self.dt,
                    }));
                },
            };
        }
    }
}
<commit_msg>Add a comment to the explicit continue in NoEvent<commit_after>use time;
use std::io::timer::sleep;

use GameWindow;
use keyboard;
use mouse;
use event;

use std::cmp;

/// Render argument.
#[deriving(Clone)]
pub struct RenderArgs {
    /// Extrapolated time in seconds, used to do smooth animation.
    pub ext_dt: f64,
    /// The width of rendered area.
    pub width: u32,
    /// The height of rendered area.
    pub height: u32,
}

/// Update argument.
#[deriving(Clone)]
pub struct UpdateArgs {
    /// Delta time in seconds.
    pub dt: f64,
}

/// Key press arguments.
#[deriving(Clone)]
pub struct KeyPressArgs {
    /// Keyboard key.
    pub key: keyboard::Key,
}

/// Key release arguments.
#[deriving(Clone)]
pub struct KeyReleaseArgs {
    /// Keyboard key.
    pub key: keyboard::Key,
}

/// Mouse press arguments.
#[deriving(Clone)]
pub struct MousePressArgs {
    /// Mouse button.
    pub button: mouse::Button,
}

/// Mouse release arguments.
#[deriving(Clone)]
pub struct MouseReleaseArgs {
    /// Mouse button.
    pub button: mouse::Button,
}

/// Mouse move arguments.
#[deriving(Clone)]
pub struct MouseMoveArgs {
    /// x.
    pub x: f64,
    /// y.
    pub y: f64,
}

/// Mouse relative move arguments.
#[deriving(Clone)]
pub struct MouseRelativeMoveArgs {
    /// Delta x.
    pub dx: f64,
    /// Delta y.
    pub dy: f64,
}

/// Mouse scroll arguments.
#[deriving(Clone)]
pub struct MouseScrollArgs {
    /// x.
    pub x: f64,
    /// y.
    pub y: f64,
}

/// Contains the different game events.
#[deriving(Clone)]
pub enum GameEvent {
    /// Render graphics.
    Render(RenderArgs),
    /// Update physical state of the game.
    Update(UpdateArgs),
    /// Pressed a keyboard key.
    KeyPress(KeyPressArgs),
    /// Released a keyboard key.
    KeyRelease(KeyReleaseArgs),
    /// Pressed a mouse button.
    MousePress(MousePressArgs),
    /// Released a mouse button.
    MouseRelease(MouseReleaseArgs),
    /// Moved mouse cursor.
    MouseMove(MouseMoveArgs),
    /// Moved mouse relative, not bounded by cursor.
    MouseRelativeMove(MouseRelativeMoveArgs),
    /// Scrolled mouse.
    MouseScroll(MouseScrollArgs)
}

#[deriving(Show)]
enum GameIteratorState {
    RenderState,
    SwapBuffersState,
    UpdateLoopState,
    HandleEventsState,
    MouseRelativeMoveState(f64, f64),
    UpdateState,
}

/// Settings for the game loop behavior.
#[deriving(Clone)]
pub struct GameIteratorSettings {
    /// The number of updates per second (UPS).
    pub updates_per_second: u64,
    /// The maximum number of frames per second (FPS target).
    pub max_frames_per_second: u64,
}

/// A game loop iterator.
///
/// Example:
///
/// ```Rust
/// let game_iter_settings = GameIteratorSettings {
///     updates_per_second: 120,
///     max_frames_per_second: 60,
/// };
/// let ref mut gl = Gl::new();
/// for e in GameIterator::new(&mut window, &game_iter_settings) {
///     match e {
///         Render(args) => {
///             // Set the viewport in window to render graphics.
///             gl.viewport(0, 0, args.width as i32, args.height as i32);
///             // Create graphics context with absolute coordinates.
///             let c = Context::abs(args.width as f64, args.height as f64);
///             // Do rendering here.
///         },
///     }
/// }
/// ```
pub struct GameIterator<'a, W> {
    /// The game window used by iterator.
    pub game_window: &'a mut W,
    state: GameIteratorState,
    last_update: u64,
    last_frame: u64,
    dt_update_in_ns: u64,
    dt_frame_in_ns: u64,
    dt: f64,
}

static billion: u64 = 1_000_000_000;

impl<'a, W: GameWindow> GameIterator<'a, W> {
    /// Creates a new game iterator.
    pub fn new(
        game_window: &'a mut W,
        settings: &GameIteratorSettings
    ) -> GameIterator<'a, W> {
        let updates_per_second: u64 = settings.updates_per_second;
        let max_frames_per_second: u64 = settings.max_frames_per_second;

        let start = time::precise_time_ns();
        GameIterator {
            game_window: game_window,
            state: RenderState,
            last_update: start,
            last_frame: start,
            dt_update_in_ns: billion / updates_per_second,
            dt_frame_in_ns: billion / max_frames_per_second,
            dt: 1.0 / updates_per_second as f64,
        }
    }
}

impl<'a, W: GameWindow>
Iterator<GameEvent>
for GameIterator<'a, W> {
    /// Returns the next game event.
    fn next(&mut self) -> Option<GameEvent> {
        loop {
            match self.state {
                RenderState => {
                    if self.game_window.should_close() { return None; }

                    let start_render = time::precise_time_ns();
                    self.last_frame = start_render;

                    let (w, h) = self.game_window.get_size();
                    if w != 0 && h != 0 {
                        // Swap buffers next time.
                        self.state = SwapBuffersState;
                        return Some(Render(RenderArgs {
                                // Extrapolate time forward to allow smooth motion.
                                ext_dt: (start_render - self.last_update) as f64 / billion as f64,
                                width: w,
                                height: h,
                            }
                        ));
                    }

                    self.state = UpdateLoopState;
                },
                SwapBuffersState => {
                    self.game_window.swap_buffers();
                    self.state = UpdateLoopState;
                },
                UpdateLoopState => {
                    let current_time = time::precise_time_ns();
                    let next_frame = self.last_frame + self.dt_frame_in_ns;
                    let next_update = self.last_update + self.dt_update_in_ns;
                    let next_event = cmp::min(next_frame, next_update);
                    if next_event > current_time {
                        sleep( (next_event - current_time) / 1_000_000 );
                    } else if next_event == next_frame {
                        self.state = RenderState;
                    } else {
                        self.state = HandleEventsState;
                    }
                },
                HandleEventsState => {
                    // Handle all events before updating.
                    return match self.game_window.poll_event() {
                        event::KeyPressed(key) => {
                            Some(KeyPress(KeyPressArgs {
                                key: key,
                            }))
                        },
                        event::KeyReleased(key) => {
                            Some(KeyRelease(KeyReleaseArgs {
                                key: key,
                            }))
                        },
                        event::MouseButtonPressed(mouse_button) => {
                            Some(MousePress(MousePressArgs {
                                button: mouse_button,
                            }))
                        },
                        event::MouseButtonReleased(mouse_button) => {
                            Some(MouseRelease(MouseReleaseArgs {
                                button: mouse_button,
                            }))
                        },
                        event::MouseMoved(x, y, relative_move) => {
                            match relative_move {
                                Some((dx, dy)) =>
                                    self.state = MouseRelativeMoveState(dx, dy),
                                None => {},
                            };
                            Some(MouseMove(MouseMoveArgs {
                                x: x,
                                y: y,
                            }))
                        },
                        event::MouseScrolled(x, y) => {
                            Some(MouseScroll(MouseScrollArgs {
                                x: x,
                                y: y
                            }))
                        },
                        event::NoEvent => {
                            self.state = UpdateState;
                            // Explicitly continue because otherwise the result
                            // of this match is immediately returned.
                            continue;
                        },
                    }
                },
                MouseRelativeMoveState(dx, dy) => {
                    self.state = HandleEventsState;
                    return Some(MouseRelativeMove(MouseRelativeMoveArgs {
                        dx: dx,
                        dy: dy,
                    }));
                },
                UpdateState => {
                    self.state = UpdateLoopState;
                    self.last_update += self.dt_update_in_ns;
                    return Some(Update(UpdateArgs{
                        dt: self.dt,
                    }));
                },
            };
        }
    }
}
<|endoftext|>


<commit_before>use gameboy::{MAX_CPU_CYCLES, Interconnect, Irq, Interrupt};

pub struct Timer {
    div: u8,
    tima: u8,
    tma: u8,
    tac: u8,
    cycles: usize,
}

impl Timer {
    pub fn new() -> Timer {
        Timer {
            div: 0x00,
            tima: 0x00,
            tma: 0x00,
            tac: 0x00,
            cycles: MAX_CPU_CYCLES / 0x1000,
        }
    }

    pub fn reset(&mut self) {
        *self = Timer::new();
    }

    pub fn step(&mut self, irq: &mut Irq, cycles: usize) -> Result<(), String> {
        // DIV register increments regardless
        self.inc_div_register(cycles);

        if !self.enabled() {
            return Ok(());
        }

        self.inc_tima_register(irq, cycles);

        Ok(())
    }

    pub fn read_u8(&self, addr: u16) -> u8 {
        match addr {
            0x04 => self.div,
            0x05 => self.tima,
            0x06 => self.tma,
            0x07 => self.tac,
            _ => panic!("read timer memory that is unmapped"),
        }
    }

    pub fn write_u8(&mut self, addr: u16, val: u8) {
        match addr {
            0x04 => self.div = 0,
            0x05 => self.tima = val,
            0x06 => self.tma = val,
            0x07 => self.tac = val,
            _ => panic!("read timer memory that is unmapped"),
        }
    }

    fn enabled(&self) -> bool {
        self.tac & 0x04 == 0x04
    }

    fn inc_div_register(&mut self, cycles: usize) {
        self.div += cycles as u8;
        if self.div >= 0xFF {
            self.div = 0x00;
        }
    }

    fn inc_tima_register(&mut self, irq: &mut Irq, cycles: usize) {
        if self.enabled() {
            self.cycles -= cycles;
            if self.cycles < 0x00 {
                self.set_timer_frequency();
                if self.tima == 0xFF {
                    self.tima = self.tma; // set the TIMA register to be whatever is in the modulo TMA register
                    irq.request(Interrupt::Timer); // it overflowed, request a timer interrupt
                }
                self.tima.wrapping_add(0x01);
            }
        }
    }

    fn set_timer_frequency(&mut self) {
        let speed = self.tac & 0x03;
        self.cycles = match speed {
            0x00 => MAX_CPU_CYCLES / 0x1000,
            0x01 => MAX_CPU_CYCLES / 0x40000,
            0x02 => MAX_CPU_CYCLES / 0x10000,
            0x03 => MAX_CPU_CYCLES / 0x4000,
            _ => 0,
        };
    }
}
<commit_msg>Slight timer fixups<commit_after>use gameboy::{MAX_CPU_CYCLES, Interconnect, Irq, Interrupt};

pub struct Timer {
    div: usize,
    tima: u8,
    tma: u8,
    tac: u8,
    cycles: usize,
}

impl Timer {
    pub fn new() -> Timer {
        Timer {
            div: 0x00,
            tima: 0x00,
            tma: 0x00,
            tac: 0x00,
            cycles: MAX_CPU_CYCLES / 0x1000,
        }
    }

    pub fn reset(&mut self) {
        *self = Timer::new();
    }

    pub fn step(&mut self, irq: &mut Irq, cycles: usize) -> Result<(), String> {
        // DIV register increments regardless
        self.inc_div_register(cycles);

        if !self.enabled() {
            return Ok(());
        }

        self.inc_tima_register(irq, cycles);

        Ok(())
    }

    pub fn read_u8(&self, addr: u16) -> u8 {
        match addr {
            0x04 => self.div as u8,
            0x05 => self.tima,
            0x06 => self.tma,
            0x07 => self.tac,
            _ => panic!("read timer memory that is unmapped"),
        }
    }

    pub fn write_u8(&mut self, addr: u16, val: u8) {
        match addr {
            0x04 => self.div = 0,
            0x05 => self.tima = val,
            0x06 => self.tma = val,
            0x07 => self.tac = val,
            _ => panic!("read timer memory that is unmapped"),
        }
    }

    fn enabled(&self) -> bool {
        self.tac & 0x04 == 0x04
    }

    fn inc_div_register(&mut self, cycles: usize) {
        self.div += cycles;
        if self.div >= 0xFF {
            self.div = 0x00;
        }
    }

    fn inc_tima_register(&mut self, irq: &mut Irq, cycles: usize) {
        if self.enabled() {
            if self.cycles < cycles {
                self.set_timer_frequency();
                if self.tima == 0xFF {
                    self.tima = self.tma; // set the TIMA register to be whatever is in the modulo TMA register
                    irq.request(Interrupt::Timer); // it overflowed, request a timer interrupt
                }
                self.tima.wrapping_add(0x01);
            }
            self.cycles = self.cycles.wrapping_sub(cycles);
        }
    }

    fn set_timer_frequency(&mut self) {
        let speed = self.tac & 0x03;
        self.cycles = match speed {
            0x00 => MAX_CPU_CYCLES / 0x1000,
            0x01 => MAX_CPU_CYCLES / 0x40000,
            0x02 => MAX_CPU_CYCLES / 0x10000,
            0x03 => MAX_CPU_CYCLES / 0x4000,
            _ => 0,
        };
    }
}
<|endoftext|>