<commit_before>use token::{Token, Lexeme};
use tokenizer::Tokenizer;
use ast::expression::Expression;
use ast::root::Root;
use ast::node::Node;
use sass::rule::SassRule;
use sass::variable::SassVariable;
use sass::comment::SassComment;
use error::{Result, SassError, ErrorKind};

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

impl<'a> Iterator for Parser<'a> {
    type Item = Result<Root>;

    fn next(&mut self) -> Option<Result<Root>> {
        let mut current_sass_rule = SassRule::new();
        let mut ambiguous_holding_pen = vec![];

        while let Some(Ok(lexeme)) = self.tokenizer.next() {
            match lexeme.token {
                Token::String(ref s) if s.starts_with("$") => {
                    let variable_name = lexeme.clone();

                    if let Err(e) = Parser::expect_token(
                        Token::Colon,
                        self.tokenizer.next()
                    ) { return Some(Err(e)) };

                    let variable_value = match Expression::parse(&mut self.tokenizer) {
                        Ok(e) => e,
                        Err(e) => return Some(Err(e)),
                    };
                    return Some(Ok(Root::Variable(
                        SassVariable {
                            name: variable_name,
                            value: variable_value
                        }
                    )))
                },
                Token::LeftCurlyBrace => {
                    current_sass_rule.selectors
                                     .extend_from_slice(&ambiguous_holding_pen);
                    current_sass_rule.children = match self.parse_body() {
                        Ok(body) => body,
                        Err(e) => return Some(Err(e)),
                    };
                    return Some(Ok(Root::Rule(current_sass_rule)))
                },
                Token::Comma => {
                    current_sass_rule.selectors.extend_from_slice(&ambiguous_holding_pen);
                    ambiguous_holding_pen = vec![];
                },
                Token::Comment(_) => {
                    return Some(Ok(Root::Comment(SassComment { content: lexeme })))
                },
                _ => {
                    match ambiguous_holding_pen.pop() {
                        Some(held_lexeme) => {
                            ambiguous_holding_pen.push(
                                held_lexeme.combine(&lexeme)
                            );
                        },
                        None => {
                           ambiguous_holding_pen = vec![lexeme];
                        },
                    }
                }
            }
        }
        None
    }
}

impl<'a> Parser<'a> {
    pub fn new(text: &str) -> Parser {
        Parser {
            tokenizer: Tokenizer::new(&text),
        }
    }

    pub fn expect_token(expected: Token, actual: Option<Result<Lexeme>>) -> Result<Lexeme> {
        match actual {
            None => Err(SassError {
                offset: 0,
                kind: ErrorKind::UnexpectedEof,
                message: format!(
                    "Expected to see `{}`, instead reached EOF.",
                    expected,
                ),
            }),
            Some(res) => {
                match res {
                    Err(e) => Err(e),
                    Ok(actual) => {
                        if actual.token == expected {
                            Ok(actual)
                        } else {
                            Err(SassError {
                                offset: actual.offset.unwrap_or(0),
                                kind: ErrorKind::ParserError,
                                message: format!(
                                    "Expected to see `{}`, instead saw `{}`.",
                                    expected,
                                    actual.token,
                                ),
                            })
                        }

                    }
                }
            }
        }
    }

    pub fn parse_body(&mut self) -> Result<Vec<Node>> {
        let mut rule_stack = vec![];
        let mut body = vec![];
        let mut ambiguous_holding_pen = vec![];

        while let Some(Ok(lexeme)) = self.tokenizer.next() {
            match lexeme.token {
                Token::RightCurlyBrace => {
                    if rule_stack.is_empty() {
                        return Ok(body);
                    } else {
                        let tmp_rule = rule_stack.pop().unwrap();

                        if rule_stack.is_empty() {
                            body.push(Node::Rule(tmp_rule));
                        } else {
                            // TODO: mut ref to last?
                            let mut rule = rule_stack.pop().unwrap();
                            rule.children.push(Node::Rule(tmp_rule));
                            rule_stack.push(rule);
                        }
                    }
                },
                Token::LeftCurlyBrace => {
                    let mut rule = SassRule::new();
                    rule.selectors = ambiguous_holding_pen;
                    ambiguous_holding_pen = vec![];
                    rule_stack.push(rule);
                },
                Token::Colon => {
                    let value = try!(Expression::parse(&mut self.tokenizer));

                    let child = match ambiguous_holding_pen.pop() {
                        Some(name_lexeme) => {
                            match name_lexeme.token {
                                Token::String(ref s) if s.starts_with("$") => {
                                    Node::Variable(
                                        SassVariable {
                                            name: name_lexeme.clone(),
                                            value: value,
                                        }
                                    )
                                },
                                Token::String(_) => {
                                    Node::Property(name_lexeme, value)
                                },
                                other => {
                                    return Err(SassError {
                                        offset: name_lexeme.offset.unwrap_or(0),
                                        kind: ErrorKind::ParserError,
                                        message: format!(
                                            "Expected to have seen a property or variable name, instead saw {:?}", other
                                        ),
                                    })
                                },
                            }
                        },
                        None => {
                            return Err(SassError {
                                offset: lexeme.offset.unwrap_or(0),
                                kind: ErrorKind::ParserError,
                                message: String::from(
                                    "Expected to have seen a property or \
                                     variable name, did not see any"
                                ),
                            })
                        }
                    };
                    if rule_stack.is_empty() {
                        body.push(child);
                    } else {
                        // TODO: mut ref to last?
                        let mut rule = rule_stack.pop().unwrap();
                        rule.children.push(child);
                        rule_stack.push(rule);
                    }
                },
                Token::Comma => {
                    // TODO: else return error
                    if let Some(Ok(after_comma)) = self.tokenizer.next() {
                        ambiguous_holding_pen.push(after_comma);
                    }
                },
                Token::Comment(_) => {
                    if rule_stack.is_empty() {
                        body.push(
                            Node::Comment(
                                SassComment { content: lexeme }
                            )
                        );
                    } else {
                        // TODO: mut ref to last?
                        let mut rule = rule_stack.pop().unwrap();
                        rule.children.push(Node::Comment(
                            SassComment { content: lexeme }
                        ));
                        rule_stack.push(rule);
                    }
                },
                _ => {
                    match ambiguous_holding_pen.pop() {
                        Some(held_lexeme) => {
                            ambiguous_holding_pen.push(
                                held_lexeme.combine(&lexeme)
                            );
                        },
                        None => {
                           ambiguous_holding_pen = vec![lexeme];
                        },
                    }
                },
            }
        }

        Err(SassError {
            offset: 0,
            kind: ErrorKind::UnexpectedEof,
            message: String::from(
                "Expected to see rule body ending in `}`, instead reached EOF."
            ),
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use sass::rule::SassRule;
    use sass::comment::SassComment;
    use sass::variable::SassVariable;
    use ast::expression::Expression;
    use ast::root::Root;
    use ast::node::Node;
    use token::{Token, Lexeme};
    use error::{SassError, ErrorKind};

    #[test]
    fn it_returns_none_for_empty_string() {
        let mut parser = Parser::new("");
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn it_returns_a_rule() {
        let mut parser = Parser::new("a { color: blue; }");
        assert_eq!(parser.next(), Some(Ok(Root::Rule(
            SassRule {
                selectors: vec![Lexeme { token: Token::String("a".into()), offset: Some(0) }],
                children: vec![Node::Property(
                    Lexeme { token: Token::String("color".into()), offset: Some(4) },
                    Expression::String(
                        Lexeme { token: Token::String("blue".into()), offset: Some(11) }
                    ),
                )],
            }
        ))));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn it_returns_nested_rules() {
        let mut parser = Parser::new("div { span img, span a { color: blue; } }");
        assert_eq!(parser.next(), Some(Ok(Root::Rule(
            SassRule {
                selectors: vec![Lexeme { token: Token::String("div".into()), offset: Some(0) }],
                children: vec![Node::Rule(
                    SassRule {
                        selectors: vec![
                            Lexeme {
                                token: Token::String("span img".into()),
                                offset: Some(6)
                            },
                            Lexeme {
                                token: Token::String("span a".into()),
                                offset: Some(16)
                            },
                        ],
                        children: vec![Node::Property(
                            Lexeme { token: Token::String("color".into()), offset: Some(25) },
                            Expression::String(
                                Lexeme { token: Token::String("blue".into()), offset: Some(32) }
                            ),
                        )],
                    }
                )],
            }
        ))));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn it_returns_rules_without_properties() {
        let mut parser = Parser::new("div { empty { span { color: red; } } }");
        assert_eq!(parser.next(), Some(Ok(Root::Rule(
            SassRule {
                selectors: vec![
                    Lexeme {
                        token: Token::String("div".into()),
                        offset: Some(0)
                    },
                ],
                children: vec![
                    Node::Rule(
                        SassRule {
                            selectors: vec![
                                Lexeme {
                                    token: Token::String("empty".into()),
                                    offset: Some(6)
                                },
                            ],
                            children: vec![
                                Node::Rule(
                                    SassRule {
                                        selectors: vec![
                                            Lexeme {
                                                token: Token::String("span".into()),
                                                offset: Some(14)
                                            }
                                        ],
                                        children: vec![
                                            Node::Property(
                                                Lexeme {
                                                    token: Token::String("color".into()),
                                                    offset: Some(21)
                                                },
                                                Expression::String(
                                                    Lexeme {
                                                        token: Token::String("red".into()),
                                                        offset: Some(28)
                                                    }
                                                )
                                            )
                                        ],
                                    }
                                ),
                            ],
                        }
                    ),
                ]
            }
        ))));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn it_returns_rules_with_multiple_selectors() {
        let mut parser = Parser::new("a, b c { color: red; }");
        assert_eq!(parser.next(), Some(Ok(Root::Rule(
            SassRule {
                selectors: vec![
                    Lexeme { token: Token::String("a".into()), offset: Some(0) },
                    Lexeme { token: Token::String("b c".into()), offset: Some(3) },
                ],
                children: vec![Node::Property(
                    Lexeme { token: Token::String("color".into()), offset: Some(9) },
                    Expression::String(
                        Lexeme { token: Token::String("red".into()), offset: Some(16) }
                    ),
                )],
            }
        ))));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn it_returns_variable_setting_statements() {
        let mut parser = Parser::new("$color: red;");
        assert_eq!(parser.next(), Some(Ok(Root::Variable(SassVariable {
            name: Lexeme { token: Token::String("$color".into()), offset: Some(0) },
            value: Expression::String(
                Lexeme { token: Token::String("red".into()), offset: Some(8) }
            ),
        }))));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn it_returns_variables_set_within_rules() {
        let mut parser = Parser::new("a { $foo: red; }");
        assert_eq!(parser.next(), Some(Ok(Root::Rule(
            SassRule {
                selectors: vec![
                    Lexeme { token: Token::String("a".into()), offset: Some(0) },
                ],
                children: vec![Node::Variable(SassVariable {
                    name: Lexeme { token: Token::String("$foo".into()), offset: Some(4) },
                    value: Expression::String(
                        Lexeme { token: Token::String("red".into()), offset: Some(10) }
                    ),
                })],
            }
        ))));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn it_returns_a_comment() {
        let mut parser = Parser::new("/* hi */");
        assert_eq!(parser.next(), Some(Ok(Root::Comment(SassComment {
            content: Lexeme { token: Token::Comment("/* hi */".into()), offset: Some(0) },
        }))));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn it_errors_with_malformed_variable_declaration() {
        let mut parser = Parser::new("$var no-colon;");
        assert_eq!(parser.next(), Some(Err(SassError {
            offset: 5,
            kind: ErrorKind::ParserError,
            message: String::from("Expected to see `:`, instead saw `no-colon`."),
        })));
    }
}
<commit_msg>Don't add a comment if we're in the middle of something else<commit_after>use token::{Token, Lexeme};
use tokenizer::Tokenizer;
use ast::expression::Expression;
use ast::root::Root;
use ast::node::Node;
use sass::rule::SassRule;
use sass::variable::SassVariable;
use sass::comment::SassComment;
use error::{Result, SassError, ErrorKind};

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

impl<'a> Iterator for Parser<'a> {
    type Item = Result<Root>;

    fn next(&mut self) -> Option<Result<Root>> {
        let mut current_sass_rule = SassRule::new();
        let mut ambiguous_holding_pen = vec![];

        while let Some(Ok(lexeme)) = self.tokenizer.next() {
            match lexeme.token {
                Token::String(ref s) if s.starts_with("$") => {
                    let variable_name = lexeme.clone();

                    if let Err(e) = Parser::expect_token(
                        Token::Colon,
                        self.tokenizer.next()
                    ) { return Some(Err(e)) };

                    let variable_value = match Expression::parse(&mut self.tokenizer) {
                        Ok(e) => e,
                        Err(e) => return Some(Err(e)),
                    };
                    return Some(Ok(Root::Variable(
                        SassVariable {
                            name: variable_name,
                            value: variable_value
                        }
                    )))
                },
                Token::LeftCurlyBrace => {
                    current_sass_rule.selectors
                                     .extend_from_slice(&ambiguous_holding_pen);
                    current_sass_rule.children = match self.parse_body() {
                        Ok(body) => body,
                        Err(e) => return Some(Err(e)),
                    };
                    return Some(Ok(Root::Rule(current_sass_rule)))
                },
                Token::Comma => {
                    current_sass_rule.selectors.extend_from_slice(&ambiguous_holding_pen);
                    ambiguous_holding_pen = vec![];
                },
                Token::Comment(_) => {
                    if ambiguous_holding_pen.is_empty() {
                        return Some(Ok(Root::Comment(
                            SassComment { content: lexeme }
                        )))
                    }
                },
                _ => {
                    match ambiguous_holding_pen.pop() {
                        Some(held_lexeme) => {
                            ambiguous_holding_pen.push(
                                held_lexeme.combine(&lexeme)
                            );
                        },
                        None => {
                           ambiguous_holding_pen = vec![lexeme];
                        },
                    }
                }
            }
        }
        None
    }
}

impl<'a> Parser<'a> {
    pub fn new(text: &str) -> Parser {
        Parser {
            tokenizer: Tokenizer::new(&text),
        }
    }

    pub fn expect_token(expected: Token, actual: Option<Result<Lexeme>>) -> Result<Lexeme> {
        match actual {
            None => Err(SassError {
                offset: 0,
                kind: ErrorKind::UnexpectedEof,
                message: format!(
                    "Expected to see `{}`, instead reached EOF.",
                    expected,
                ),
            }),
            Some(res) => {
                match res {
                    Err(e) => Err(e),
                    Ok(actual) => {
                        if actual.token == expected {
                            Ok(actual)
                        } else {
                            Err(SassError {
                                offset: actual.offset.unwrap_or(0),
                                kind: ErrorKind::ParserError,
                                message: format!(
                                    "Expected to see `{}`, instead saw `{}`.",
                                    expected,
                                    actual.token,
                                ),
                            })
                        }

                    }
                }
            }
        }
    }

    pub fn parse_body(&mut self) -> Result<Vec<Node>> {
        let mut rule_stack = vec![];
        let mut body = vec![];
        let mut ambiguous_holding_pen = vec![];

        while let Some(Ok(lexeme)) = self.tokenizer.next() {
            match lexeme.token {
                Token::RightCurlyBrace => {
                    if rule_stack.is_empty() {
                        return Ok(body);
                    } else {
                        let tmp_rule = rule_stack.pop().unwrap();

                        if rule_stack.is_empty() {
                            body.push(Node::Rule(tmp_rule));
                        } else {
                            // TODO: mut ref to last?
                            let mut rule = rule_stack.pop().unwrap();
                            rule.children.push(Node::Rule(tmp_rule));
                            rule_stack.push(rule);
                        }
                    }
                },
                Token::LeftCurlyBrace => {
                    let mut rule = SassRule::new();
                    rule.selectors = ambiguous_holding_pen;
                    ambiguous_holding_pen = vec![];
                    rule_stack.push(rule);
                },
                Token::Colon => {
                    let value = try!(Expression::parse(&mut self.tokenizer));

                    let child = match ambiguous_holding_pen.pop() {
                        Some(name_lexeme) => {
                            match name_lexeme.token {
                                Token::String(ref s) if s.starts_with("$") => {
                                    Node::Variable(
                                        SassVariable {
                                            name: name_lexeme.clone(),
                                            value: value,
                                        }
                                    )
                                },
                                Token::String(_) => {
                                    Node::Property(name_lexeme, value)
                                },
                                other => {
                                    return Err(SassError {
                                        offset: name_lexeme.offset.unwrap_or(0),
                                        kind: ErrorKind::ParserError,
                                        message: format!(
                                            "Expected to have seen a property or variable name, instead saw {:?}", other
                                        ),
                                    })
                                },
                            }
                        },
                        None => {
                            return Err(SassError {
                                offset: lexeme.offset.unwrap_or(0),
                                kind: ErrorKind::ParserError,
                                message: String::from(
                                    "Expected to have seen a property or \
                                     variable name, did not see any"
                                ),
                            })
                        }
                    };
                    if rule_stack.is_empty() {
                        body.push(child);
                    } else {
                        // TODO: mut ref to last?
                        let mut rule = rule_stack.pop().unwrap();
                        rule.children.push(child);
                        rule_stack.push(rule);
                    }
                },
                Token::Comma => {
                    // TODO: else return error
                    if let Some(Ok(after_comma)) = self.tokenizer.next() {
                        ambiguous_holding_pen.push(after_comma);
                    }
                },
                Token::Comment(_) => {
                    if rule_stack.is_empty() {
                        body.push(
                            Node::Comment(
                                SassComment { content: lexeme }
                            )
                        );
                    } else {
                        // TODO: mut ref to last?
                        let mut rule = rule_stack.pop().unwrap();
                        rule.children.push(Node::Comment(
                            SassComment { content: lexeme }
                        ));
                        rule_stack.push(rule);
                    }
                },
                _ => {
                    match ambiguous_holding_pen.pop() {
                        Some(held_lexeme) => {
                            ambiguous_holding_pen.push(
                                held_lexeme.combine(&lexeme)
                            );
                        },
                        None => {
                           ambiguous_holding_pen = vec![lexeme];
                        },
                    }
                },
            }
        }

        Err(SassError {
            offset: 0,
            kind: ErrorKind::UnexpectedEof,
            message: String::from(
                "Expected to see rule body ending in `}`, instead reached EOF."
            ),
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use sass::rule::SassRule;
    use sass::comment::SassComment;
    use sass::variable::SassVariable;
    use ast::expression::Expression;
    use ast::root::Root;
    use ast::node::Node;
    use token::{Token, Lexeme};
    use error::{SassError, ErrorKind};

    #[test]
    fn it_returns_none_for_empty_string() {
        let mut parser = Parser::new("");
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn it_returns_a_rule() {
        let mut parser = Parser::new("a { color: blue; }");
        assert_eq!(parser.next(), Some(Ok(Root::Rule(
            SassRule {
                selectors: vec![Lexeme { token: Token::String("a".into()), offset: Some(0) }],
                children: vec![Node::Property(
                    Lexeme { token: Token::String("color".into()), offset: Some(4) },
                    Expression::String(
                        Lexeme { token: Token::String("blue".into()), offset: Some(11) }
                    ),
                )],
            }
        ))));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn it_returns_nested_rules() {
        let mut parser = Parser::new("div { span img, span a { color: blue; } }");
        assert_eq!(parser.next(), Some(Ok(Root::Rule(
            SassRule {
                selectors: vec![Lexeme { token: Token::String("div".into()), offset: Some(0) }],
                children: vec![Node::Rule(
                    SassRule {
                        selectors: vec![
                            Lexeme {
                                token: Token::String("span img".into()),
                                offset: Some(6)
                            },
                            Lexeme {
                                token: Token::String("span a".into()),
                                offset: Some(16)
                            },
                        ],
                        children: vec![Node::Property(
                            Lexeme { token: Token::String("color".into()), offset: Some(25) },
                            Expression::String(
                                Lexeme { token: Token::String("blue".into()), offset: Some(32) }
                            ),
                        )],
                    }
                )],
            }
        ))));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn it_returns_rules_without_properties() {
        let mut parser = Parser::new("div { empty { span { color: red; } } }");
        assert_eq!(parser.next(), Some(Ok(Root::Rule(
            SassRule {
                selectors: vec![
                    Lexeme {
                        token: Token::String("div".into()),
                        offset: Some(0)
                    },
                ],
                children: vec![
                    Node::Rule(
                        SassRule {
                            selectors: vec![
                                Lexeme {
                                    token: Token::String("empty".into()),
                                    offset: Some(6)
                                },
                            ],
                            children: vec![
                                Node::Rule(
                                    SassRule {
                                        selectors: vec![
                                            Lexeme {
                                                token: Token::String("span".into()),
                                                offset: Some(14)
                                            }
                                        ],
                                        children: vec![
                                            Node::Property(
                                                Lexeme {
                                                    token: Token::String("color".into()),
                                                    offset: Some(21)
                                                },
                                                Expression::String(
                                                    Lexeme {
                                                        token: Token::String("red".into()),
                                                        offset: Some(28)
                                                    }
                                                )
                                            )
                                        ],
                                    }
                                ),
                            ],
                        }
                    ),
                ]
            }
        ))));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn it_returns_rules_with_multiple_selectors() {
        let mut parser = Parser::new("a, b c { color: red; }");
        assert_eq!(parser.next(), Some(Ok(Root::Rule(
            SassRule {
                selectors: vec![
                    Lexeme { token: Token::String("a".into()), offset: Some(0) },
                    Lexeme { token: Token::String("b c".into()), offset: Some(3) },
                ],
                children: vec![Node::Property(
                    Lexeme { token: Token::String("color".into()), offset: Some(9) },
                    Expression::String(
                        Lexeme { token: Token::String("red".into()), offset: Some(16) }
                    ),
                )],
            }
        ))));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn it_returns_variable_setting_statements() {
        let mut parser = Parser::new("$color: red;");
        assert_eq!(parser.next(), Some(Ok(Root::Variable(SassVariable {
            name: Lexeme { token: Token::String("$color".into()), offset: Some(0) },
            value: Expression::String(
                Lexeme { token: Token::String("red".into()), offset: Some(8) }
            ),
        }))));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn it_returns_variables_set_within_rules() {
        let mut parser = Parser::new("a { $foo: red; }");
        assert_eq!(parser.next(), Some(Ok(Root::Rule(
            SassRule {
                selectors: vec![
                    Lexeme { token: Token::String("a".into()), offset: Some(0) },
                ],
                children: vec![Node::Variable(SassVariable {
                    name: Lexeme { token: Token::String("$foo".into()), offset: Some(4) },
                    value: Expression::String(
                        Lexeme { token: Token::String("red".into()), offset: Some(10) }
                    ),
                })],
            }
        ))));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn it_returns_a_comment() {
        let mut parser = Parser::new("/* hi */");
        assert_eq!(parser.next(), Some(Ok(Root::Comment(SassComment {
            content: Lexeme { token: Token::Comment("/* hi */".into()), offset: Some(0) },
        }))));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn it_errors_with_malformed_variable_declaration() {
        let mut parser = Parser::new("$var no-colon;");
        assert_eq!(parser.next(), Some(Err(SassError {
            offset: 5,
            kind: ErrorKind::ParserError,
            message: String::from("Expected to see `:`, instead saw `no-colon`."),
        })));
    }
}
<|endoftext|>


<commit_before>use {Span, Spanned};
use lexer::{mod, Lexer, Token};
use std::iter::Peekable;

#[deriving(Show, Clone)]
pub enum ParseError {
    UnexpectedEndOfFile,

    /// An unexpected token has been encountered.
    UnexpectedToken(Spanned<Token>, String),
}

#[deriving(Show, Clone)]
pub struct TranslationUnit(Vec<ExternalDeclaration>);

#[deriving(Show, Clone)]
pub enum ExternalDeclaration {
    /// Function definition.
    ExternalDeclarationFunctionDefinition(FunctionDeclaration, Vec<Statement>),
    ExternalDeclarationDeclaration(Declaration),
}

#[deriving(Show, Clone)]
pub enum Declaration {
    DeclarationVariable(FullySpecifiedType, String, Option<Expression>),
    DeclarationFunction(FunctionDeclaration),
}

#[deriving(Show, Clone)]
/// `$retvalue $name($params)`
pub struct FunctionDeclaration(FullySpecifiedType, String, Vec<()>);

#[deriving(Show, Clone)]
pub struct StructDefinition(Vec<()>);

#[deriving(Show, Clone)]
pub struct FullySpecifiedType {
    pub ty: Type,
    pub storage_qualifiers: Vec<StorageQualifier>,
    pub parameter_qualifier: Option<ParameterQualifier>,
    pub precision_qualifier: Option<PrecisionQualifier>,
}

#[deriving(Show, Clone)]
pub enum StorageQualifier {
    StorageQualifierConst,
    StorageQualifierInOut,
    StorageQualifierIn,
    StorageQualifierOut,
    StorageQualifierCentroid,
    StorageQualifierPatch,
    StorageQualifierSample,
    StorageQualifierUniform,
    StorageQualifierBuffer,
    StorageQualifierShared,
    StorageQualifierCoherent,
    StorageQualifierVolatile,
    StorageQualifierRestrict,
    StorageQualifierReadonly,
    StorageQualifierWriteonly,
    StorageQualifierSubroutine(Vec<()>),        // TODO:
}

#[deriving(Show, Clone)]
pub enum PrecisionQualifier {
    PrecisionQualifierHigh,
    PrecisionQualifierMedium,
    PrecisionQualifierLow,
}

#[deriving(Show, Clone)]
pub enum ParameterQualifier {
    ParameterQualifierIn,
    ParameterQualifierOut,
    ParameterQualifierInOut,
}

#[deriving(Show, Clone)]
pub enum Type {
    Void,
    Float,
    Int,
    Bool,
    Vec2,
    Vec3,
    Vec4,
    BVec2,
    BVec3,
    BVec4,
    IVec2,
    IVec3,
    IVec4,
    Mat2,
    Mat3,
    Mat4,
    Sampler2D,
    SamplerCube,
    TypeStruct(StructDefinition),
    TypeIdentifier(String),
}

#[deriving(Show, Clone)]
pub enum Statement {
    StatementExpression(Expression),
    /// `{ $statements }`
    StatementScope(Vec<Statement>),
    /// if `Expression` then `Statement` else `Option<Statement>`.
    StatementIf(Expression, Box<Statement>, Option<Box<Statement>>),
    /// `continue;`
    StatementContinue,
    /// `break;`
    StatementBreak,
    /// `return $expression;`
    StatementReturn(Expression),
    /// `discard;`
    StatementDiscard,
    StatementDeclaration(Declaration),
}

#[deriving(Show, Clone)]
pub enum Expression {
    /// `$op $2`
    ExpressionUnaryOperation(UnaryOperation, Box<Expression>),
    /// `$1 $op $2`
    ExpressionBinaryOperation(Box<Expression>, BinaryOperation, Box<Expression>),
    /// `$1 ? $2 : $3`
    ExpressionCondition(Box<Expression>, Box<Expression>, Box<Expression>),
    /// `$1($2)`
    ExpressionFunctionCall(Box<Expression>, Vec<Expression>),
    /// `$1`,
    ExpressionIdentifier(String),
    /// `__LINE__`
    ExpressionLine,
    /// `__FILE__`
    ExpressionFile,
    /// `__VERSION__`
    ExpressionVersion,
}

#[deriving(Show, Clone)]
pub enum UnaryOperation {
    /// `+`
    UnaryOperationPlus,
    /// `-`
    UnaryOperationMinus,
    /// `!`
    UnaryOperationNot,
    /// `++e`
    UnaryOperationPreInc,
    /// `--e`
    UnaryOperationPreDec,
    /// `e++`
    UnaryOperationPostInc,
    /// `e--`
    UnaryOperationPostDec,
}

#[deriving(Show, Clone)]
pub enum BinaryOperation {
    /// `+`
    BinaryOperationAddition,
    /// `-`
    BinaryOperationSubstraction,
    /// `*`
    BinaryOperationMultiplication,
    /// `/`
    BinaryOperationDivision,
    /// `%`
    BinaryOperationMod,
    /// `^`
    BinaryOperationXor,
    /// `&&`
    BinaryOperationAnd,
    /// `||`
    BinaryOperationOr,
    /// `&`
    BinaryOperationBinAnd,
    /// `|`
    BinaryOperationBinOr,
}

pub fn parse<R: Reader>(data: R) -> Result<TranslationUnit, ParseError> {
    Parser {
        lexer: Lexer::new(data).peekable(),
    }.parse_translation_unit()
}

struct Parser<R> {
    lexer: Peekable<Spanned<Token>, Lexer<R>>,
}

impl<R: Reader> Parser<R> {
    fn parse_translation_unit(&mut self) -> Result<TranslationUnit, ParseError> {
        let mut result = Vec::new();

        loop {
            match try!(self.parse_external_declaration()) {
                Some(decl) => result.push(decl),
                None => break
            };
        }

        Ok(TranslationUnit(result))
    }

    fn parse_external_declaration(&mut self) -> Result<Option<ExternalDeclaration>, ParseError> {
        self.skip_whitespaces();

        let token = match self.lexer.peek() {
            Some(token) => token.clone(),
            None => return Ok(None),
        };

        if token.content == lexer::Sharp {
            unimplemented!()
        }

        let ty = try!(self.parse_fully_specified_type());
        try!(self.expect_whitespace());
        let name = try!(self.parse_identifier());

        match (try!(self.peek())).content {
            lexer::SemiColon => {
                self.lexer.next();
                return Ok(Some(ExternalDeclarationDeclaration(
                    DeclarationVariable(ty, name, None)
                )));
            },
            lexer::LeftParenthesis => {
                self.lexer.next();
                // TODO: function parameters
                try!(self.expect_token(lexer::RightParenthesis));
                self.skip_whitespaces();

                match (try!(self.peek())).content {
                    lexer::LeftBrace => {
                        self.lexer.next();
                        self.skip_whitespaces();
                        let body = try!(self.parse_statements_list());
                        self.skip_whitespaces();
                        try!(self.expect_token(lexer::RightBrace));

                        return Ok(Some(ExternalDeclarationFunctionDefinition(
                            FunctionDeclaration(ty, name, Vec::new()),
                            body
                        )));
                    },
                    lexer::SemiColon => {
                        self.lexer.next();
                        return Ok(Some(ExternalDeclarationDeclaration(
                            DeclarationFunction(FunctionDeclaration(ty, name, Vec::new()))
                        )));
                    },
                    _ => ()
                }
            }
            _ => ()
        };

        Err(UnexpectedToken(try!(self.peek()), format!("external declaration")))
    }

    fn peek(&mut self) -> Result<Spanned<Token>, ParseError> {
        match self.lexer.peek() {
            Some(token) => Ok(token.clone()),
            None => Err(UnexpectedEndOfFile),
        }
    }

    fn expect_whitespace(&mut self) -> Result<(), ParseError> {
        let token = try!(self.peek());

        if let lexer::Whitespace(_) = token.content {
            self.lexer.next();
            return Ok(());
        } else {
            return Err(UnexpectedToken(token.clone(), format!("whitespace")));
        }
    }

    fn skip_whitespaces(&mut self) {
        loop {
            let token = match self.lexer.peek() {
                Some(token) => token.clone(),
                None => return,
            };

            if let lexer::Whitespace(_) = token.content {
                self.lexer.next();
            } else {
                break;
            }
        }
    }

    fn parse_identifier(&mut self) -> Result<String, ParseError> {
        let token = try!(self.peek());

        if let lexer::Identifier(ref id) = token.content {
            let val = Ok(id.clone());
            self.lexer.next();
            val
        } else {
            Err(UnexpectedToken(token.clone(), format!("identifier")))
        }
    }

    // TODO: incomplete
    fn parse_fully_specified_type(&mut self) -> Result<FullySpecifiedType, ParseError> {
        let mut token;

        let mut storage_qualifiers = Vec::new();

        loop {
            token = try!(self.peek());

            match token.content {
                lexer::Uniform => {
                    storage_qualifiers.push(StorageQualifierUniform);
                },
                lexer::Attribute => {
                    storage_qualifiers.push(StorageQualifierIn);
                },
                lexer::Varying => {
                    //storage_qualifiers.push(StorageQualifierOut);
                    // TODO: same as `in` in vertex shaders and `out` in fragment shaders
                },
                _ => break
            }

            self.lexer.next();
            self.expect_whitespace();
        }

        token = try!(self.peek());

        let ty = match token.content {
            lexer::Void => Void,
            lexer::Int => Int,
            lexer::Mat4 => Mat4,
            lexer::Vec2 => Vec2,
            _ => return Err(UnexpectedToken(token, format!("type")))
        };

        self.lexer.next();

        Ok(FullySpecifiedType {
            ty: ty,
            storage_qualifiers: storage_qualifiers,
            parameter_qualifier: None,
            precision_qualifier: None,
        })
    }

    fn parse_expression(&mut self) -> Result<Expression, ParseError> {
        // TODO: operators precedence

        let token = try!(self.peek());

        let expression = match token.content {
            lexer::Plus | lexer::Dash | lexer::Bang | lexer::Increment | lexer::Decrement => {
                self.lexer.next();

                let op = match token.content {
                    lexer::Plus => UnaryOperationPlus,
                    lexer::Dash => UnaryOperationMinus,
                    lexer::Bang => UnaryOperationNot,
                    lexer::Increment => UnaryOperationPreInc,
                    lexer::Decrement => UnaryOperationPreDec,
                    _ => fail!()
                };

                let expr = try!(self.parse_expression());
                ExpressionUnaryOperation(op, box expr)
            },
            lexer::Identifier(ref id) => {
                self.lexer.next();
                ExpressionIdentifier(id.clone())
            },
            _ => return Err(UnexpectedToken(token.clone(), format!("expression")))
        };

        match self.lexer.peek().map(|e| e.clone()) {
            Some(ref a) if a.content == lexer::Increment => {
                self.lexer.next();
                Ok(ExpressionUnaryOperation(UnaryOperationPostInc, box expression))
            },
            Some(ref a) if a.content == lexer::Decrement => {
                self.lexer.next();
                Ok(ExpressionUnaryOperation(UnaryOperationPostDec, box expression))
            },
            Some(ref a) if a.content == lexer::LeftParenthesis => {
                self.lexer.next();
                unimplemented!()
            },
            _ => Ok(expression),
        }
    }

    fn parse_statements_list(&mut self) -> Result<Vec<Statement>, ParseError> {
        let mut result = Vec::new();
        while self.lexer.peek().map(|e| e.content.clone()) != Some(lexer::RightBrace) {
            result.push(try!(self.parse_statement()));
            self.skip_whitespaces();
        }
        Ok(result)
    }

    fn parse_statement(&mut self) -> Result<Statement, ParseError> {
        let token = try!(self.peek());

        match token.content {
            lexer::LeftBrace => {
                self.lexer.next();
                let list = try!(self.parse_statements_list());
                try!(self.expect_token(lexer::RightBrace));
                Ok(StatementScope(list))
            },
            lexer::Continue => {
                self.lexer.next();
                try!(self.expect_semicolon());
                Ok(StatementContinue)
            },
            lexer::Break => {
                self.lexer.next();
                try!(self.expect_semicolon());
                Ok(StatementBreak)
            },
            lexer::Return => {
                self.lexer.next();
                let expr = try!(self.parse_expression());
                try!(self.expect_semicolon());
                Ok(StatementReturn(expr))
            },
            lexer::Discard => {
                self.lexer.next();
                try!(self.expect_semicolon());
                Ok(StatementDiscard)
            },
            _ => {
                self.parse_expression().map(|e| StatementExpression(e))
            }
        }
    }

    fn expect_semicolon(&mut self) -> Result<(), ParseError> {
        self.expect_token(lexer::SemiColon)
    }

    fn expect_token(&mut self, token: Token) -> Result<(), ParseError> {
        match self.lexer.next() {
            None => Err(UnexpectedEndOfFile),
            Some(ref a) if a.content == token => Ok(()),
            Some(a) => Err(UnexpectedToken(a.clone(), token.to_string())),
        }
    }
}

#[cfg(test)]
mod test {
    use std::io::BufReader;
    use super::parse;

    #[test]
    fn test() {
        let src = b"\
                uniform mat4 uMatrix;

                attribute vec2 iPosition;
                attribute vec2 iTexCoords;

                varying vec2 vTexCoords;

                void main() {
                    gl_Position = uMatrix * vec4(iPosition, 0.0, 1.0);
                    vTexCoords = iTexCoords;
                }";

        let reader = BufReader::new(src);

        fail!("{}", parse(reader));
    }
}
<commit_msg>Switch to cleaner parsing system<commit_after>use {Span, Spanned};
use lexer::{mod, Lexer, Token};

#[deriving(Show, Clone)]
pub enum ParseError {
    UnexpectedEndOfFile,

    /// An unexpected token has been encountered.
    UnexpectedToken(Spanned<Token>, String),
}

#[deriving(Show, Clone)]
pub struct TranslationUnit(Vec<ExternalDeclaration>);

#[deriving(Show, Clone)]
pub enum ExternalDeclaration {
    /// Function definition.
    ExternalDeclarationFunctionDefinition(FunctionDeclaration, Vec<Statement>),
    ExternalDeclarationDeclaration(Declaration),
}

#[deriving(Show, Clone)]
pub enum Declaration {
    DeclarationVariable(FullySpecifiedType, String, Option<Expression>),
    DeclarationFunction(FunctionDeclaration),
}

#[deriving(Show, Clone)]
/// `$retvalue $name($params)`
pub struct FunctionDeclaration(FullySpecifiedType, String, Vec<()>);

#[deriving(Show, Clone)]
pub struct StructDefinition(Vec<()>);

#[deriving(Show, Clone)]
pub struct FullySpecifiedType {
    pub ty: Type,
    pub storage_qualifiers: Vec<StorageQualifier>,
    pub parameter_qualifier: Option<ParameterQualifier>,
    pub precision_qualifier: Option<PrecisionQualifier>,
}

#[deriving(Show, Clone)]
pub enum StorageQualifier {
    StorageQualifierConst,
    StorageQualifierInOut,
    StorageQualifierIn,
    StorageQualifierOut,
    StorageQualifierCentroid,
    StorageQualifierPatch,
    StorageQualifierSample,
    StorageQualifierUniform,
    StorageQualifierBuffer,
    StorageQualifierShared,
    StorageQualifierCoherent,
    StorageQualifierVolatile,
    StorageQualifierRestrict,
    StorageQualifierReadonly,
    StorageQualifierWriteonly,
    StorageQualifierSubroutine(Vec<()>),        // TODO:
}

#[deriving(Show, Clone)]
pub enum PrecisionQualifier {
    PrecisionQualifierHigh,
    PrecisionQualifierMedium,
    PrecisionQualifierLow,
}

#[deriving(Show, Clone)]
pub enum ParameterQualifier {
    ParameterQualifierIn,
    ParameterQualifierOut,
    ParameterQualifierInOut,
}

#[deriving(Show, Clone)]
pub enum Type {
    Void,
    Float,
    Int,
    Bool,
    Vec2,
    Vec3,
    Vec4,
    BVec2,
    BVec3,
    BVec4,
    IVec2,
    IVec3,
    IVec4,
    Mat2,
    Mat3,
    Mat4,
    Sampler2D,
    SamplerCube,
    TypeStruct(StructDefinition),
    TypeIdentifier(String),
}

#[deriving(Show, Clone)]
pub enum Statement {
    StatementExpression(Expression),
    /// `{ $statements }`
    StatementScope(Vec<Statement>),
    /// if `Expression` then `Statement` else `Option<Statement>`.
    StatementIf(Expression, Box<Statement>, Option<Box<Statement>>),
    /// `continue;`
    StatementContinue,
    /// `break;`
    StatementBreak,
    /// `return $expression;`
    StatementReturn(Expression),
    /// `discard;`
    StatementDiscard,
    StatementDeclaration(Declaration),
}

#[deriving(Show, Clone)]
pub enum Expression {
    /// `$op $2`
    ExpressionUnaryOperation(UnaryOperation, Box<Expression>),
    /// `$1 $op $2`
    ExpressionBinaryOperation(Box<Expression>, BinaryOperation, Box<Expression>),
    /// `$1 ? $2 : $3`
    ExpressionCondition(Box<Expression>, Box<Expression>, Box<Expression>),
    /// `$1($2)`
    ExpressionFunctionCall(Box<Expression>, Vec<Expression>),
    /// `$1`,
    ExpressionIdentifier(String),
    /// `__LINE__`
    ExpressionLine,
    /// `__FILE__`
    ExpressionFile,
    /// `__VERSION__`
    ExpressionVersion,
}

#[deriving(Show, Clone)]
pub enum UnaryOperation {
    /// `+`
    UnaryOperationPlus,
    /// `-`
    UnaryOperationMinus,
    /// `!`
    UnaryOperationNot,
    /// `++e`
    UnaryOperationPreInc,
    /// `--e`
    UnaryOperationPreDec,
    /// `e++`
    UnaryOperationPostInc,
    /// `e--`
    UnaryOperationPostDec,
}

#[deriving(Show, Clone)]
pub enum BinaryOperation {
    /// `+`
    BinaryOperationAddition,
    /// `-`
    BinaryOperationSubstraction,
    /// `*`
    BinaryOperationMultiplication,
    /// `/`
    BinaryOperationDivision,
    /// `%`
    BinaryOperationMod,
    /// `^`
    BinaryOperationXor,
    /// `&&`
    BinaryOperationAnd,
    /// `||`
    BinaryOperationOr,
    /// `&`
    BinaryOperationBinAnd,
    /// `|`
    BinaryOperationBinOr,
}

pub fn parse<R: Reader>(data: R) -> Result<TranslationUnit, ParseError> {
    let mut parser = Parser {
        lexer: Lexer::new(data),
        next_token: None,
    };

    try!(parser.read_next());
    parser.parse_translation_unit()
}

struct Parser<R> {
    lexer: Lexer<R>,
    next_token: Option<Spanned<Token>>,
}

impl<R: Reader> Parser<R> {
    fn read_next(&mut self) -> Result<(), ParseError> {
        self.next_token = self.lexer.next();
        Ok(())
    }

    fn parse_translation_unit(&mut self) -> Result<TranslationUnit, ParseError> {
        let mut result = Vec::new();

        loop {
            match try!(self.parse_external_declaration()) {
                Some(decl) => result.push(decl),
                None => break
            };
        }

        Ok(TranslationUnit(result))
    }

    fn parse_external_declaration(&mut self) -> Result<Option<ExternalDeclaration>, ParseError> {
        self.skip_whitespaces();

        let token = match self.next_token {
            Some(ref token) => token.clone(),
            None => return Ok(None),
        };

        if token.content == lexer::Sharp {
            unimplemented!()
        }

        let ty = try!(self.parse_fully_specified_type());
        try!(self.expect_whitespace());
        let name = try!(self.parse_identifier());

        match (try!(self.peek())).content {
            lexer::SemiColon => {
                try!(self.read_next());
                return Ok(Some(ExternalDeclarationDeclaration(
                    DeclarationVariable(ty, name, None)
                )));
            },
            lexer::LeftParenthesis => {
                try!(self.read_next());
                // TODO: function parameters
                try!(self.expect_token(lexer::RightParenthesis));
                self.skip_whitespaces();

                match (try!(self.peek())).content {
                    lexer::LeftBrace => {
                        try!(self.read_next());
                        self.skip_whitespaces();
                        let body = try!(self.parse_statements_list());
                        self.skip_whitespaces();
                        try!(self.expect_token(lexer::RightBrace));

                        return Ok(Some(ExternalDeclarationFunctionDefinition(
                            FunctionDeclaration(ty, name, Vec::new()),
                            body
                        )));
                    },
                    lexer::SemiColon => {
                        try!(self.read_next());
                        return Ok(Some(ExternalDeclarationDeclaration(
                            DeclarationFunction(FunctionDeclaration(ty, name, Vec::new()))
                        )));
                    },
                    _ => ()
                }
            }
            _ => ()
        };

        Err(UnexpectedToken(try!(self.peek()), format!("external declaration")))
    }

    fn peek(&mut self) -> Result<Spanned<Token>, ParseError> {
        match self.next_token {
            Some(ref token) => Ok(token.clone()),
            None => Err(UnexpectedEndOfFile),
        }
    }

    fn expect_whitespace(&mut self) -> Result<(), ParseError> {
        let token = try!(self.peek());

        if let lexer::Whitespace(_) = token.content {
            try!(self.read_next());
            return Ok(());
        } else {
            return Err(UnexpectedToken(token.clone(), format!("whitespace")));
        }
    }

    fn skip_whitespaces(&mut self) {
        loop {
            let token = match self.next_token {
                Some(ref token) => token.clone(),
                None => return,
            };

            if let lexer::Whitespace(_) = token.content {
                self.read_next();
            } else {
                break;
            }
        }
    }

    fn parse_identifier(&mut self) -> Result<String, ParseError> {
        let token = try!(self.peek());

        if let lexer::Identifier(ref id) = token.content {
            let val = Ok(id.clone());
            try!(self.read_next());
            val
        } else {
            Err(UnexpectedToken(token.clone(), format!("identifier")))
        }
    }

    // TODO: incomplete
    fn parse_fully_specified_type(&mut self) -> Result<FullySpecifiedType, ParseError> {
        let mut token;

        let mut storage_qualifiers = Vec::new();

        loop {
            token = try!(self.peek());

            match token.content {
                lexer::Uniform => {
                    storage_qualifiers.push(StorageQualifierUniform);
                },
                lexer::Attribute => {
                    storage_qualifiers.push(StorageQualifierIn);
                },
                lexer::Varying => {
                    //storage_qualifiers.push(StorageQualifierOut);
                    // TODO: same as `in` in vertex shaders and `out` in fragment shaders
                },
                _ => break
            }

            try!(self.read_next());
            self.expect_whitespace();
        }

        token = try!(self.peek());

        let ty = match token.content {
            lexer::Void => Void,
            lexer::Int => Int,
            lexer::Mat4 => Mat4,
            lexer::Vec2 => Vec2,
            _ => return Err(UnexpectedToken(token, format!("type")))
        };

        try!(self.read_next());

        Ok(FullySpecifiedType {
            ty: ty,
            storage_qualifiers: storage_qualifiers,
            parameter_qualifier: None,
            precision_qualifier: None,
        })
    }

    fn parse_expression(&mut self) -> Result<Expression, ParseError> {
        // TODO: operators precedence

        let token = try!(self.peek());

        let expression = match token.content {
            lexer::Plus | lexer::Dash | lexer::Bang | lexer::Increment | lexer::Decrement => {
                try!(self.read_next());

                let op = match token.content {
                    lexer::Plus => UnaryOperationPlus,
                    lexer::Dash => UnaryOperationMinus,
                    lexer::Bang => UnaryOperationNot,
                    lexer::Increment => UnaryOperationPreInc,
                    lexer::Decrement => UnaryOperationPreDec,
                    _ => fail!()
                };

                let expr = try!(self.parse_expression());
                ExpressionUnaryOperation(op, box expr)
            },
            lexer::Identifier(ref id) => {
                try!(self.read_next());
                ExpressionIdentifier(id.clone())
            },
            _ => return Err(UnexpectedToken(token.clone(), format!("expression")))
        };

        match self.next_token.as_ref().map(|e| e.clone()) {
            Some(ref a) if a.content == lexer::Increment => {
                try!(self.read_next());
                Ok(ExpressionUnaryOperation(UnaryOperationPostInc, box expression))
            },
            Some(ref a) if a.content == lexer::Decrement => {
                try!(self.read_next());
                Ok(ExpressionUnaryOperation(UnaryOperationPostDec, box expression))
            },
            Some(ref a) if a.content == lexer::LeftParenthesis => {
                try!(self.read_next());
                unimplemented!()
            },
            _ => Ok(expression),
        }
    }

    fn parse_statements_list(&mut self) -> Result<Vec<Statement>, ParseError> {
        let mut result = Vec::new();
        while self.next_token.as_ref().map(|e| e.content.clone()) != Some(lexer::RightBrace) {
            result.push(try!(self.parse_statement()));
            self.skip_whitespaces();
        }
        Ok(result)
    }

    fn parse_statement(&mut self) -> Result<Statement, ParseError> {
        let token = try!(self.peek());

        match token.content {
            lexer::LeftBrace => {
                try!(self.read_next());
                let list = try!(self.parse_statements_list());
                try!(self.expect_token(lexer::RightBrace));
                Ok(StatementScope(list))
            },
            lexer::Continue => {
                try!(self.read_next());
                try!(self.expect_semicolon());
                Ok(StatementContinue)
            },
            lexer::Break => {
                try!(self.read_next());
                try!(self.expect_semicolon());
                Ok(StatementBreak)
            },
            lexer::Return => {
                try!(self.read_next());
                let expr = try!(self.parse_expression());
                try!(self.expect_semicolon());
                Ok(StatementReturn(expr))
            },
            lexer::Discard => {
                try!(self.read_next());
                try!(self.expect_semicolon());
                Ok(StatementDiscard)
            },
            _ => {
                self.parse_expression().map(|e| StatementExpression(e))
            }
        }
    }

    fn expect_semicolon(&mut self) -> Result<(), ParseError> {
        self.expect_token(lexer::SemiColon)
    }

    fn expect_token(&mut self, token: Token) -> Result<(), ParseError> {
        let val = match self.next_token {
            None => Err(UnexpectedEndOfFile),
            Some(ref a) if a.content == token => Ok(()),
            Some(ref a) => Err(UnexpectedToken(a.clone(), token.to_string())),
        };

        if val.is_ok() {
            try!(self.read_next());
        }

        val
    }
}

#[cfg(test)]
mod test {
    use std::io::BufReader;
    use super::parse;

    #[test]
    fn test() {
        let src = b"\
                uniform mat4 uMatrix;

                attribute vec2 iPosition;
                attribute vec2 iTexCoords;

                varying vec2 vTexCoords;

                void main() {
                    gl_Position = uMatrix * vec4(iPosition, 0.0, 1.0);
                    vTexCoords = iTexCoords;
                }";

        let reader = BufReader::new(src);

        fail!("{}", parse(reader));
    }
}
<|endoftext|>


<commit_before>
use device;
use gfx;
use gfx::DeviceHelper;
use graphics::{
    BackEnd,
};

use Texture;

static BUFFER_SIZE: uint = 1024;

static VERTEX_SHADER: gfx::ShaderSource = shaders!{
    GLSL_120: b"
#version 120
attribute vec2 pos;
attribute vec3 color;
varying vec4 v_Color;
void main() {
    v_Color = vec4(color, 1.0);
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
    GLSL_150: b"
#version 150 core
in vec2 pos;
in vec3 color;
out vec4 v_Color;
void main() {
    v_Color = vec4(color, 1.0);
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
};

static FRAGMENT_SHADER: gfx::ShaderSource = shaders!{
    GLSL_120: b"
#version 120
varying vec4 v_Color;
void main() {
    gl_FragColor = v_Color;
}
"
    GLSL_150: b"
#version 150 core
in vec4 v_Color;
out vec4 o_Color;
void main() {
    o_Color = v_Color;
}
"
};

static VERTEX_SHADER_UV: gfx::ShaderSource = shaders!{
    GLSL_120: b"
#version 120
attribute vec2 pos;
attribute vec3 color;
attribute vec2 uv;
uniform sampler2D s_texture;
varying vec4 v_Color;
varying vec2 v_UV;
void main() {
    v_UV = uv;
    v_Color = color;
    gl_Position = a_v4Position;
}
"
    GLSL_150: b"
#version 150 core
in vec2 pos;
in vec3 color;
in vec2 uv;
uniform sampler2D s_texture;
out vec4 v_Color;
out vec2 v_UV;
void main() {
    v_UV = uv;
    v_Color = color;
    gl_Position = a_v4Position;
}
"
};

static FRAGMENT_SHADER_UV: gfx::ShaderSource = shaders!{
    GLSL_120: b"
#version 120
uniform sampler2D s_texture;
varying vec2 v_UV;
varying vec4 v_Color;
void main()
{
    gl_FragColor = texture(s_texture, v_UV) * v_Color;
}
"
    GLSL_150: b"
#version 150 core
out vec4 o_Color;
uniform sampler2D s_texture;
in vec2 v_UV;
in vec4 v_Color;
void main()
{
    o_Color = texture(s_texture, v_UV) * v_Color;
}
"
};

#[vertex_format]
struct Vertex {
    pos: [f32, ..2],
    color: [f32, ..4],
}

impl Vertex {
    fn new(pos: [f32, ..2], color: [f32, ..4]) -> Vertex {
        Vertex {
            pos: pos,
            color: color,
        }
    }
}

#[vertex_format]
struct VertexUV {
    pos: [f32, ..2],
    color: [f32, ..4],
    uv: [f32, ..2],
}

impl VertexUV {
    fn new(pos: [f32, ..2], color: [f32, ..4], uv: [f32, ..2]) -> VertexUV {
        VertexUV {
            pos: pos,
            color: color,
            uv: uv,
        }
    }
}

#[shader_param(ProgramUV)]
struct ParamsUV {
    s_texture: gfx::shade::TextureParam,
}

/// The graphics back-end.
pub struct Gfx2d {
    renderer: gfx::Renderer,
    state: gfx::DrawState,
    program: gfx::shade::EmptyProgram,
    program_uv: ProgramUV,
    vertex_data: Vec<Vertex>,
    vertex_data_uv: Vec<VertexUV>,
    buffer: gfx::BufferHandle<Vertex>,
    buffer_uv: gfx::BufferHandle<VertexUV>,
}

impl Gfx2d {
    /// Creates a new Gfx2d object.
    pub fn new<D: gfx::Device>(device: &mut D) -> Gfx2d {
        Gfx2d {
            state: gfx::DrawState::new(),
            program: device.link_program(
                    VERTEX_SHADER.clone(),
                    FRAGMENT_SHADER.clone()
                ).unwrap(),
            program_uv: device.link_program(
                    VERTEX_SHADER_UV.clone(),
                    FRAGMENT_SHADER_UV.clone()
                ).unwrap(),
            vertex_data: Vec::with_capacity(BUFFER_SIZE),
            vertex_data_uv: Vec::with_capacity(BUFFER_SIZE),
            renderer: device.create_renderer(),
            buffer: device.create_buffer(BUFFER_SIZE, gfx::UsageDynamic),
            buffer_uv: device.create_buffer(BUFFER_SIZE, gfx::UsageDynamic),
        }
    }

    /// Returns the command buffer to be submitted to device.
    pub fn as_buffer(&self) -> &device::GlCommandBuffer {
        self.renderer.as_buffer()
    }
}

impl BackEnd<Texture> for Gfx2d {
    fn supports_tri_list_xy_f32_rgba_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32]
    ) {
        let &Gfx2d {
            ref mut vertex_data,
            ref mut renderer,
            ref mut buffer,
            ..
        } = self;
        vertex_data.clear();
        let n = vertices.len() / 2;
        for i in range(0, n) {
            vertex_data.push(
                Vertex::new(
                    [vertices[2 * i], vertices[2 * i + 1]],
                    [
                        colors[4 * i],
                        colors[4 * i + 1],
                        colors[4 * i + 2],
                        colors[4 * i + 3]
                    ]
                )
            );
        }
        renderer.update_buffer_vec(*buffer, vertex_data.clone(), 0);
    }
}
<commit_msg>Implement on tuple<commit_after>
use device;
use gfx;
use gfx::DeviceHelper;
use graphics::{
    BackEnd,
};

use Texture;

static BUFFER_SIZE: uint = 1024;

static VERTEX_SHADER: gfx::ShaderSource = shaders!{
    GLSL_120: b"
#version 120
attribute vec2 pos;
attribute vec3 color;
varying vec4 v_Color;
void main() {
    v_Color = vec4(color, 1.0);
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
    GLSL_150: b"
#version 150 core
in vec2 pos;
in vec3 color;
out vec4 v_Color;
void main() {
    v_Color = vec4(color, 1.0);
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
};

static FRAGMENT_SHADER: gfx::ShaderSource = shaders!{
    GLSL_120: b"
#version 120
varying vec4 v_Color;
void main() {
    gl_FragColor = v_Color;
}
"
    GLSL_150: b"
#version 150 core
in vec4 v_Color;
out vec4 o_Color;
void main() {
    o_Color = v_Color;
}
"
};

static VERTEX_SHADER_UV: gfx::ShaderSource = shaders!{
    GLSL_120: b"
#version 120
attribute vec2 pos;
attribute vec3 color;
attribute vec2 uv;
uniform sampler2D s_texture;
varying vec4 v_Color;
varying vec2 v_UV;
void main() {
    v_UV = uv;
    v_Color = color;
    gl_Position = a_v4Position;
}
"
    GLSL_150: b"
#version 150 core
in vec2 pos;
in vec3 color;
in vec2 uv;
uniform sampler2D s_texture;
out vec4 v_Color;
out vec2 v_UV;
void main() {
    v_UV = uv;
    v_Color = color;
    gl_Position = a_v4Position;
}
"
};

static FRAGMENT_SHADER_UV: gfx::ShaderSource = shaders!{
    GLSL_120: b"
#version 120
uniform sampler2D s_texture;
varying vec2 v_UV;
varying vec4 v_Color;
void main()
{
    gl_FragColor = texture(s_texture, v_UV) * v_Color;
}
"
    GLSL_150: b"
#version 150 core
out vec4 o_Color;
uniform sampler2D s_texture;
in vec2 v_UV;
in vec4 v_Color;
void main()
{
    o_Color = texture(s_texture, v_UV) * v_Color;
}
"
};

#[vertex_format]
struct Vertex {
    pos: [f32, ..2],
    color: [f32, ..4],
}

impl Vertex {
    fn new(pos: [f32, ..2], color: [f32, ..4]) -> Vertex {
        Vertex {
            pos: pos,
            color: color,
        }
    }
}

#[vertex_format]
struct VertexUV {
    pos: [f32, ..2],
    color: [f32, ..4],
    uv: [f32, ..2],
}

impl VertexUV {
    fn new(pos: [f32, ..2], color: [f32, ..4], uv: [f32, ..2]) -> VertexUV {
        VertexUV {
            pos: pos,
            color: color,
            uv: uv,
        }
    }
}

#[shader_param(BatchUV, OwnedBatchUV)]
struct ParamsUV {
    s_texture: gfx::shade::TextureParam,
}

/// The graphics back-end.
pub struct Gfx2d<C: gfx::CommandBuffer> {
    state: gfx::DrawState,
    program: device::Handle<u32,device::shade::ProgramInfo>,
    program_uv: device::Handle<u32,device::shade::ProgramInfo>,
    buffer: gfx::BufferHandle<Vertex>,
    buffer_uv: gfx::BufferHandle<VertexUV>,
    mesh: gfx::Mesh,
    mesh_uv: gfx::Mesh,
}

impl<C: gfx::CommandBuffer> Gfx2d<C> {
    /// Creates a new Gfx2d object.
    pub fn new<D: gfx::Device<C>>(device: &mut D) -> Gfx2d<C> {
        let buffer = device.create_buffer(BUFFER_SIZE, gfx::UsageDynamic);
        let buffer_uv = device.create_buffer(BUFFER_SIZE, gfx::UsageDynamic);
        Gfx2d {
            state: gfx::DrawState::new(),
            program: device.link_program(
                    VERTEX_SHADER.clone(),
                    FRAGMENT_SHADER.clone()
                ).unwrap(),
            program_uv: device.link_program(
                    VERTEX_SHADER_UV.clone(),
                    FRAGMENT_SHADER_UV.clone()
                ).unwrap(),
            buffer: buffer,
            buffer_uv: buffer_uv,
            mesh: gfx::Mesh::from_format(buffer, BUFFER_SIZE as u32),
            mesh_uv: gfx::Mesh::from_format(buffer, BUFFER_SIZE as u32),
        }
    }
}

impl<'a, C: gfx::CommandBuffer> BackEnd<Texture>
for (gfx::Renderer<C>, Gfx2d<C>) {
    fn supports_tri_list_xy_f32_rgba_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32]
    ) {
        let &(ref mut renderer, Gfx2d {
            ref mut buffer,
            ..
        }) = self;
        let mut vertex_data = Vec::new();
        let n = vertices.len() / 2;
        for i in range(0, n) {
            vertex_data.push(
                Vertex::new(
                    [vertices[2 * i], vertices[2 * i + 1]],
                    [
                        colors[4 * i],
                        colors[4 * i + 1],
                        colors[4 * i + 2],
                        colors[4 * i + 3]
                    ]
                )
            );
        }

        /*
        let n = vertex_data.len();
        renderer.update_buffer_vec(*buffer, vertex_data, 0);
        */
    }
}
<|endoftext|>


<commit_before>use std::collections::hash_map::{HashMap, RandomState};
use std::error;
use std::hash::{BuildHasher, Hash};
use record::Commands;
use {Command, Error, Record, Stack};

/// A group of either stacks or records.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Group<K: Hash + Eq, V, S = RandomState> where S: BuildHasher {
    map: HashMap<K, V, S>,
    active: Option<K>,
}

impl<K: Hash + Eq, V, S: BuildHasher> Group<K, V, S> {
    /// Returns a new group.
    #[inline]
    pub fn new() -> Group<K, V, RandomState> {
        Default::default()
    }

    /// Returns a new group with the given capacity.
    #[inline]
    pub fn with_capacity(capacity: usize) -> Group<K, V, RandomState> {
        Group::with_capacity_and_hasher(capacity, Default::default())
    }

    /// Returns a new group with the given hasher.
    #[inline]
    pub fn with_hasher(hash_builder: S) -> Group<K, V, S> {
        Group {
            map: HashMap::with_hasher(hash_builder),
            active: None,
        }
    }

    /// Returns a new group with the given capacity and hasher.
    #[inline]
    pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Group<K, V, S> {
        Group {
            map: HashMap::with_capacity_and_hasher(capacity, hash_builder),
            active: None,
        }
    }

    /// Returns the capacity of the group.
    #[inline]
    pub fn capacity(&self) -> usize {
        self.map.capacity()
    }

    /// Returns the number of items in the group.
    #[inline]
    pub fn len(&self) -> usize {
        self.map.len()
    }

    /// Returns `true` if the group is empty.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.map.is_empty()
    }

    /// Inserts an item into the group.
    #[inline]
    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
        self.map.insert(k, v)
    }

    /// Removes an item from the group.
    #[inline]
    pub fn remove(&mut self, k: &K) -> Option<V> {
        self.map.remove(k)
    }

    /// Gets the current active item in the group.
    #[inline]
    pub fn get(&self) -> Option<&V> {
        self.active.as_ref().and_then(|active| self.map.get(active))
    }

    /// Sets the current active item in the group.
    #[inline]
    pub fn set<T: Into<Option<K>>>(&mut self, k: T) -> bool {
        match k.into() {
            Some(ref k) if !self.map.contains_key(k) => false,
            k => {
                self.active = k;
                true
            }
        }
    }
}

impl<K: Hash + Eq, R, S: BuildHasher> Group<K, Stack<R>, S> {
    /// Calls the [`push`] method on the active stack.
    ///
    /// [`push`]: stack/struct.Stack.html#method.push
    #[inline]
    pub fn push<C>(&mut self, cmd: C) -> Option<Result<(), Error<R>>>
    where
        C: Command<R> + 'static,
        R: 'static,
    {
        let map = &mut self.map;
        self.active
            .as_ref()
            .and_then(|active| map.get_mut(active))
            .map(move |stack| stack.push(cmd))
    }

    /// Calls the [`pop`] method on the active stack.
    ///
    /// [`pop`]: stack/struct.Stack.html#method.pop
    #[inline]
    pub fn pop(&mut self) -> Option<Result<Box<Command<R>>, Error<R>>> {
        let map = &mut self.map;
        self.active
            .as_ref()
            .and_then(|active| map.get_mut(active))
            .and_then(|stack| stack.pop())
    }
}

impl<'a, K: Hash + Eq, R, S: BuildHasher> Group<K, Record<'a, R>, S> {
    /// Calls the [`push`] method on the active record.
    ///
    /// [`push`]: record/struct.Record.html#method.push
    #[inline]
    pub fn push<C>(&mut self, cmd: C) -> Option<Result<Commands<R>, Error<R>>>
    where
        C: Command<R> + 'static,
        R: 'static,
    {
        let map = &mut self.map;
        self.active
            .as_ref()
            .and_then(|active| map.get_mut(active))
            .map(move |record| record.push(cmd))
    }

    /// Calls the [`redo`] method on the active record.
    ///
    /// [`redo`]: record/struct.Record.html#method.redo
    #[inline]
    pub fn redo(&mut self) -> Option<Result<(), Box<error::Error>>> {
        let map = &mut self.map;
        self.active
            .as_ref()
            .and_then(|active| map.get_mut(active))
            .and_then(|record| record.redo())
    }

    /// Calls the [`undo`] method on the active record.
    ///
    /// [`undo`]: record/struct.Record.html#method.undo
    #[inline]
    pub fn undo(&mut self) -> Option<Result<(), Box<error::Error>>> {
        let map = &mut self.map;
        self.active
            .as_ref()
            .and_then(|active| map.get_mut(active))
            .and_then(|record| record.undo())
    }
}

impl<K: Hash + Eq, V, S: BuildHasher + Default> Default for Group<K, V, S> {
    #[inline]
    fn default() -> Group<K, V, S> {
        Group::with_hasher(Default::default())
    }
}
<commit_msg>Fix imports<commit_after>use std::collections::hash_map::{HashMap, RandomState};
use std::error;
use std::hash::{BuildHasher, Hash};
use {Command, Commands, Error, Record, Stack};

/// A group of either stacks or records.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Group<K: Hash + Eq, V, S = RandomState> where S: BuildHasher {
    map: HashMap<K, V, S>,
    active: Option<K>,
}

impl<K: Hash + Eq, V, S: BuildHasher> Group<K, V, S> {
    /// Returns a new group.
    #[inline]
    pub fn new() -> Group<K, V, RandomState> {
        Default::default()
    }

    /// Returns a new group with the given capacity.
    #[inline]
    pub fn with_capacity(capacity: usize) -> Group<K, V, RandomState> {
        Group::with_capacity_and_hasher(capacity, Default::default())
    }

    /// Returns a new group with the given hasher.
    #[inline]
    pub fn with_hasher(hash_builder: S) -> Group<K, V, S> {
        Group {
            map: HashMap::with_hasher(hash_builder),
            active: None,
        }
    }

    /// Returns a new group with the given capacity and hasher.
    #[inline]
    pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Group<K, V, S> {
        Group {
            map: HashMap::with_capacity_and_hasher(capacity, hash_builder),
            active: None,
        }
    }

    /// Returns the capacity of the group.
    #[inline]
    pub fn capacity(&self) -> usize {
        self.map.capacity()
    }

    /// Returns the number of items in the group.
    #[inline]
    pub fn len(&self) -> usize {
        self.map.len()
    }

    /// Returns `true` if the group is empty.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.map.is_empty()
    }

    /// Inserts an item into the group.
    #[inline]
    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
        self.map.insert(k, v)
    }

    /// Removes an item from the group.
    #[inline]
    pub fn remove(&mut self, k: &K) -> Option<V> {
        self.map.remove(k)
    }

    /// Gets the current active item in the group.
    #[inline]
    pub fn get(&self) -> Option<&V> {
        self.active.as_ref().and_then(|active| self.map.get(active))
    }

    /// Sets the current active item in the group.
    #[inline]
    pub fn set<T: Into<Option<K>>>(&mut self, k: T) -> bool {
        match k.into() {
            Some(ref k) if !self.map.contains_key(k) => false,
            k => {
                self.active = k;
                true
            }
        }
    }
}

impl<K: Hash + Eq, R, S: BuildHasher> Group<K, Stack<R>, S> {
    /// Calls the [`push`] method on the active stack.
    ///
    /// [`push`]: stack/struct.Stack.html#method.push
    #[inline]
    pub fn push<C>(&mut self, cmd: C) -> Option<Result<(), Error<R>>>
    where
        C: Command<R> + 'static,
        R: 'static,
    {
        let map = &mut self.map;
        self.active
            .as_ref()
            .and_then(|active| map.get_mut(active))
            .map(move |stack| stack.push(cmd))
    }

    /// Calls the [`pop`] method on the active stack.
    ///
    /// [`pop`]: stack/struct.Stack.html#method.pop
    #[inline]
    pub fn pop(&mut self) -> Option<Result<Box<Command<R>>, Error<R>>> {
        let map = &mut self.map;
        self.active
            .as_ref()
            .and_then(|active| map.get_mut(active))
            .and_then(|stack| stack.pop())
    }
}

impl<'a, K: Hash + Eq, R, S: BuildHasher> Group<K, Record<'a, R>, S> {
    /// Calls the [`push`] method on the active record.
    ///
    /// [`push`]: record/struct.Record.html#method.push
    #[inline]
    pub fn push<C>(&mut self, cmd: C) -> Option<Result<Commands<R>, Error<R>>>
    where
        C: Command<R> + 'static,
        R: 'static,
    {
        let map = &mut self.map;
        self.active
            .as_ref()
            .and_then(|active| map.get_mut(active))
            .map(move |record| record.push(cmd))
    }

    /// Calls the [`redo`] method on the active record.
    ///
    /// [`redo`]: record/struct.Record.html#method.redo
    #[inline]
    pub fn redo(&mut self) -> Option<Result<(), Box<error::Error>>> {
        let map = &mut self.map;
        self.active
            .as_ref()
            .and_then(|active| map.get_mut(active))
            .and_then(|record| record.redo())
    }

    /// Calls the [`undo`] method on the active record.
    ///
    /// [`undo`]: record/struct.Record.html#method.undo
    #[inline]
    pub fn undo(&mut self) -> Option<Result<(), Box<error::Error>>> {
        let map = &mut self.map;
        self.active
            .as_ref()
            .and_then(|active| map.get_mut(active))
            .and_then(|record| record.undo())
    }
}

impl<K: Hash + Eq, V, S: BuildHasher + Default> Default for Group<K, V, S> {
    #[inline]
    fn default() -> Group<K, V, S> {
        Group::with_hasher(Default::default())
    }
}
<|endoftext|>