<commit_before>use std::collections::HashMap;
use std::fmt;

use crate::ast;
use crate::lexer;
use crate::token;

// For debug visualization I migth potentially use this approach
// https://users.rust-lang.org/t/is-it-possible-to-implement-debug-for-fn-type/14824

// Greeting to the master of functinal Rust - mighty @raventid
type PrefixParseFnAlias = Fn(&Parser) -> token::Expression + 'static;

struct PrefixParseFn(Box<PrefixParseFnAlias>);
impl fmt::Debug for PrefixParseFn {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", "prefix_parse_fn")
    }
}

type InfixParseFnAlias = Fn(&Parser, token::Expression) -> token::Expression + 'static;

struct InfixParseFn(Box<InfixParseFnAlias>);
impl fmt::Debug for InfixParseFn {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", "infix_parse_fn")
    }
}

#[derive(Debug)]
struct LambdaParsers {
    pub prefix_parse_fns: HashMap<token::TokenType, PrefixParseFn>,
    pub infix_parse_fns: HashMap<token::TokenType, InfixParseFn>,
}

impl LambdaParsers {
    fn register_parsers(&mut self) {
        self.register_prefix(
            token::IDENT.to_string(),
            Box::new(|parser| {
                token::Expression::Identifier(token::Identifier {
                    token: parser.current_token.clone(),
                    value: parser.current_token.literal.clone(),
                })

            })
        );
    }

    fn register_prefix(&mut self, token_type: token::TokenType, f: Box<PrefixParseFnAlias>) {
        self.prefix_parse_fns.insert(token_type, PrefixParseFn(f));
    }

    fn register_infix(&mut self, token_type: token::TokenType, f: Box<InfixParseFnAlias>) {
        self.infix_parse_fns.insert(token_type, InfixParseFn(f));
    }

    fn parse_identifier(parser: &Parser) -> token::Expression {
        token::Expression::Identifier(token::Identifier {
            token: parser.current_token.clone(),
            value: parser.current_token.literal.clone(),
        })
    }
}

#[derive(Debug)]
pub struct Parser {
    lexer: lexer::Lexer,
    current_token: token::Token,
    peek_token: token::Token,
    pub errors: Vec<String>,
    lambda_parsers: LambdaParsers,
}

impl Parser {
    fn new(mut lexer: lexer::Lexer) -> Self {
        let current_token = lexer.next_token();
        let peek_token = lexer.next_token();
        let errors = Vec::new();
        let lambda_parsers = LambdaParsers {
            prefix_parse_fns: HashMap::new(),
            infix_parse_fns: HashMap::new(),
        };

        let mut parser = Self {
            lexer,
            current_token,
            peek_token,
            errors,
            lambda_parsers,
        };

        parser.lambda_parsers.register_parsers();

        parser
    }

    // fn register_parsers(self) {
    //     let parser = self.clone();
    //     self.register_prefix(
    //         token::IDENT.to_string(),
    //         Box::new(move |parser| {
    //             token::Expression::Identifier(token::Identifier {
    //                 token: parser.current_token,
    //                 value: parser.current_token.literal,
    //             })

    //         })
    //     );
    // }

    fn next_token(&mut self) {
        self.current_token = self.peek_token.clone();
        self.peek_token = self.lexer.next_token();
    }

    pub fn parse_program(&mut self) -> Option<ast::Program> {
        let mut program = ast::Program {
            statements: Vec::new(),
        };
        while self.current_token.token_type != token::EOF {
            let statement = self.parse_statement();
            match statement {
                Some(stmt) => program.statements.push(stmt),
                _ => (), // Just ignore that case
            };
            self.next_token();
        }
        Some(program)
    }

    fn parse_statement(&mut self) -> Option<token::Statements> {
        dbg!(&self);
        match self.current_token.token_type.as_ref() {
            token::LET => match self.parse_let_statement() {
                Some(stmt) => Some(token::Statements::LetStatement(stmt)),
                _ => None,
            },
            token::RETURN => match self.parse_return_statement() {
                Some(stmt) => Some(token::Statements::ReturnStatement(stmt)),
                _ => None,
            },
            // If we did not encounter any `let` or `return` it might've happened that
            // we've encountered another type of statement.
            // The last one in our language - expresion statement.
            _ => match self.parse_expression_statement() {
                Some(stmt) => Some(token::Statements::ExpressionStatement(stmt)),
                _ => None,
            },
        }
    }

    fn parse_let_statement(&mut self) -> Option<token::LetStatement> {
        let token = self.current_token.clone();

        if self.peek_token.token_type == token::IDENT {
            self.next_token();
        } else {
            self.peek_error(token::IDENT.to_string());
            return None;
        }

        let name = token::Identifier {
            token: self.current_token.clone(),
            value: self.current_token.literal.clone(),
        };

        if self.peek_token.token_type == token::ASSIGN {
            self.next_token();
        } else {
            self.peek_error(token::ASSIGN.to_string());
            return None;
        }

        // TODO: It's a fragile design for now, this code might hang if we don't
        // have a terminating semicolon and next token is token::EOF
        // in this case we'll enter an infinite loop.
        // Doesn't next_token() protect us from this? Apparently - not.
        while !(self.current_token.token_type == token::SEMICOLON) {
            self.next_token(); // skip to next statement in our program
        }

        // TODO: Same happens in return parser. I'm skipping
        // semicolon, so in `parse_statement` function I can
        // just start to parse next value.
        // Weird, it does not work here that way.
        // self.next_token();

        Some(token::LetStatement {
            token,
            name,
            value: "dumb".to_string(),
        })
    }

    fn parse_return_statement(&mut self) -> Option<token::ReturnStatement> {
        let statement = token::ReturnStatement {
            token: self.current_token.clone(),
            return_value: "dumb".to_string(), // How to better describe expression?
        };

        self.next_token();

        while !(self.peek_token.token_type == token::SEMICOLON) {
            self.next_token(); // skip everything till `;` for now
        }

        // TODO: Should I skip semicolon here?
        self.next_token();

        Some(statement)
    }

    fn parse_expression_statement(&mut self) -> Option<token::ExpressionStatement> {
        let statement = token::ExpressionStatement {
            token: self.current_token.clone(),
            expression: match self.parse_expression(token::LOWEST) {
                Some(expression) => expression,
                None => panic!("I do not expect that expression is empty in parse_identifier!"),
            }
        };

        if self.peek_token.token_type == token::SEMICOLON {
            self.next_token();
        }

        Some(statement)
    }

    fn parse_expression(&self, precedence: u8) -> Option<token::Expression> {
        match self.lambda_parsers.prefix_parse_fns.get(&self.current_token.token_type) {
            Some(PrefixParseFn(prefix_parse_fn)) => Some(prefix_parse_fn(&self)),
            None => return None,
        }
    }

    // fn parse_identifier(&self) -> token::Expression {
    //     token::Expression::Identifier(token::Identifier {
    //         token: self.current_token,
    //         value: self.current_token.literal,
    //     })
    // }

    fn peek_error(&mut self, token: token::TokenType) {
        let message = format!(
            "expected next token to be {expected}, got {got} instead",
            expected = token,
            got = self.peek_token.token_type,
        );

        self.errors.push(message);
    }

    // fn register_prefix(&mut self, token_type: token::TokenType, f: Box<PrefixParseFnAlias>) {
    //     self.prefix_parse_fns.insert(token_type, PrefixParseFn(f));
    // }

    // fn register_infix(&mut self, token_type: token::TokenType, f: Box<InfixParseFnAlias>) {
    //     self.infix_parse_fns.insert(token_type, InfixParseFn(f));
    // }
}

#[cfg(test)]
mod tests {
    use crate::ast::Node;
    use crate::lexer;
    use crate::parser::Parser;
    use crate::token::Statements;
    use crate::token::Expression;

    #[test]
    fn test_let_statements() {
        let input = r###"
          let x = 5;
          let y = 10;
          let bebe = 101010;
        "###
        .to_string();

        let lexer = lexer::Lexer::new(input);
        let mut parser = Parser::new(lexer);

        let program = match parser.parse_program() {
            Some(program) => program,
            None => panic!("Could not parse program"),
        };

        // We would like to accumulate every error in program
        // and later render them to user.
        if !parser.errors.is_empty() {
            println!("Parser encountered {} errors", parser.errors.len());
            for error in parser.errors {
                println!("parser error: {}", error);
            }
            panic!("A few parsing error encountered, see them above.");
        }

        assert_eq!(program.statements.len(), 3);

        let expected = vec!["x".to_string(), "y".to_string(), "bebe".to_string()];

        program
            .statements
            .into_iter()
            .zip(expected.into_iter())
            .for_each(|(statement, expected_identifier)| {
                assert_eq!(statement.token_literal(), "let");

                let let_statement = match statement {
                    Statements::LetStatement(statement) => statement,
                    _ => panic!("I didn't expected anything besides `let` statement"),
                };

                assert_eq!(let_statement.name.value, expected_identifier);

                assert_eq!(let_statement.name.token_literal(), expected_identifier);
            });
    }

    #[test]
    fn test_broken_let_statements_and_check_if_errors_appear() {
        let input = r###"
          let x = 5;
          let y = 10;
          let bebe 101010;
        "###
        .to_string();

        let lexer = lexer::Lexer::new(input);
        let mut parser = Parser::new(lexer);

        match parser.parse_program() {
            Some(program) => program,
            None => panic!("Could not parse program"),
        };

        // We would like to accumulate every error in program
        // and later render them to user.
        if !parser.errors.is_empty() {
            for error in parser.errors {
                assert_eq!(
                    "parser error: expected next token to be =, got INT instead",
                    format!("parser error: {}", error)
                );
            }
        }
    }

    #[test]
    fn test_return_statement() {
        let input = r###"
          return 1;
          return 111;
        "###
        .to_string();

        let lexer = lexer::Lexer::new(input);
        let mut parser = Parser::new(lexer);

        let program = match parser.parse_program() {
            Some(program) => program,
            None => panic!("Could not parse program"),
        };

        // We would like to accumulate every error in program
        // and later render them to user.
        if !parser.errors.is_empty() {
            println!("Parser encountered {} errors", parser.errors.len());
            for error in parser.errors {
                println!("parser error: {}", error);
            }
            panic!("A few parsing error encountered, see them above.");
        }

        assert_eq!(program.statements.len(), 2);

        let expected = vec!["1".to_string(), "111".to_string()];

        program
            .statements
            .into_iter()
            .zip(expected.into_iter())
            .for_each(|(statement, expected_identifier)| {
                assert_eq!(statement.token_literal(), "return");

                let return_statement = match statement {
                    Statements::ReturnStatement(statement) => statement,
                    _ => panic!("I didn't expected anything besides `return` statement"),
                };
            });
    }

    #[test]
    fn test_identifier_expression() {
        let input = r###"
          bebe;
        "###
        .to_string();

        let lexer = lexer::Lexer::new(input);
        let mut parser = Parser::new(lexer);

        let program = match parser.parse_program() {
            Some(program) => program,
            None => panic!("Could not parse program"),
        };

        // We would like to accumulate every error in program
        // and later render them to user.
        if !parser.errors.is_empty() {
            println!("Parser encountered {} errors", parser.errors.len());
            for error in parser.errors {
                println!("parser error: {}", error);
            }
            panic!("A few parsing error encountered, see them above.");
        }

        assert_eq!(program.statements.len(), 1);

        program.statements.into_iter().for_each(|statement| {
            let expression_statement = match statement {
                Statements::ExpressionStatement(statement) => statement,
                _ => panic!("I didn't expect something besides expression statement"),
            };

            let identifier = match expression_statement.expression {
                Expression::Identifier(i) => i,
                _ => panic!("expected to find identifier, but found smth else"),
            };
            // TODO: Maybe pattern matching on concrete branch is better here
            // then some general value() method.
            // Anyway in control code I will use it the other way.
            assert_eq!(identifier.value, "bebe");
            assert_eq!(identifier.token_literal(), "bebe");
        })
    }

    #[test]
    fn test_int_literal_expression() {
        let input = r###"
          42;
        "###
        .to_string();

        let lexer = lexer::Lexer::new(input);
        let mut parser = Parser::new(lexer);

        let program = match parser.parse_program() {
            Some(program) => program,
            None => panic!("Could not parse program"),
        };

        // We would like to accumulate every error in program
        // and later render them to user.
        if !parser.errors.is_empty() {
            println!("Parser encountered {} errors", parser.errors.len());
            for error in parser.errors {
                println!("parser error: {}", error);
            }
            panic!("A few parsing error encountered, see them above.");
        }

        assert_eq!(program.statements.len(), 1);

        program.statements.into_iter().for_each(|statement| {
            let expression_statement = match statement {
                Statements::ExpressionStatement(statement) => statement,
                _ => panic!("I didn't expect something besides expression statement"),
            };

            let integer_literal = match expression_statement.expression {
                Expression::IntegerLiteral(il) => il,
                _ => panic!("expected to find an integer_literal, but found smth else"),
            };
            // TODO: Maybe pattern matching on concrete branch is better here
            // then some general value() method.
            // Anyway in control code I will use it the other way.
            assert_eq!(integer_literal.value, 42);
            assert_eq!(integer_literal.token_literal(), "42");
        })
    }

}
<commit_msg>parser support for integer literal<commit_after>use std::collections::HashMap;
use std::fmt;

use crate::ast;
use crate::lexer;
use crate::token;

// For debug visualization I migth potentially use this approach
// https://users.rust-lang.org/t/is-it-possible-to-implement-debug-for-fn-type/14824

// Greeting to the master of functinal Rust - mighty @raventid
type PrefixParseFnAlias = Fn(&Parser) -> token::Expression + 'static;

struct PrefixParseFn(Box<PrefixParseFnAlias>);
impl fmt::Debug for PrefixParseFn {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", "prefix_parse_fn")
    }
}

type InfixParseFnAlias = Fn(&Parser, token::Expression) -> token::Expression + 'static;

struct InfixParseFn(Box<InfixParseFnAlias>);
impl fmt::Debug for InfixParseFn {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", "infix_parse_fn")
    }
}

#[derive(Debug)]
struct LambdaParsers {
    pub prefix_parse_fns: HashMap<token::TokenType, PrefixParseFn>,
    pub infix_parse_fns: HashMap<token::TokenType, InfixParseFn>,
}

impl LambdaParsers {
    fn register_parsers(&mut self) {
        self.register_prefix(
            token::IDENT.to_string(),
            Box::new(|parser| {
                token::Expression::Identifier(token::Identifier {
                    token: parser.current_token.clone(),
                    value: parser.current_token.literal.clone(),
                })

            })
        );

        self.register_prefix(
            token::INT.to_string(),
            Box::new(Self::parse_int_literal)
        )
    }

    fn register_prefix(&mut self, token_type: token::TokenType, f: Box<PrefixParseFnAlias>) {
        self.prefix_parse_fns.insert(token_type, PrefixParseFn(f));
    }

    fn register_infix(&mut self, token_type: token::TokenType, f: Box<InfixParseFnAlias>) {
        self.infix_parse_fns.insert(token_type, InfixParseFn(f));
    }

    fn parse_identifier(parser: &Parser) -> token::Expression {
        token::Expression::Identifier(token::Identifier {
            token: parser.current_token.clone(),
            value: parser.current_token.literal.clone(),
        })
    }

    fn parse_int_literal(parser: &Parser) -> token::Expression {
        let to_be_integer = parser.current_token.literal.clone();

        // TODO: This extremly bad
        // Lambda parsers should bubble errors to parser.
        // Parser should handle them gracefully.
        let integer = to_be_integer.parse::<i32>().unwrap();

        token::Expression::IntegerLiteral(token::IntegerLiteral {
            token: parser.current_token.clone(),
            value: integer,
        })
    }
}

#[derive(Debug)]
pub struct Parser {
    lexer: lexer::Lexer,
    current_token: token::Token,
    peek_token: token::Token,
    pub errors: Vec<String>,
    lambda_parsers: LambdaParsers,
}

impl Parser {
    fn new(mut lexer: lexer::Lexer) -> Self {
        let current_token = lexer.next_token();
        let peek_token = lexer.next_token();
        let errors = Vec::new();
        let lambda_parsers = LambdaParsers {
            prefix_parse_fns: HashMap::new(),
            infix_parse_fns: HashMap::new(),
        };

        let mut parser = Self {
            lexer,
            current_token,
            peek_token,
            errors,
            lambda_parsers,
        };

        parser.lambda_parsers.register_parsers();

        parser
    }

    // fn register_parsers(self) {
    //     let parser = self.clone();
    //     self.register_prefix(
    //         token::IDENT.to_string(),
    //         Box::new(move |parser| {
    //             token::Expression::Identifier(token::Identifier {
    //                 token: parser.current_token,
    //                 value: parser.current_token.literal,
    //             })

    //         })
    //     );
    // }

    fn next_token(&mut self) {
        self.current_token = self.peek_token.clone();
        self.peek_token = self.lexer.next_token();
    }

    pub fn parse_program(&mut self) -> Option<ast::Program> {
        let mut program = ast::Program {
            statements: Vec::new(),
        };
        while self.current_token.token_type != token::EOF {
            let statement = self.parse_statement();
            match statement {
                Some(stmt) => program.statements.push(stmt),
                _ => (), // Just ignore that case
            };
            self.next_token();
        }
        Some(program)
    }

    fn parse_statement(&mut self) -> Option<token::Statements> {
        dbg!(&self);
        match self.current_token.token_type.as_ref() {
            token::LET => match self.parse_let_statement() {
                Some(stmt) => Some(token::Statements::LetStatement(stmt)),
                _ => None,
            },
            token::RETURN => match self.parse_return_statement() {
                Some(stmt) => Some(token::Statements::ReturnStatement(stmt)),
                _ => None,
            },
            // If we did not encounter any `let` or `return` it might've happened that
            // we've encountered another type of statement.
            // The last one in our language - expresion statement.
            _ => match self.parse_expression_statement() {
                Some(stmt) => Some(token::Statements::ExpressionStatement(stmt)),
                _ => None,
            },
        }
    }

    fn parse_let_statement(&mut self) -> Option<token::LetStatement> {
        let token = self.current_token.clone();

        if self.peek_token.token_type == token::IDENT {
            self.next_token();
        } else {
            self.peek_error(token::IDENT.to_string());
            return None;
        }

        let name = token::Identifier {
            token: self.current_token.clone(),
            value: self.current_token.literal.clone(),
        };

        if self.peek_token.token_type == token::ASSIGN {
            self.next_token();
        } else {
            self.peek_error(token::ASSIGN.to_string());
            return None;
        }

        // TODO: It's a fragile design for now, this code might hang if we don't
        // have a terminating semicolon and next token is token::EOF
        // in this case we'll enter an infinite loop.
        // Doesn't next_token() protect us from this? Apparently - not.
        while !(self.current_token.token_type == token::SEMICOLON) {
            self.next_token(); // skip to next statement in our program
        }

        // TODO: Same happens in return parser. I'm skipping
        // semicolon, so in `parse_statement` function I can
        // just start to parse next value.
        // Weird, it does not work here that way.
        // self.next_token();

        Some(token::LetStatement {
            token,
            name,
            value: "dumb".to_string(),
        })
    }

    fn parse_return_statement(&mut self) -> Option<token::ReturnStatement> {
        let statement = token::ReturnStatement {
            token: self.current_token.clone(),
            return_value: "dumb".to_string(), // How to better describe expression?
        };

        self.next_token();

        while !(self.peek_token.token_type == token::SEMICOLON) {
            self.next_token(); // skip everything till `;` for now
        }

        // TODO: Should I skip semicolon here?
        self.next_token();

        Some(statement)
    }

    fn parse_expression_statement(&mut self) -> Option<token::ExpressionStatement> {
        let statement = token::ExpressionStatement {
            token: self.current_token.clone(),
            expression: match self.parse_expression(token::LOWEST) {
                Some(expression) => expression,
                None => panic!("I do not expect that expression is empty in parse_identifier!"),
            }
        };

        if self.peek_token.token_type == token::SEMICOLON {
            self.next_token();
        }

        Some(statement)
    }

    fn parse_expression(&self, precedence: u8) -> Option<token::Expression> {
        match self.lambda_parsers.prefix_parse_fns.get(&self.current_token.token_type) {
            Some(PrefixParseFn(prefix_parse_fn)) => Some(prefix_parse_fn(&self)),
            None => return None,
        }
    }

    // fn parse_identifier(&self) -> token::Expression {
    //     token::Expression::Identifier(token::Identifier {
    //         token: self.current_token,
    //         value: self.current_token.literal,
    //     })
    // }

    fn peek_error(&mut self, token: token::TokenType) {
        let message = format!(
            "expected next token to be {expected}, got {got} instead",
            expected = token,
            got = self.peek_token.token_type,
        );

        self.errors.push(message);
    }

    // fn register_prefix(&mut self, token_type: token::TokenType, f: Box<PrefixParseFnAlias>) {
    //     self.prefix_parse_fns.insert(token_type, PrefixParseFn(f));
    // }

    // fn register_infix(&mut self, token_type: token::TokenType, f: Box<InfixParseFnAlias>) {
    //     self.infix_parse_fns.insert(token_type, InfixParseFn(f));
    // }
}

#[cfg(test)]
mod tests {
    use crate::ast::Node;
    use crate::lexer;
    use crate::parser::Parser;
    use crate::token::Statements;
    use crate::token::Expression;

    #[test]
    fn test_let_statements() {
        let input = r###"
          let x = 5;
          let y = 10;
          let bebe = 101010;
        "###
        .to_string();

        let lexer = lexer::Lexer::new(input);
        let mut parser = Parser::new(lexer);

        let program = match parser.parse_program() {
            Some(program) => program,
            None => panic!("Could not parse program"),
        };

        // We would like to accumulate every error in program
        // and later render them to user.
        if !parser.errors.is_empty() {
            println!("Parser encountered {} errors", parser.errors.len());
            for error in parser.errors {
                println!("parser error: {}", error);
            }
            panic!("A few parsing error encountered, see them above.");
        }

        assert_eq!(program.statements.len(), 3);

        let expected = vec!["x".to_string(), "y".to_string(), "bebe".to_string()];

        program
            .statements
            .into_iter()
            .zip(expected.into_iter())
            .for_each(|(statement, expected_identifier)| {
                assert_eq!(statement.token_literal(), "let");

                let let_statement = match statement {
                    Statements::LetStatement(statement) => statement,
                    _ => panic!("I didn't expected anything besides `let` statement"),
                };

                assert_eq!(let_statement.name.value, expected_identifier);

                assert_eq!(let_statement.name.token_literal(), expected_identifier);
            });
    }

    #[test]
    fn test_broken_let_statements_and_check_if_errors_appear() {
        let input = r###"
          let x = 5;
          let y = 10;
          let bebe 101010;
        "###
        .to_string();

        let lexer = lexer::Lexer::new(input);
        let mut parser = Parser::new(lexer);

        match parser.parse_program() {
            Some(program) => program,
            None => panic!("Could not parse program"),
        };

        // We would like to accumulate every error in program
        // and later render them to user.
        if !parser.errors.is_empty() {
            for error in parser.errors {
                assert_eq!(
                    "parser error: expected next token to be =, got INT instead",
                    format!("parser error: {}", error)
                );
            }
        }
    }

    #[test]
    fn test_return_statement() {
        let input = r###"
          return 1;
          return 111;
        "###
        .to_string();

        let lexer = lexer::Lexer::new(input);
        let mut parser = Parser::new(lexer);

        let program = match parser.parse_program() {
            Some(program) => program,
            None => panic!("Could not parse program"),
        };

        // We would like to accumulate every error in program
        // and later render them to user.
        if !parser.errors.is_empty() {
            println!("Parser encountered {} errors", parser.errors.len());
            for error in parser.errors {
                println!("parser error: {}", error);
            }
            panic!("A few parsing error encountered, see them above.");
        }

        assert_eq!(program.statements.len(), 2);

        let expected = vec!["1".to_string(), "111".to_string()];

        program
            .statements
            .into_iter()
            .zip(expected.into_iter())
            .for_each(|(statement, expected_identifier)| {
                assert_eq!(statement.token_literal(), "return");

                let return_statement = match statement {
                    Statements::ReturnStatement(statement) => statement,
                    _ => panic!("I didn't expected anything besides `return` statement"),
                };
            });
    }

    #[test]
    fn test_identifier_expression() {
        let input = r###"
          bebe;
        "###
        .to_string();

        let lexer = lexer::Lexer::new(input);
        let mut parser = Parser::new(lexer);

        let program = match parser.parse_program() {
            Some(program) => program,
            None => panic!("Could not parse program"),
        };

        // We would like to accumulate every error in program
        // and later render them to user.
        if !parser.errors.is_empty() {
            println!("Parser encountered {} errors", parser.errors.len());
            for error in parser.errors {
                println!("parser error: {}", error);
            }
            panic!("A few parsing error encountered, see them above.");
        }

        assert_eq!(program.statements.len(), 1);

        program.statements.into_iter().for_each(|statement| {
            let expression_statement = match statement {
                Statements::ExpressionStatement(statement) => statement,
                _ => panic!("I didn't expect something besides expression statement"),
            };

            let identifier = match expression_statement.expression {
                Expression::Identifier(i) => i,
                _ => panic!("expected to find identifier, but found smth else"),
            };
            // TODO: Maybe pattern matching on concrete branch is better here
            // then some general value() method.
            // Anyway in control code I will use it the other way.
            assert_eq!(identifier.value, "bebe");
            assert_eq!(identifier.token_literal(), "bebe");
        })
    }

    #[test]
    fn test_int_literal_expression() {
        let input = r###"
          42;
        "###
        .to_string();

        let lexer = lexer::Lexer::new(input);
        let mut parser = Parser::new(lexer);

        let program = match parser.parse_program() {
            Some(program) => program,
            None => panic!("Could not parse program"),
        };

        // We would like to accumulate every error in program
        // and later render them to user.
        if !parser.errors.is_empty() {
            println!("Parser encountered {} errors", parser.errors.len());
            for error in parser.errors {
                println!("parser error: {}", error);
            }
            panic!("A few parsing error encountered, see them above.");
        }

        assert_eq!(program.statements.len(), 1);

        program.statements.into_iter().for_each(|statement| {
            let expression_statement = match statement {
                Statements::ExpressionStatement(statement) => statement,
                _ => panic!("I didn't expect something besides expression statement"),
            };

            let integer_literal = match expression_statement.expression {
                Expression::IntegerLiteral(il) => il,
                _ => panic!("expected to find an integer_literal, but found smth else"),
            };
            // TODO: Maybe pattern matching on concrete branch is better here
            // then some general value() method.
            // Anyway in control code I will use it the other way.
            assert_eq!(integer_literal.value, 42);
            assert_eq!(integer_literal.token_literal(), "42");
        })
    }

}
<|endoftext|>


<commit_before>use std::mem;

use num::bigint;
use num::bigint::ToBigInt;
use num::traits::{Zero, One};

use encoding::{Encoding, DecoderTrap};
use encoding::all::ISO_8859_1;

use bertterm::BertTerm;
use error::{Result, BertError};

static BERT_MAGIC_NUMBER: u8 = 131;
static SMALL_INTEGER_EXT: u8 = 97;
static INTEGER_EXT: u8 = 98;
static FLOAT_EXT: u8 = 99;
static ATOM_EXT: u8 = 100;
static SMALL_ATOM_EXT: u8 = 115;
static SMALL_TUPLE_EXT: u8 = 104;
static LARGE_TUPLE_EXT: u8 = 105;
static NIL_EXT: u8 = 106;
static STRING_EXT: u8 = 107;
static LIST_EXT: u8 = 108;
static BINARY_EXT: u8 = 109;
static SMALL_BIG_EXT: u8 = 110;
static LARGE_BIG_EXT: u8 = 111;
static ATOM_UTF8_EXT: u8 = 118;
static SMALL_ATOM_UTF8_EXT: u8 = 119;
static NEW_FLOAT_EXT: u8 = 70;

#[derive(Debug)]
pub struct Parser {
    contents: Vec<u8>,
    pos: usize,
}

impl Parser {
    pub fn new(contents: Vec<u8>) -> Parser {
        Parser { contents: contents, pos: 0 }
    }

    pub fn parse(&mut self) -> Result<BertTerm> {
        let () = self.magic_number()?;
        let term = self.bert_term()?;
        if self.pos == self.contents.len() {
            return Ok(term);
        } else {
            return Err(BertError::ExtraData(self.pos));
        }
    }

    // Parsers
    fn magic_number(&mut self) -> Result<()> {
        let offset = self.pos;
        let magic = self.eat_u8()?;
        if magic != BERT_MAGIC_NUMBER {
            return Err(BertError::InvalidMagicNumber(offset));
        } else {
            return Ok(());
        }
    }

    fn bert_term(&mut self) -> Result<BertTerm> {
        let offset = self.pos;
        let tag = self.eat_u8()?;
        if tag == SMALL_INTEGER_EXT {
            self.small_integer()
        } else if tag == INTEGER_EXT {
            self.integer()
        } else if tag == FLOAT_EXT {
            self.old_float()
        } else if tag == NEW_FLOAT_EXT {
            self.new_float()
        } else if tag == ATOM_EXT {
            let len = self.eat_u16_be()? as usize;
            self.atom(len)
        } else if tag == SMALL_ATOM_EXT {
            let len = self.eat_u8()? as usize;
            self.atom(len)
        } else if tag == ATOM_UTF8_EXT {
            let len = self.eat_u16_be()? as usize;
            self.atom_utf8(len)
        } else if tag == SMALL_ATOM_UTF8_EXT {
            let len = self.eat_u8()? as usize;
            self.atom_utf8(len)
        } else if tag == SMALL_TUPLE_EXT {
            let len = self.eat_u8()? as usize;
            self.tuple(len)
        } else if tag == LARGE_TUPLE_EXT {
            let len = self.eat_u32_be()? as usize;
            self.tuple(len)
        } else if tag == NIL_EXT {
            Ok(BertTerm::List(vec![]))
        } else if tag == LIST_EXT {
            self.list()
        } else if tag == STRING_EXT {
            self.string()
        } else if tag == BINARY_EXT {
            self.binary()
        } else if tag == SMALL_BIG_EXT {
            let len = self.eat_u8()?;
            self.bigint(len as usize)
        } else if tag == LARGE_BIG_EXT {
            let len = self.eat_u32_be()?;
            self.bigint(len as usize)
        } else {
            Err(BertError::InvalidTag(offset, tag))
        }
    }

    fn small_integer(&mut self) -> Result<BertTerm> {
        let b = self.eat_u8()?;
        Ok(BertTerm::Int(b as i32))
    }

    fn integer(&mut self) -> Result<BertTerm> {
        let n = self.eat_i32_be()?;
        Ok(BertTerm::Int(n))
    }

    fn old_float(&mut self) -> Result<BertTerm> {
        let offset = self.pos;
        let mut s = String::new();
        while !self.eof() && self.peek()? != 0 {
            s.push(self.eat_char()?);
        }

        while !self.eof() && self.peek()? == 0 {
            let _ = self.eat_u8()?;
        }

        s.parse::<f64>()
            .map_err(|_| BertError::InvalidFloat(offset))
            .map(|f| BertTerm::Float(f))
    }

    fn new_float(&mut self) -> Result<BertTerm> {
        let raw_bytes = self.eat_u64_be()?;
        let f: f64 = unsafe { mem::transmute(raw_bytes) };
        Ok(BertTerm::Float(f))
    }

    fn atom(&mut self, len: usize) -> Result<BertTerm> {
        let offset = self.pos;
        let mut bytes: Vec<u8> = Vec::with_capacity(len);
        for _ in 0 .. len {
            bytes.push(self.eat_u8()?);
        }
        ISO_8859_1.decode(&bytes, DecoderTrap::Strict)
            .map(|s| BertTerm::Atom(s))
            .map_err(|_| BertError::InvalidLatin1Atom(offset))
    }

    fn atom_utf8(&mut self, len: usize) -> Result<BertTerm> {
        let offset = self.pos;
        let mut buf = Vec::with_capacity(len);
        for _ in 0 .. len {
            buf.push(self.eat_u8()?);
        }
        String::from_utf8(buf)
            .map(|s| BertTerm::Atom(s))
            .map_err(|_| BertError::InvalidUTF8Atom(offset))
    }

    fn tuple(&mut self, len: usize) -> Result<BertTerm> {
        let mut terms = Vec::with_capacity(len);
        for _ in 0 .. len {
            terms.push(self.bert_term()?);
        }
        Ok(BertTerm::Tuple(terms))
    }

    fn string(&mut self) -> Result<BertTerm> {
        let len = self.eat_u16_be()?;
        let mut bytes = Vec::with_capacity(len as usize);
        for _ in 0 .. len {
            bytes.push(self.eat_u8()?);
        }
        Ok(BertTerm::String(bytes))
    }

    fn binary(&mut self) -> Result<BertTerm> {
        let len = self.eat_u32_be()?;
        let mut bytes = Vec::with_capacity(len as usize);
        for _ in 0 .. len {
            bytes.push(self.eat_u8()?);
        }
        Ok(BertTerm::Binary(bytes))
    }

    fn list(&mut self) -> Result<BertTerm> {
        let len = self.eat_u32_be()?;
        let mut terms = Vec::with_capacity(len as usize + 1);
        for _ in 0 .. len {
            terms.push(self.bert_term()?);
        }
        let tail = self.bert_term()?;
        match tail {
            BertTerm::List(_) => (),
            last_term => { terms.push(last_term); }
        };
        Ok(BertTerm::List(terms))
    }

    fn bigint(&mut self, len: usize) -> Result<BertTerm> {
        let sign = self.eat_u8()?;
        let mut sum: bigint::BigInt = Zero::zero();
        let mut pos: bigint::BigInt = One::one();
        for _ in 0 .. len {
            let d = self.eat_u8()?;
            let t = &pos * &(d.to_bigint().unwrap());
            sum = sum + &t;
            pos = pos * (256).to_bigint().unwrap();
        }
        if sign == 1 {
            sum = -sum;
        }
        Ok(BertTerm::BigInt(sum))
    }

    // Low-level parsing methods
    fn eof(&self) -> bool {
        self.pos >= self.contents.len()
    }

    fn peek(&self) -> Result<u8> {
        self.peek_at(self.pos)
    }

    fn peek_at(&self, offset: usize) -> Result<u8> {
        if self.eof() {
            return Err(BertError::EOF(offset));
        } else {
            return Ok(self.contents[offset]);
        }
    }

    fn eat_u8(&mut self) -> Result<u8> {
        let b = self.peek()?;
        self.pos += 1;
        return Ok(b);
    }

    fn eat_char(&mut self) -> Result<char> {
        let b = self.eat_u8()?;
        return Ok(b as char);
    }

    fn eat_u16_be(&mut self) -> Result<u16> {
        let b0 = self.eat_u8()? as u16;
        let b1 = self.eat_u8()? as u16;
        return Ok((b0 << 8) + b1)
    }

    fn eat_i32_be(&mut self) -> Result<i32> {
        let b0 = self.eat_u8()? as i32;
        let b1 = self.eat_u8()? as i32;
        let b2 = self.eat_u8()? as i32;
        let b3 = self.eat_u8()? as i32;
        return Ok((b0 << 24) + (b1 << 16) + (b2 << 8) + b3)
    }

    fn eat_u32_be(&mut self) -> Result<u32> {
        let b0 = self.eat_u8()? as u32;
        let b1 = self.eat_u8()? as u32;
        let b2 = self.eat_u8()? as u32;
        let b3 = self.eat_u8()? as u32;
        return Ok((b0 << 24) + (b1 << 16) + (b2 << 8) + b3)
    }

    fn eat_u64_be(&mut self) -> Result<u64> {
        let mut n: u64 = 0;
        n += (self.eat_u8()? as u64) << 56;
        n += (self.eat_u8()? as u64) << 48;
        n += (self.eat_u8()? as u64) << 40;
        n += (self.eat_u8()? as u64) << 32;
        n += (self.eat_u8()? as u64) << 24;
        n += (self.eat_u8()? as u64) << 16;
        n += (self.eat_u8()? as u64) << 8;
        n += self.eat_u8()? as u64;
        return Ok(n);
    }
}
<commit_msg>Replace position comparison with eof() call<commit_after>use std::mem;

use num::bigint;
use num::bigint::ToBigInt;
use num::traits::{Zero, One};

use encoding::{Encoding, DecoderTrap};
use encoding::all::ISO_8859_1;

use bertterm::BertTerm;
use error::{Result, BertError};

static BERT_MAGIC_NUMBER: u8 = 131;
static SMALL_INTEGER_EXT: u8 = 97;
static INTEGER_EXT: u8 = 98;
static FLOAT_EXT: u8 = 99;
static ATOM_EXT: u8 = 100;
static SMALL_ATOM_EXT: u8 = 115;
static SMALL_TUPLE_EXT: u8 = 104;
static LARGE_TUPLE_EXT: u8 = 105;
static NIL_EXT: u8 = 106;
static STRING_EXT: u8 = 107;
static LIST_EXT: u8 = 108;
static BINARY_EXT: u8 = 109;
static SMALL_BIG_EXT: u8 = 110;
static LARGE_BIG_EXT: u8 = 111;
static ATOM_UTF8_EXT: u8 = 118;
static SMALL_ATOM_UTF8_EXT: u8 = 119;
static NEW_FLOAT_EXT: u8 = 70;

#[derive(Debug)]
pub struct Parser {
    contents: Vec<u8>,
    pos: usize,
}

impl Parser {
    pub fn new(contents: Vec<u8>) -> Parser {
        Parser { contents: contents, pos: 0 }
    }

    pub fn parse(&mut self) -> Result<BertTerm> {
        let () = self.magic_number()?;
        let term = self.bert_term()?;
        if self.eof() {
            return Ok(term);
        } else {
            return Err(BertError::ExtraData(self.pos));
        }
    }

    // Parsers
    fn magic_number(&mut self) -> Result<()> {
        let offset = self.pos;
        let magic = self.eat_u8()?;
        if magic != BERT_MAGIC_NUMBER {
            return Err(BertError::InvalidMagicNumber(offset));
        } else {
            return Ok(());
        }
    }

    fn bert_term(&mut self) -> Result<BertTerm> {
        let offset = self.pos;
        let tag = self.eat_u8()?;
        if tag == SMALL_INTEGER_EXT {
            self.small_integer()
        } else if tag == INTEGER_EXT {
            self.integer()
        } else if tag == FLOAT_EXT {
            self.old_float()
        } else if tag == NEW_FLOAT_EXT {
            self.new_float()
        } else if tag == ATOM_EXT {
            let len = self.eat_u16_be()? as usize;
            self.atom(len)
        } else if tag == SMALL_ATOM_EXT {
            let len = self.eat_u8()? as usize;
            self.atom(len)
        } else if tag == ATOM_UTF8_EXT {
            let len = self.eat_u16_be()? as usize;
            self.atom_utf8(len)
        } else if tag == SMALL_ATOM_UTF8_EXT {
            let len = self.eat_u8()? as usize;
            self.atom_utf8(len)
        } else if tag == SMALL_TUPLE_EXT {
            let len = self.eat_u8()? as usize;
            self.tuple(len)
        } else if tag == LARGE_TUPLE_EXT {
            let len = self.eat_u32_be()? as usize;
            self.tuple(len)
        } else if tag == NIL_EXT {
            Ok(BertTerm::List(vec![]))
        } else if tag == LIST_EXT {
            self.list()
        } else if tag == STRING_EXT {
            self.string()
        } else if tag == BINARY_EXT {
            self.binary()
        } else if tag == SMALL_BIG_EXT {
            let len = self.eat_u8()?;
            self.bigint(len as usize)
        } else if tag == LARGE_BIG_EXT {
            let len = self.eat_u32_be()?;
            self.bigint(len as usize)
        } else {
            Err(BertError::InvalidTag(offset, tag))
        }
    }

    fn small_integer(&mut self) -> Result<BertTerm> {
        let b = self.eat_u8()?;
        Ok(BertTerm::Int(b as i32))
    }

    fn integer(&mut self) -> Result<BertTerm> {
        let n = self.eat_i32_be()?;
        Ok(BertTerm::Int(n))
    }

    fn old_float(&mut self) -> Result<BertTerm> {
        let offset = self.pos;
        let mut s = String::new();
        while !self.eof() && self.peek()? != 0 {
            s.push(self.eat_char()?);
        }

        while !self.eof() && self.peek()? == 0 {
            let _ = self.eat_u8()?;
        }

        s.parse::<f64>()
            .map_err(|_| BertError::InvalidFloat(offset))
            .map(|f| BertTerm::Float(f))
    }

    fn new_float(&mut self) -> Result<BertTerm> {
        let raw_bytes = self.eat_u64_be()?;
        let f: f64 = unsafe { mem::transmute(raw_bytes) };
        Ok(BertTerm::Float(f))
    }

    fn atom(&mut self, len: usize) -> Result<BertTerm> {
        let offset = self.pos;
        let mut bytes: Vec<u8> = Vec::with_capacity(len);
        for _ in 0 .. len {
            bytes.push(self.eat_u8()?);
        }
        ISO_8859_1.decode(&bytes, DecoderTrap::Strict)
            .map(|s| BertTerm::Atom(s))
            .map_err(|_| BertError::InvalidLatin1Atom(offset))
    }

    fn atom_utf8(&mut self, len: usize) -> Result<BertTerm> {
        let offset = self.pos;
        let mut buf = Vec::with_capacity(len);
        for _ in 0 .. len {
            buf.push(self.eat_u8()?);
        }
        String::from_utf8(buf)
            .map(|s| BertTerm::Atom(s))
            .map_err(|_| BertError::InvalidUTF8Atom(offset))
    }

    fn tuple(&mut self, len: usize) -> Result<BertTerm> {
        let mut terms = Vec::with_capacity(len);
        for _ in 0 .. len {
            terms.push(self.bert_term()?);
        }
        Ok(BertTerm::Tuple(terms))
    }

    fn string(&mut self) -> Result<BertTerm> {
        let len = self.eat_u16_be()?;
        let mut bytes = Vec::with_capacity(len as usize);
        for _ in 0 .. len {
            bytes.push(self.eat_u8()?);
        }
        Ok(BertTerm::String(bytes))
    }

    fn binary(&mut self) -> Result<BertTerm> {
        let len = self.eat_u32_be()?;
        let mut bytes = Vec::with_capacity(len as usize);
        for _ in 0 .. len {
            bytes.push(self.eat_u8()?);
        }
        Ok(BertTerm::Binary(bytes))
    }

    fn list(&mut self) -> Result<BertTerm> {
        let len = self.eat_u32_be()?;
        let mut terms = Vec::with_capacity(len as usize + 1);
        for _ in 0 .. len {
            terms.push(self.bert_term()?);
        }
        let tail = self.bert_term()?;
        match tail {
            BertTerm::List(_) => (),
            last_term => { terms.push(last_term); }
        };
        Ok(BertTerm::List(terms))
    }

    fn bigint(&mut self, len: usize) -> Result<BertTerm> {
        let sign = self.eat_u8()?;
        let mut sum: bigint::BigInt = Zero::zero();
        let mut pos: bigint::BigInt = One::one();
        for _ in 0 .. len {
            let d = self.eat_u8()?;
            let t = &pos * &(d.to_bigint().unwrap());
            sum = sum + &t;
            pos = pos * (256).to_bigint().unwrap();
        }
        if sign == 1 {
            sum = -sum;
        }
        Ok(BertTerm::BigInt(sum))
    }

    // Low-level parsing methods
    fn eof(&self) -> bool {
        self.pos >= self.contents.len()
    }

    fn peek(&self) -> Result<u8> {
        self.peek_at(self.pos)
    }

    fn peek_at(&self, offset: usize) -> Result<u8> {
        if self.eof() {
            return Err(BertError::EOF(offset));
        } else {
            return Ok(self.contents[offset]);
        }
    }

    fn eat_u8(&mut self) -> Result<u8> {
        let b = self.peek()?;
        self.pos += 1;
        return Ok(b);
    }

    fn eat_char(&mut self) -> Result<char> {
        let b = self.eat_u8()?;
        return Ok(b as char);
    }

    fn eat_u16_be(&mut self) -> Result<u16> {
        let b0 = self.eat_u8()? as u16;
        let b1 = self.eat_u8()? as u16;
        return Ok((b0 << 8) + b1)
    }

    fn eat_i32_be(&mut self) -> Result<i32> {
        let b0 = self.eat_u8()? as i32;
        let b1 = self.eat_u8()? as i32;
        let b2 = self.eat_u8()? as i32;
        let b3 = self.eat_u8()? as i32;
        return Ok((b0 << 24) + (b1 << 16) + (b2 << 8) + b3)
    }

    fn eat_u32_be(&mut self) -> Result<u32> {
        let b0 = self.eat_u8()? as u32;
        let b1 = self.eat_u8()? as u32;
        let b2 = self.eat_u8()? as u32;
        let b3 = self.eat_u8()? as u32;
        return Ok((b0 << 24) + (b1 << 16) + (b2 << 8) + b3)
    }

    fn eat_u64_be(&mut self) -> Result<u64> {
        let mut n: u64 = 0;
        n += (self.eat_u8()? as u64) << 56;
        n += (self.eat_u8()? as u64) << 48;
        n += (self.eat_u8()? as u64) << 40;
        n += (self.eat_u8()? as u64) << 32;
        n += (self.eat_u8()? as u64) << 24;
        n += (self.eat_u8()? as u64) << 16;
        n += (self.eat_u8()? as u64) << 8;
        n += self.eat_u8()? as u64;
        return Ok(n);
    }
}
<|endoftext|>


<commit_before>
use ast::ExprAst;
use ast::BoolNode;
use ast::CharNode;
use ast::IntNode;
use ast::StrNode;
use ast::EmptyListNode;

use ast::Ast;

#[deriving(Clone, Show)]
pub struct Parser {
    code: String,
    cur: uint,
    col: uint,
    line: uint
}

#[allow(dead_code)]
pub struct ParserError {
    line: uint,
    col: uint,
    desc: String
}

#[allow(dead_code)]
impl ParserError {
    pub fn new(line: uint, col: uint, desc: String) -> ParserError {
        ParserError {
            line: line,
            col: col,
            desc: desc
        }
    }
}

#[allow(dead_code)]
pub type ParseResult<T> = Result<T, ParserError>;

#[allow(dead_code)]
impl Parser {
    pub fn new() -> Parser {
        Parser{
            code: "".to_string(),
            line: 0,
            cur: 0,
            col: 0
        }
    }

    pub fn load(&mut self, code: String) -> ExprAst {
        self.code = code;
        self.line = 1;
        self.cur = 0;
        self.col = 0;
        self.skip_space();

        let mut cur = self.readc();
        if cur == '#' {
            let next = self.readc();
            match next {
                't' => return ExprAst::Bool(BoolNode::new(true)),
                'f' => return ExprAst::Bool(BoolNode::new(false)),
                '\\' => return self.read_char(),
                _ => panic!("error")
            }
        } else if UnicodeChar::is_numeric(cur) ||
            (cur == '-' && (UnicodeChar::is_numeric(self.peekc()))) {
                let mut sign = 1i;
                let mut num = 0i;
                if cur == '-' {
                    sign = -1;
                } else {
                    self.unread();
                }
                loop {
                    cur = self.readc();
                    if !UnicodeChar::is_numeric(cur) {
                        break;
                    }
                    num = (num * 10i) + (cur as int - '0' as int);
                }
                num *= sign;
                if self.is_delimiter(cur) {
                    self.unread();
                    return ExprAst::Int(IntNode::new(num));
                } else {
                    panic!("number not followed by delimiter");
                }
            } else if cur == '\"' {
                let mut buf = String::new();
                loop {
                    cur = self.readc();
                    if cur == '\"' {
                        break;
                    }
                    buf.push(cur);
                }
                return ExprAst::Str(StrNode::new(buf));
            } else if cur == '(' && cur != ')' {
                return self.read_pair();
            }
        ExprAst::Char(CharNode::new('a'))
    }

    //============= private methods =================

    fn read_pair(&mut self) -> ExprAst {
        self.skip_space();
        let cur = self.readc();
        if cur != '(' && cur == ')' {
            return ExprAst::EmptyList(EmptyListNode::new());
        }
        self.unread();
        //let car_obj = self.read()
        return ExprAst::EmptyList(EmptyListNode::new());
    }

    fn is_delimiter(&self, ch: char) -> bool {
        ch.is_whitespace() ||
            ch == '\"' || ch == '(' || ch == ')' ||  ch == ';' ||
            (ch as u32 == 0)
    }

    fn is_initial(&self, ch: char) -> bool {
        ch.is_alphabetic() ||
            ch == '*' || ch == '/' || ch == '+' || ch == '-' ||
            ch == '>' || ch == '<' || ch == '=' || ch == '?' ||
            ch == '!'
    }

    fn skip_space(&mut self) {
        while self.peekc().is_whitespace() {
            self.readc();
        }
    }

    fn peekc(&self) -> char {
        if self.cur >= self.code.len() {
            panic!("invalid position");
        }
        self.code.char_at(self.cur)
    }

    fn prevc(&self) -> char {
        if self.cur <= 0 {
            panic!("invalid position");
        }
        self.code.char_at(self.cur - 1)
    }

    fn readc(&mut self) -> char {
        if self.cur < self.code.len() {
            let res = self.peekc();
            if res == '\n' {
                self.line += 1;
            }
            self.cur += 1;
            res
        } else {
            0 as char
        }
    }

    fn unread(&mut self) {
        if self.cur == 0 {
            panic!("error current position");
        }
        if self.prevc() == '\n' {
            assert!(self.line > 1);
            self.line -= 1;
        }
        self.cur -= 1;
    }

    fn read_char(&mut self) -> ExprAst {
        ExprAst::Char(CharNode::new('a'))
    }
}

#[test]
fn test_parser() {
    let mut parser = Parser::new();
    let res = parser.load("11".to_string());
    assert!(res.as_int() == 11);
    res.print();

    let res = parser.load("-11".to_string());
    assert!(res.as_int() == -11);
    res.print();

    let res = parser.load(r#""hello""#.to_string());
    assert!(res.as_str() == "hello");
    res.print();

    let res = parser.load("()".to_string());
    assert!(res.is_empty_list());
    res.print();
}
<commit_msg>more on parser<commit_after>
use ast::ExprAst;
use ast::BoolNode;
use ast::CharNode;
use ast::IntNode;
use ast::StrNode;
use ast::EmptyListNode;

use ast::Ast;

#[deriving(Clone, Show)]
pub struct Parser {
    code: String,
    cur: uint,
    col: uint,
    line: uint
}

#[allow(dead_code)]
pub struct ParserError {
    line: uint,
    col: uint,
    desc: String
}

#[allow(dead_code)]
impl ParserError {
    pub fn new(line: uint, col: uint, desc: String) -> ParserError {
        ParserError {
            line: line,
            col: col,
            desc: desc
        }
    }
}

#[allow(dead_code)]
pub type ParseResult<T> = Result<T, ParserError>;

#[allow(dead_code)]
impl Parser {
    pub fn new() -> Parser {
        Parser{
            code: "".to_string(),
            line: 0,
            cur: 0,
            col: 0
        }
    }

    pub fn load(&mut self, code: String) -> ExprAst {
        self.code = code;
        self.line = 1;
        self.cur = 0;
        self.col = 0;
        self.skip_space();
        self.read_exp()
    }

    //============= private methods =================
    fn read_exp(&mut self) -> ExprAst {
        let mut cur = self.readc();
        if cur == '#' {
            let next = self.readc();
            match next {
                't' => return ExprAst::Bool(BoolNode::new(true)),
                'f' => return ExprAst::Bool(BoolNode::new(false)),
                '\\' => return self.read_char(),
                _ => panic!("error")
            }
        } else if UnicodeChar::is_numeric(cur) ||
            (cur == '-' && (UnicodeChar::is_numeric(self.peekc()))) {
                let mut sign = 1i;
                let mut num = 0i;
                if cur == '-' {
                    sign = -1;
                } else {
                    self.unread();
                }
                loop {
                    cur = self.readc();
                    if !UnicodeChar::is_numeric(cur) {
                        break;
                    }
                    num = (num * 10i) + (cur as int - '0' as int);
                }
                num *= sign;
                if self.is_delimiter(cur) {
                    self.unread();
                    return ExprAst::Int(IntNode::new(num));
                } else {
                    panic!("number not followed by delimiter");
                }
            } else if cur == '\"' {
                let mut buf = String::new();
                loop {
                    cur = self.readc();
                    if cur == '\"' {
                        break;
                    }
                    buf.push(cur);
                }
                return ExprAst::Str(StrNode::new(buf));
            } else if cur == '(' && cur != ')' {
                return self.read_pair();
            }
        ExprAst::Char(CharNode::new('a'))
    }

    fn read_pair(&mut self) -> ExprAst {
        self.skip_space();
        let cur = self.readc();
        if cur == ')' {
            return ExprAst::EmptyList(EmptyListNode::new());
        }
        self.unread();
        //let car_obj = self.read()
        return ExprAst::EmptyList(EmptyListNode::new());
    }

    fn is_delimiter(&self, ch: char) -> bool {
        ch.is_whitespace() ||
            ch == '\"' || ch == '(' || ch == ')' ||  ch == ';' ||
            (ch as u32 == 0)
    }

    fn is_initial(&self, ch: char) -> bool {
        ch.is_alphabetic() ||
            ch == '*' || ch == '/' || ch == '+' || ch == '-' ||
            ch == '>' || ch == '<' || ch == '=' || ch == '?' ||
            ch == '!'
    }

    fn skip_space(&mut self) {
        while self.peekc().is_whitespace() {
            self.readc();
        }
    }

    fn peekc(&self) -> char {
        if self.cur >= self.code.len() {
            panic!("invalid position");
        }
        self.code.char_at(self.cur)
    }

    fn prevc(&self) -> char {
        if self.cur <= 0 {
            panic!("invalid position");
        }
        self.code.char_at(self.cur - 1)
    }

    fn readc(&mut self) -> char {
        if self.cur < self.code.len() {
            let res = self.peekc();
            if res == '\n' {
                self.line += 1;
            }
            self.cur += 1;
            res
        } else {
            0 as char
        }
    }

    fn unread(&mut self) {
        if self.cur == 0 {
            panic!("error current position");
        }
        if self.prevc() == '\n' {
            assert!(self.line > 1);
            self.line -= 1;
        }
        self.cur -= 1;
    }

    fn read_char(&mut self) -> ExprAst {
        ExprAst::Char(CharNode::new('a'))
    }
}

#[test]
fn test_parser() {
    let mut parser = Parser::new();
    let res = parser.load("11".to_string());
    assert!(res.as_int() == 11);
    res.print();

    let res = parser.load("-11".to_string());
    assert!(res.as_int() == -11);
    res.print();

    let res = parser.load(r#""hello""#.to_string());
    assert!(res.as_str() == "hello");
    res.print();

    let res = parser.load("()".to_string());
    assert!(res.is_empty_list());
    res.print();
}
<|endoftext|>


<commit_before>use ::*;

fn out<S: ToString>(screen : &mut RawTerminal<Stdout>, output : S) {
    write!(*screen, "{}", output.to_string()).unwrap();
}

fn curs(screen : &mut RawTerminal<Stdout>, coord : Coord) {
    out(screen, termion::cursor::Goto(coord.col+1, coord.row+1));
}

fn color<C: Color>(screen : &mut RawTerminal<Stdout>, clr : C) {
    out(screen, Fg(clr));
}

pub fn render_loop(
    stop         : Arc<Mutex<bool>>,
    floor        : Arc<Mutex<Floor>>,
    player       : Arc<Mutex<Player>>,
    dirty_coords : Arc<Mutex<Vec<Coord>>>,
    messages     : Arc<Mutex<Vec<String>>>,
    monsters     : Arc<Mutex<Vec<Monster>>>,
) {
    let mut screen = &mut stdout().into_raw_mode().unwrap();
    out(screen, termion::cursor::Hide); // Hide the cursor
    out(screen, termion::clear::All);   // Clear the screen

    // Draw the entire floor
    curs(screen, Coord::new(0,0));
    {
        let floor = floor.lock().unwrap();
        for row in &floor.tiles {
            for tile in row {
                if let Some(ref wall) = tile.wall {
                    out(screen, wall);
                } else {
                    out(screen, " ");
                }
            }
            out(screen, "\r\n");
        }
    }

    // Render Loop
    loop {
        sleep(Duration::from_millis(10));
        {
            if *stop.lock().unwrap() {
                break;
            }
        }

        // Lock floor first...
        let floor = floor.lock().unwrap();

        // Redraw any dirty coordinates with floor tiles
        let mut dirty_coords = dirty_coords.lock().unwrap();
        for coord in dirty_coords.drain(..) {
            curs(screen, coord);
            out(screen, floor.get_symbol(&coord));
        }

        // Render Player
        let mut player = player.lock().unwrap();
        if player.dirty {
            player.dirty = false;
            // Player's sword
            curs(screen, player.sword_coord);
            color(screen, Red);
            out(screen, sword_symbol(player.facing));
            // Player himself
            curs(screen, player.coord);
            color(screen, Blue);
            out(screen, &player.symbol);
            color(screen, Reset);
        }
        // Player Score
        let score_string = format!("Score: {}", player.score);
        curs(screen, Coord::new((floor.cols - score_string.len()) as u16,
                                floor.rows as u16));
        out(screen, score_string);

        // Render Monsters
        {
            let monsters = monsters.lock().unwrap();
            for monster in monsters.iter() {
                curs(screen, monster.coord);
                color(screen, Green);
                out(screen, &monster.symbol);
                color(screen, Reset);
            }
        }

        // Game Title
        curs(screen, Coord::new(0, floor.rows as u16));
        out(screen, "Rusty Sword - Game of Infamy!");

        // Messages
        curs(screen, Coord::new(0, (floor.rows + 2) as u16));
        let mut messages = messages.lock().unwrap();
        if messages.len() > 4 {
            messages.remove(0);
        }
        for msg in messages.iter() {
            if msg.contains("spawned") {
                color(screen, Green);
            } else if msg.contains("You killed") {
                color(screen, Blue);
            } else if msg.contains("were eaten") {
                color(screen, Red);
            } else {
                color(screen, LightWhite);
            }
            out(screen, msg);
            out(screen, format!("{}\n\r", clear::UntilNewline));
            color(screen, Reset);
        }

        screen.flush().unwrap();
    }

    // Nice cleanup: Move cursor below the floor, so we can see how we finished
    {
        let floor = floor.lock().unwrap();
        curs(screen, Coord::new(0, (floor.rows+7) as u16));
    }
    out(screen, termion::cursor::Show); // Show the cursor again
    screen.flush().unwrap();
}

<commit_msg>Simplifying more<commit_after>use ::*;

fn out<S: ToString>(screen : &mut RawTerminal<Stdout>, output : S) {
    write!(*screen, "{}", output.to_string()).unwrap();
}

fn curs(screen : &mut RawTerminal<Stdout>, coord : Coord) {
    out(screen, termion::cursor::Goto(coord.col+1, coord.row+1));
}

pub fn render_loop(
    stop         : Arc<Mutex<bool>>,
    floor        : Arc<Mutex<Floor>>,
    player       : Arc<Mutex<Player>>,
    dirty_coords : Arc<Mutex<Vec<Coord>>>,
    messages     : Arc<Mutex<Vec<String>>>,
    monsters     : Arc<Mutex<Vec<Monster>>>,
) {
    let mut screen = &mut stdout().into_raw_mode().unwrap();
    out(screen, termion::cursor::Hide); // Hide the cursor
    out(screen, termion::clear::All);   // Clear the screen

    // Draw the entire floor
    curs(screen, Coord::new(0,0));
    {
        let floor = floor.lock().unwrap();
        for row in &floor.tiles {
            for tile in row {
                if let Some(ref wall) = tile.wall {
                    out(screen, wall);
                } else {
                    out(screen, " ");
                }
            }
            out(screen, "\r\n");
        }
    }

    // Render Loop
    loop {
        sleep(Duration::from_millis(10));
        {
            if *stop.lock().unwrap() {
                break;
            }
        }

        // Lock floor first...
        let floor = floor.lock().unwrap();

        // Redraw any dirty coordinates with floor tiles
        let mut dirty_coords = dirty_coords.lock().unwrap();
        for coord in dirty_coords.drain(..) {
            curs(screen, coord);
            out(screen, floor.get_symbol(&coord));
        }

        // Render Player
        let mut player = player.lock().unwrap();
        if player.dirty {
            player.dirty = false;
            // Player's sword
            curs(screen, player.sword_coord);
            out(screen, Fg(Red));
            out(screen, sword_symbol(player.facing));
            // Player himself
            curs(screen, player.coord);
            out(screen, Fg(Blue));
            out(screen, &player.symbol);
            out(screen, Fg(Reset));
        }
        // Player Score
        let score_string = format!("Score: {}", player.score);
        curs(screen, Coord::new((floor.cols - score_string.len()) as u16,
                                floor.rows as u16));
        out(screen, score_string);

        // Render Monsters
        {
            let monsters = monsters.lock().unwrap();
            for monster in monsters.iter() {
                curs(screen, monster.coord);
                out(screen, Fg(Green));
                out(screen, &monster.symbol);
                out(screen, Fg(Reset));
            }
        }

        // Game Title
        curs(screen, Coord::new(0, floor.rows as u16));
        out(screen, "Rusty Sword - Game of Infamy!");

        // Messages
        curs(screen, Coord::new(0, (floor.rows + 2) as u16));
        let mut messages = messages.lock().unwrap();
        if messages.len() > 4 {
            messages.remove(0);
        }
        for msg in messages.iter() {
            if msg.contains("spawned") {
                out(screen, Fg(Green));
            } else if msg.contains("You killed") {
                out(screen, Fg(Blue));
            } else if msg.contains("were eaten") {
                out(screen, Fg(Red));
            } else {
                out(screen, Fg(LightWhite));
            }
            out(screen, msg);
            out(screen, format!("{}\n\r", clear::UntilNewline));
            out(screen, Fg(Reset));
        }

        screen.flush().unwrap();
    }

    // Nice cleanup: Move cursor below the floor, so we can see how we finished
    {
        let floor = floor.lock().unwrap();
        curs(screen, Coord::new(0, (floor.rows+7) as u16));
    }
    out(screen, termion::cursor::Show); // Show the cursor again
    screen.flush().unwrap();
}

<|endoftext|>


<commit_before>use std::path:: { Path, PathBuf };
use std::fmt:: { Display, Formatter, Result };
use coverage:: { Coverage };

#[derive(Debug)]
pub struct Report {
    files: Vec<FileResult>
}

impl Report {
    pub fn new(files: Vec<FileResult>) -> Self {
        Report { files: files }
    }
    pub fn files(&self) -> Vec<FileResult> {
        self.files.to_vec()
    }
    pub fn sorted_files(&self) -> Vec<FileResult> {
        let mut files = self.files();
        files.sort_by(|a, b| { b.coverage.partial_cmp(&a.coverage).unwrap() });
        files
    }
}

#[derive(Debug, Clone)]
pub struct FileResult {
    path: PathBuf,
    coverage: Coverage
}

impl FileResult {
    pub fn new<P: AsRef<Path>>(path: P, coverage: Coverage) -> Self {
        FileResult { path: path.as_ref().to_path_buf(), coverage: coverage }
    }
    pub fn coverage(&self) -> &Coverage {
        &self.coverage
    }
}

impl Display for FileResult {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "{} {}", self.coverage(), self.path.display())
    }
}

#[cfg(test)]
mod tests {
    use report:: { Report, FileResult };
    use coverage:: { Coverage };

    #[test]
    fn test_sorted_files() {
        let report = Report::new(vec!(
            FileResult::new("test1.rs", Coverage::new(0.1)),
            FileResult::new("test2.rs", Coverage::new(0.2)),
            FileResult::new("test3.rs", Coverage::new(0.3))
        ));
        let files = report.sorted_files();

        assert_eq!(&Coverage::new(0.3), files.get(0).unwrap().coverage());
        assert_eq!(&Coverage::new(0.2), files.get(1).unwrap().coverage());
        assert_eq!(&Coverage::new(0.1), files.get(2).unwrap().coverage());
    }

    #[test]
    fn test_display_file_result() {
        let result = FileResult::new("test1.rs", Coverage::new(0.1));
        println!("{}", result);
    }
}
<commit_msg>impl display trait<commit_after>use std::path:: { Path, PathBuf };
use std::fmt:: { Display, Formatter, Result };
use coverage:: { Coverage };

#[derive(Debug)]
pub struct Report {
    files: Vec<FileResult>
}

impl Report {
    pub fn new(files: Vec<FileResult>) -> Self {
        Report { files: files }
    }
    pub fn files(&self) -> Vec<FileResult> {
        self.files.to_vec()
    }
    pub fn sorted_files(&self) -> Vec<FileResult> {
        let mut files = self.files();
        files.sort_by(|a, b| { b.coverage.partial_cmp(&a.coverage).unwrap() });
        files
    }
}

impl Display for Report {
    fn fmt(&self, f: &mut Formatter) -> Result {
        for file in self.sorted_files().iter() {
            let _ = try!(write!(f, "{}", file));
        }
        Ok(())
    }
}

#[derive(Debug, Clone)]
pub struct FileResult {
    path: PathBuf,
    coverage: Coverage
}

impl FileResult {
    pub fn new<P: AsRef<Path>>(path: P, coverage: Coverage) -> Self {
        FileResult { path: path.as_ref().to_path_buf(), coverage: coverage }
    }
    pub fn coverage(&self) -> &Coverage {
        &self.coverage
    }
}

impl Display for FileResult {
    fn fmt(&self, f: &mut Formatter) -> Result {
        writeln!(f, "{} {}", self.coverage(), self.path.display())
    }
}

#[cfg(test)]
mod tests {
    use report:: { Report, FileResult };
    use coverage:: { Coverage };

    #[test]
    fn test_sorted_files() {
        let report = Report::new(vec!(
            FileResult::new("test1.rs", Coverage::new(0.1)),
            FileResult::new("test2.rs", Coverage::new(0.2)),
            FileResult::new("test3.rs", Coverage::new(0.3))
        ));
        let files = report.sorted_files();

        assert_eq!(&Coverage::new(0.3), files.get(0).unwrap().coverage());
        assert_eq!(&Coverage::new(0.2), files.get(1).unwrap().coverage());
        assert_eq!(&Coverage::new(0.1), files.get(2).unwrap().coverage());
    }

    #[test]
    fn test_display_file_result() {
        let result = FileResult::new("test1.rs", Coverage::new(0.1));
        println!("{}", result);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The Rouille developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

/// Equivalent to a `match` expression but for routes.
///
/// Here is an example usage:
///
/// ```ignored      // FIXME:
/// # #[macro_use] extern crate rouille; fn main() {
/// # let request: rouille::Request = unsafe { std::mem::uninitialized() };
/// router!(request,
///     // first route
///     (GET) (/) => {
///         12
///     },
///
///     // ... other routes here ...
///
///     // default route
///     _ => 5
/// )
/// # }
/// ```
///
/// The macro will take each route one by one and execute the first one that matches, similar to a
/// `match` language construct. The whole `router!` expression then returns what the closure
/// returns, therefore they must all return the same type.
///
/// You can use parameters by putting them inside `{}`:
///
/// ```ignore
/// (GET) (/{id}/foo) => {
///     ...
/// },
/// ```
///
/// If you use parameters inside `{}`, then a field with the same name must exist in the closure's
/// parameters list. The parameters do not need be in the same order.
///
/// Each parameter gets parsed through the `FromStr` trait. If the parsing fails, the route is
/// ignored. If you get an error because the type of the parameter couldn't be inferred, you can
/// also specify the type inside the brackets:
///
/// ```ignore
/// (GET) (/{id: u32}/foo) => {
///     ...
/// },
/// ```
///
/// Some other things to note:
///
/// - The right of the `=>` must be a block (must be surrounded by `{` and `}`).
/// - The pattern of the URL and the closure must be inside parentheses. This is to bypass
///   limitations of Rust's macros system.
/// - The default handler (with `_`) must be present or will get a compilation error.
///
// FIXME: turn `: $pt:ident` into `ty`
// TODO: don't panic if parsing fails
#[macro_export]
macro_rules! router {
    ($request:expr, $(($method:ident) ($($pat:tt)+) => $value:block,)* _ => $def:expr) => {
        {
            let ref request = $request;

            // ignoring the GET parameters (everything after `?`)
            let request_url = request.url();
            let request_url = {
                let pos = request_url.find('?').unwrap_or(request_url.len());
                &request_url[..pos]
            };

            let mut ret = None;

            $({
                if ret.is_none() && request.method() == stringify!($method) {
                    ret = router!(__check_pattern request_url $value $($pat)+);
                }
            })+

            if let Some(ret) = ret {
                ret
            } else {
                $def
            }
        }
    };

    (__check_pattern $url:ident $value:block /{$p:ident} $($rest:tt)*) => (
        if !$url.starts_with('/') {
            None
        } else {
            let url = &$url[1..];
            let pat_end = url.find('/').unwrap_or(url.len());
            let rest_url = &url[pat_end..];

            if let Some($p) = url[0 .. pat_end].parse().ok() {
                router!(__check_pattern rest_url $value $($rest)*)
            } else {
                None
            }
        }
    );

    (__check_pattern $url:ident $value:block /{$p:ident: $t:ty} $($rest:tt)*) => (
        if !$url.starts_with('/') {
            None
        } else {
            let url = &$url[1..];
            let pat_end = url.find('/').unwrap_or(url.len());
            let rest_url = &url[pat_end..];

            if let Some($p) = url[0 .. pat_end].parse().ok() {
                let $p: $t = $p;
                router!(__check_pattern rest_url $value $($rest)*)
            } else {
                None
            }
        }
    );

    (__check_pattern $url:ident $value:block /$p:ident $($rest:tt)*) => (
        {
            let required = concat!("/", stringify!($p));
            if $url.starts_with(required) {
                let rest_url = &$url[required.len()..];
                router!(__check_pattern rest_url $value $($rest)*)
            } else {
                None
            }
        }
    );

    (__check_pattern $url:ident $value:block) => (
        if $url.len() == 0 { Some($value) } else { None }
    );

    (__check_pattern $url:ident $value:block /) => (
        if $url == "/" { Some($value) } else { None }
    );
}
<commit_msg>Fix doctest in router.rs<commit_after>// Copyright (c) 2016 The Rouille developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

/// Equivalent to a `match` expression but for routes.
///
/// Here is an example usage:
///
/// ```no_run
/// # #[macro_use] extern crate rouille; fn main() {
/// # let request: rouille::Request = unsafe { std::mem::uninitialized() };
/// let _result = router!(request,
///     // first route
///     (GET) (/) => {
///         12
///     },
///
///     // ... other routes here ...
///
///     // default route
///     _ => 5
/// );
/// # }
/// ```
///
/// The macro will take each route one by one and execute the first one that matches, similar to a
/// `match` language construct. The whole `router!` expression then returns what the closure
/// returns, therefore they must all return the same type.
///
/// You can use parameters by putting them inside `{}`:
///
/// ```ignore
/// (GET) (/{id}/foo) => {
///     ...
/// },
/// ```
///
/// If you use parameters inside `{}`, then a field with the same name must exist in the closure's
/// parameters list. The parameters do not need be in the same order.
///
/// Each parameter gets parsed through the `FromStr` trait. If the parsing fails, the route is
/// ignored. If you get an error because the type of the parameter couldn't be inferred, you can
/// also specify the type inside the brackets:
///
/// ```ignore
/// (GET) (/{id: u32}/foo) => {
///     ...
/// },
/// ```
///
/// Some other things to note:
///
/// - The right of the `=>` must be a block (must be surrounded by `{` and `}`).
/// - The pattern of the URL and the closure must be inside parentheses. This is to bypass
///   limitations of Rust's macros system.
/// - The default handler (with `_`) must be present or will get a compilation error.
///
// FIXME: turn `: $pt:ident` into `ty`
// TODO: don't panic if parsing fails
#[macro_export]
macro_rules! router {
    ($request:expr, $(($method:ident) ($($pat:tt)+) => $value:block,)* _ => $def:expr) => {
        {
            let ref request = $request;

            // ignoring the GET parameters (everything after `?`)
            let request_url = request.url();
            let request_url = {
                let pos = request_url.find('?').unwrap_or(request_url.len());
                &request_url[..pos]
            };

            let mut ret = None;

            $({
                if ret.is_none() && request.method() == stringify!($method) {
                    ret = router!(__check_pattern request_url $value $($pat)+);
                }
            })+

            if let Some(ret) = ret {
                ret
            } else {
                $def
            }
        }
    };

    (__check_pattern $url:ident $value:block /{$p:ident} $($rest:tt)*) => (
        if !$url.starts_with('/') {
            None
        } else {
            let url = &$url[1..];
            let pat_end = url.find('/').unwrap_or(url.len());
            let rest_url = &url[pat_end..];

            if let Some($p) = url[0 .. pat_end].parse().ok() {
                router!(__check_pattern rest_url $value $($rest)*)
            } else {
                None
            }
        }
    );

    (__check_pattern $url:ident $value:block /{$p:ident: $t:ty} $($rest:tt)*) => (
        if !$url.starts_with('/') {
            None
        } else {
            let url = &$url[1..];
            let pat_end = url.find('/').unwrap_or(url.len());
            let rest_url = &url[pat_end..];

            if let Some($p) = url[0 .. pat_end].parse().ok() {
                let $p: $t = $p;
                router!(__check_pattern rest_url $value $($rest)*)
            } else {
                None
            }
        }
    );

    (__check_pattern $url:ident $value:block /$p:ident $($rest:tt)*) => (
        {
            let required = concat!("/", stringify!($p));
            if $url.starts_with(required) {
                let rest_url = &$url[required.len()..];
                router!(__check_pattern rest_url $value $($rest)*)
            } else {
                None
            }
        }
    );

    (__check_pattern $url:ident $value:block) => (
        if $url.len() == 0 { Some($value) } else { None }
    );

    (__check_pattern $url:ident $value:block /) => (
        if $url == "/" { Some($value) } else { None }
    );
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use libimagrt::runtime::Runtime;

pub fn track(rt: &Runtime) -> i32 {
    unimplemented!()
}

<commit_msg>Implement "track" subcommand<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::str::FromStr;

use clap::ArgMatches;
use chrono::naive::NaiveDateTime;

use libimagrt::runtime::Runtime;
use libimagerror::trace::trace_error;
use libimagentrytimetrack::tag::TimeTrackingTag;
use libimagentrytimetrack::timetrackingstore::TimeTrackStore;
use libimagerror::trace::MapErrTrace;

pub fn track(rt: &Runtime) -> i32 {
    let (_, cmd) = rt.cli().subcommand();
    let cmd = cmd.unwrap(); // checked in main()

    // Gets the appropriate time from the commandline or None on error (errors already logged, so
    // callee can directly return in case of error
    fn get_time(cmd: &ArgMatches, clap_name: &str, errname: &str) -> Option<NaiveDateTime> {
        let val = cmd
            .value_of(clap_name)
            .map(::chrono::naive::NaiveDateTime::from_str)
            .unwrap(); // clap has our back

        match val {
            Ok(ndt) => Some(ndt),
            Err(e)  => {
                trace_error(&e);
                error!("Cannot continue, not having {} time", errname);
                None
            },
        }
    }

    let start = match get_time(&cmd, "start-time", "start") {
        Some(t) => t,
        None    => return 1,
    };

    let stop = match get_time(&cmd, "stop-time", "stop") {
        Some(t) => t,
        None    => return 1,
    };

    cmd.values_of("tags")
        .unwrap() // enforced by clap
        .map(String::from)
        .map(TimeTrackingTag::from)
        .fold(0, |acc, ttt| {
            rt.store()
              .create_timetracking(&start, &stop, &ttt)
              .map_err_trace()
              .map(|_| acc)
              .unwrap_or(1)
        })
}

<|endoftext|>


<commit_before>extern crate r6;

use std::old_io::BufReader;
use r6::runtime::Runtime;
use r6::compiler::Compiler;
use r6::base::libbase;
use r6::parser::Parser;

macro_rules! assert_evaluates_to {
    ($src:expr, $expected:expr) => (
        {
            let mut src_reader = BufReader::new($src.as_bytes());
            let mut src_parser = Parser::new(&mut src_reader);
            let sourcecode = match src_parser.parse_datum() {
                Ok(code) => code,
                Err(e) => panic!("failed to parse source: {:?}", e)
            };

            let mut res_reader = BufReader::new($expected.as_bytes());
            let mut res_parser = Parser::new(&mut res_reader);
            let expected = match res_parser.parse_datum() {
                Ok(val) => val,
                Err(e) => panic!("failed to parse result: {:?}", e)
            };

            let base = libbase();
            let compiler = Compiler::new(&base);
            let bytecode = match compiler.compile(&sourcecode) {
                Ok(code) => code,
                Err(e) => panic!("compile failure: {:?}", e)
            };
            let mut runtime = Runtime::new(bytecode);
            let result = runtime.run();
            if !((result == expected) && (expected == result)) {
                panic!("test failed: expected `{:?}` but got `{:?}`", expected, result);
            }
        }
    )
}

#[test]
fn lexical_scoping() {
    // (\y f -> f 2) #f ((\y -> (\x -> y)) #t)
    // If it's dynamic scope, it should return 0
    // If it's static scope, it should return 1
    assert_evaluates_to!("((lambda (y f) (f 2)) #f ((lambda (y) (lambda (x) y)) #t))", "#t")
}

#[test]
fn if_expression_test() {
    assert_evaluates_to!("(if #t 1 0)", "1");
    assert_evaluates_to!("(if #f 1 0)", "0");
}

#[test]
fn eval_to_self_test() {
    assert_evaluates_to!("#t", "#t");
    assert_evaluates_to!("23", "23");
}

#[test]
fn numeric_expressions_test() {
    assert_evaluates_to!("(+ 23 42)", "65");
    assert_evaluates_to!("(+ 14 (* 23 42))", "980");
    assert_evaluates_to!("(- 3 1)", "2");
    assert_evaluates_to!("(- 3)", "-3");
    assert_evaluates_to!("(/ 3 2)", "3/2");
    assert_evaluates_to!("(/ 3.0 2)", "1.5");
}

#[test]
fn let_test() {
    assert_evaluates_to!("(let ((x 23) (y 42)) (+ x y))", "65");
}

#[test]
fn set_test() {
    assert_evaluates_to!("(let ((x 23)) (set! x 24) x)", "24");
}

#[test]
fn list_test() {
    assert_evaluates_to!("(list 1 2 3)", "(1 2 3)");
    assert_evaluates_to!("(list)", "()");
}

#[test]
fn quote_test() {
    assert_evaluates_to!(r#"(quote a)"#, "a");
    assert_evaluates_to!(r#"(quote (1 2 3))"#, "(1 2 3)");
    assert_evaluates_to!(r#"(quote #\a)"#, r#"#\a"#);
}

#[test]
fn quote_abbrev_test() {
    assert_evaluates_to!(r#"'a"#, "a");
    assert_evaluates_to!(r#"'(1 2 3)"#, "(1 2 3)");
    assert_evaluates_to!(r#"'#\a"#, r#"#\a"#);
}

#[test]
fn typecheck_test() {
    assert_evaluates_to!("(boolean? #t)", "#t");
    assert_evaluates_to!("(boolean? #f)", "#t");
    assert_evaluates_to!("(boolean? 1)", "#f");

    assert_evaluates_to!("(pair? (list 1 2))", "#t");
    assert_evaluates_to!("(pair? (list))", "#f");
    assert_evaluates_to!("(pair? 1)", "#f");

    assert_evaluates_to!(r#"(symbol? #\a)"#, "#f");
    assert_evaluates_to!(r#"(symbol? 'a)"#, "#t");

    assert_evaluates_to!(r#"(char? #\a)"#, "#t");
    assert_evaluates_to!(r#"(char? 'a)"#, "#f");

    assert_evaluates_to!(r#"(string? "a")"#, "#t");
    assert_evaluates_to!(r#"(string? 'a)"#, "#f");

    assert_evaluates_to!(r#"(procedure? +)"#, "#t");
    assert_evaluates_to!(r#"(procedure? '+)"#, "#f");

    assert_evaluates_to!(r#"(null? (list))"#, "#t");
    assert_evaluates_to!(r#"(null? (list 1 2))"#, "#f");
}

#[test]
fn car_test() {
    assert_evaluates_to!("(car '(a b))", "a");
}

#[test]
fn cdr_test() {
    assert_evaluates_to!("(cdr '(a b))", "(b)");
}
<commit_msg>Add a test from r6rs spec<commit_after>extern crate r6;

use std::old_io::BufReader;
use r6::runtime::Runtime;
use r6::compiler::Compiler;
use r6::base::libbase;
use r6::parser::Parser;

macro_rules! assert_evaluates_to {
    ($src:expr, $expected:expr) => (
        {
            let mut src_reader = BufReader::new($src.as_bytes());
            let mut src_parser = Parser::new(&mut src_reader);
            let sourcecode = match src_parser.parse_datum() {
                Ok(code) => code,
                Err(e) => panic!("failed to parse source: {:?}", e)
            };

            let mut res_reader = BufReader::new($expected.as_bytes());
            let mut res_parser = Parser::new(&mut res_reader);
            let expected = match res_parser.parse_datum() {
                Ok(val) => val,
                Err(e) => panic!("failed to parse result: {:?}", e)
            };

            let base = libbase();
            let compiler = Compiler::new(&base);
            let bytecode = match compiler.compile(&sourcecode) {
                Ok(code) => code,
                Err(e) => panic!("compile failure: {:?}", e)
            };
            let mut runtime = Runtime::new(bytecode);
            let result = runtime.run();
            if !((result == expected) && (expected == result)) {
                panic!("test failed: expected `{:?}` but got `{:?}`", expected, result);
            }
        }
    )
}

#[test]
fn lexical_scoping() {
    // (\y f -> f 2) #f ((\y -> (\x -> y)) #t)
    // If it's dynamic scope, it should return 0
    // If it's static scope, it should return 1
    assert_evaluates_to!("((lambda (y f) (f 2)) #f ((lambda (y) (lambda (x) y)) #t))", "#t")
}

#[test]
fn lambda_test() {
    assert_evaluates_to!("((lambda (x) (+ x x)) 4)", "8");
}

#[test]
fn if_expression_test() {
    assert_evaluates_to!("(if #t 1 0)", "1");
    assert_evaluates_to!("(if #f 1 0)", "0");
}

#[test]
fn eval_to_self_test() {
    assert_evaluates_to!("#t", "#t");
    assert_evaluates_to!("23", "23");
}

#[test]
fn numeric_expressions_test() {
    assert_evaluates_to!("(+ 23 42)", "65");
    assert_evaluates_to!("(+ 14 (* 23 42))", "980");
    assert_evaluates_to!("(- 3 1)", "2");
    assert_evaluates_to!("(- 3)", "-3");
    assert_evaluates_to!("(/ 3 2)", "3/2");
    assert_evaluates_to!("(/ 3.0 2)", "1.5");
}

#[test]
fn let_test() {
    assert_evaluates_to!("(let ((x 23) (y 42)) (+ x y))", "65");
}

#[test]
fn set_test() {
    assert_evaluates_to!("(let ((x 23)) (set! x 24) x)", "24");
}

#[test]
fn list_test() {
    assert_evaluates_to!("(list 1 2 3)", "(1 2 3)");
    assert_evaluates_to!("(list)", "()");
}

#[test]
fn quote_test() {
    assert_evaluates_to!(r#"(quote a)"#, "a");
    assert_evaluates_to!(r#"(quote (1 2 3))"#, "(1 2 3)");
    assert_evaluates_to!(r#"(quote #\a)"#, r#"#\a"#);
}

#[test]
fn quote_abbrev_test() {
    assert_evaluates_to!(r#"'a"#, "a");
    assert_evaluates_to!(r#"'(1 2 3)"#, "(1 2 3)");
    assert_evaluates_to!(r#"'#\a"#, r#"#\a"#);
}

#[test]
fn typecheck_test() {
    assert_evaluates_to!("(boolean? #t)", "#t");
    assert_evaluates_to!("(boolean? #f)", "#t");
    assert_evaluates_to!("(boolean? 1)", "#f");

    assert_evaluates_to!("(pair? (list 1 2))", "#t");
    assert_evaluates_to!("(pair? (list))", "#f");
    assert_evaluates_to!("(pair? 1)", "#f");

    assert_evaluates_to!(r#"(symbol? #\a)"#, "#f");
    assert_evaluates_to!(r#"(symbol? 'a)"#, "#t");

    assert_evaluates_to!(r#"(char? #\a)"#, "#t");
    assert_evaluates_to!(r#"(char? 'a)"#, "#f");

    assert_evaluates_to!(r#"(string? "a")"#, "#t");
    assert_evaluates_to!(r#"(string? 'a)"#, "#f");

    assert_evaluates_to!(r#"(procedure? +)"#, "#t");
    assert_evaluates_to!(r#"(procedure? '+)"#, "#f");

    assert_evaluates_to!(r#"(null? (list))"#, "#t");
    assert_evaluates_to!(r#"(null? (list 1 2))"#, "#f");
}

#[test]
fn car_test() {
    assert_evaluates_to!("(car '(a b))", "a");
}

#[test]
fn cdr_test() {
    assert_evaluates_to!("(cdr '(a b))", "(b)");
}
<|endoftext|>


<commit_before>/*
 * Cymbalum, Molecular Simulation in Rust
 * Copyright (C) 2015 Guillaume Fraux
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
*/
#![allow(non_snake_case)]
//! Testing physical properties of a Lennard-Jones gaz of Helium.
extern crate env_logger;
extern crate cymbalum;
use self::cymbalum::*;

use std::path::Path;

fn setup<T: Integrator + 'static>(integrator: T) -> (Simulation, Universe) {
    let data_dir = Path::new(file!()).parent().unwrap();
    let configuration = data_dir.join("data").join("Helium.xyz");
    let mut universe = Universe::from_file(configuration.to_str().unwrap()).unwrap();
    universe.set_cell(UnitCell::cubic(10.0));
    universe.add_pair_interaction("He", "He",
        LennardJones{
            sigma: units::from(2.0, "A").unwrap(),
            epsilon: units::from(0.2, "kJ/mol").unwrap()
        }
    );

    let mut velocities = BoltzmanVelocities::new(units::from(300.0, "K").unwrap());
    velocities.init(&mut universe);

    let simulation = Simulation::new(
        MolecularDynamics::from_integrator(integrator)
    );
    return (simulation, universe);
}

#[test]
#[allow(unused_must_use)]
fn constant_energy_velocity_verlet() {
    env_logger::init();
    let (mut simulation, mut universe) = setup(
        VelocityVerlet::new(units::from(1.0, "fs").unwrap())
    );

    let E_initial = universe.total_energy();
    simulation.run(&mut universe, 1000);
    let E_final = universe.total_energy();

    assert!(f64::abs(E_initial - E_final) < 1e-5);
}

#[test]
#[allow(unused_must_use)]
fn constant_energy_verlet() {
    env_logger::init();
    let (mut simulation, mut universe) = setup(
        Verlet::new(units::from(1.0, "fs").unwrap())
    );
    let E_initial = universe.total_energy();
    simulation.run(&mut universe, 1000);
    let E_final = universe.total_energy();
    assert!(f64::abs(E_initial - E_final) < 1e-4);
}
<commit_msg>Add a test for leap-frog integrator<commit_after>/*
 * Cymbalum, Molecular Simulation in Rust
 * Copyright (C) 2015 Guillaume Fraux
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
*/
#![allow(non_snake_case)]
//! Testing physical properties of a Lennard-Jones gaz of Helium.
extern crate env_logger;
extern crate cymbalum;
use self::cymbalum::*;

use std::path::Path;

fn setup<T: Integrator + 'static>(integrator: T) -> (Simulation, Universe) {
    let data_dir = Path::new(file!()).parent().unwrap();
    let configuration = data_dir.join("data").join("Helium.xyz");
    let mut universe = Universe::from_file(configuration.to_str().unwrap()).unwrap();
    universe.set_cell(UnitCell::cubic(10.0));
    universe.add_pair_interaction("He", "He",
        LennardJones{
            sigma: units::from(2.0, "A").unwrap(),
            epsilon: units::from(0.2, "kJ/mol").unwrap()
        }
    );

    let mut velocities = BoltzmanVelocities::new(units::from(300.0, "K").unwrap());
    velocities.init(&mut universe);

    let simulation = Simulation::new(
        MolecularDynamics::from_integrator(integrator)
    );
    return (simulation, universe);
}

#[test]
#[allow(unused_must_use)]
fn constant_energy_velocity_verlet() {
    env_logger::init();
    let (mut simulation, mut universe) = setup(
        VelocityVerlet::new(units::from(1.0, "fs").unwrap())
    );

    let E_initial = universe.total_energy();
    simulation.run(&mut universe, 1000);
    let E_final = universe.total_energy();

    assert!(f64::abs(E_initial - E_final) < 1e-5);
}

#[test]
#[allow(unused_must_use)]
fn constant_energy_verlet() {
    env_logger::init();
    let (mut simulation, mut universe) = setup(
        Verlet::new(units::from(1.0, "fs").unwrap())
    );
    let E_initial = universe.total_energy();
    simulation.run(&mut universe, 1000);
    let E_final = universe.total_energy();
    assert!(f64::abs(E_initial - E_final) < 1e-4);
}

#[test]
#[allow(unused_must_use)]
fn constant_energy_leap_frog() {
    env_logger::init();
    let (mut simulation, mut universe) = setup(
        LeapFrog::new(units::from(1.0, "fs").unwrap())
    );
    let E_initial = universe.total_energy();
    simulation.run(&mut universe, 1000);
    let E_final = universe.total_energy();
    assert!(f64::abs(E_initial - E_final) < 1e-5);
}
<|endoftext|>