<commit_before>use oak_runtime::parse_state::*;
use oak_runtime::parse_state::ParseResult::*;

use std::io::prelude::*;
use std::fs::File;
use std::io::BufReader;

use ast::Stmt;

grammar! bailey {
    use ast::Ident;
    use ast::Literal;
    use ast::Expr;
    use ast::Stmt;
    use ast::BinOp;
    use ast::Decl;
    use ast::Block;
    use ast::BinOp::*;
    use std::str::FromStr;

    program
        = newlines (stmt terminator)*

    stmt
        = assign_stmt
        / if_stmt
        / while_stmt
        / decl > decl_to_stmt
        / expr > expr_to_stmt

    assign_stmt
        = var bind_op expr > assign_stmt

    if_stmt
        = if_kw expr block (else_kw block)? > if_stmt

    while_stmt
        = while_kw expr block > while_stmt

    decl
        = class_decl
        / method_decl

    class_decl
        = class_kw ident class_body > class_decl

    class_body
        = lbracket (newlines method_decl)* rbracket

    method_decl
        = def_kw ident lparen param_list rparen block > method_decl

    block
        = newlines lbracket stmt_list rbracket spacing > block

    stmt_list
        = empty_stmt_list
        / stmt (terminator stmt)* > stmt_list

    function_call
        = newlines ident lparen arg_list rparen

    method_call
        = callable_expr (dot function_call)+

    expr
        = newlines cond_expr

    cond_expr
        = add_expr (cond_expr_op add_expr)* > fold_left

    add_expr
        = mult_expr (add_expr_op mult_expr)* > fold_left

    mult_expr
        = primary_expr (mult_expr_op primary_expr)* > fold_left

    primary_expr
        = method_call > method_call
        / callable_expr

    callable_expr
        = function_call > function_call
        / literal > lit_to_exp
        / constant
        / var
        / array
        / map
        / lparen expr rparen

    arg_list
        = empty_list
        / expr (comma expr)* > arg_list

    param_list
        = empty_param_list
        / ident (comma ident)* > param_list

    empty_list = &rparen > empty_list
    empty_param_list = &rparen > empty_param_list
    empty_stmt_list = &rbracket > empty_stmt_list

    digit = ["0-9"]
    ident_char = ["A-Za-z0-9_"]

    var = !digit !keyword ident_char+ spacing > var
    ident = !digit !keyword ident_char+ spacing > ident
    constant = !keyword !digit ["A-Z"]+ ident_char+ spacing > constant

    literal
        = string_lit
        / float_lit
        / int_lit

    int_lit = digit+ spacing > int_lit
    float_lit = digit+ dot digit+ spacing > float_lit
    string_lit = (dbl_quot_string_lit / sng_quot_string_lit) spacing > string_lit

    array_elem = expr > array_elem
    array = lsqbracket array_elem (comma array_elem)* rsqbracket > array

    map_entry =  (expr colon expr) > map_entry
    map = lbracket map_entry (comma map_entry)* rbracket > map

    dbl_quot_string_lit = dbl_quot (spacing_char / !dbl_quot .)* dbl_quot
    sng_quot_string_lit = sng_quot (spacing_char / !sng_quot .)* sng_quot

    spacing_char = [" \r\t"]
    spacing = spacing_char* -> ()
    newline = "\n" spacing -> ()
    semicolon = ";" spacing -> ()
    newlines = newline* spacing -> ()
    terminator = (newline / semicolon) newlines -> ()

    class_kw = "class" spacing
    def_kw = "def" spacing
    else_kw = "else" spacing
    false_kw = "false" spacing
    if_kw = "if" spacing
    nil_kw = "nil" spacing
    true_kw = "true" spacing
    while_kw = "while" spacing

    keyword
        = def_kw
        / if_kw
        / else_kw
        / class_kw
        / true_kw
        / false_kw
        / nil_kw

    add_expr_op
        = add_op > add_bin_op
        / sub_op > sub_bin_op

    mult_expr_op
        = mul_op > mul_bin_op
        / div_op > div_bin_op

    cond_expr_op
        = lt_op > lt_bin_op /
        lte_op > lte_bin_op /
        gt_op > gt_bin_op /
        gte_op > gte_bin_op /
        ne_op > ne_bin_op /
        eq_op > eq_bin_op /
        andand_op > and_bin_op /
        oror_op > or_bin_op

    bind_op = "=" spacing
    add_op = "+" spacing
    sub_op = "-" spacing
    mul_op = "*" spacing
    div_op = "/" spacing
    lt_op = "<" spacing
    lte_op = "<=" spacing
    gt_op = ">" spacing
    gte_op = ">=" spacing
    ne_op = "!=" spacing
    eq_op = "==" spacing
    andand_op  = "&&" spacing
    oror_op = "||" spacing

    lparen = "(" newlines -> ()
    rparen = newlines ")" -> ()
    lbracket = "{" newlines -> ()
    rbracket = newlines "}" -> ()
    lsqbracket = "[" newlines
    rsqbracket = newlines "]"
    dbl_quot = "\"" spacing
    sng_quot = "'" spacing
    dot = "." spacing
    comma = "," spacing
    colon = ":" spacing

    fn decl_to_stmt(decl: Decl) -> Stmt {
        Stmt::Decl(Box::new(decl))
    }

    fn expr_to_stmt(expr: Expr) -> Stmt {
        Stmt::Expr(Box::new(expr))
    }

    fn lit_to_exp(literal: Literal) -> Expr {
        Expr::Literal(Box::new(literal))
    }

    fn int_lit(raw_text: Vec<char>) -> Literal {
        Literal::Integer(to_number(raw_text))
    }

    fn float_lit(mut integer: Vec<char>, fractional: Vec<char>) -> Literal {
        integer.push('.');
        Literal::Float(to_float(combine(integer, fractional)))
    }

    fn string_lit(raw_text: Vec<char>) -> Literal {
        Literal::Str(to_string(raw_text))
    }

    fn array(first: Box<Expr>, rest: Vec<Box<Expr>>) -> Expr {
        Expr::Array(combine_one_with_many(first, rest))
    }

    fn array_elem(expr: Expr) -> Box<Expr> {
        Box::new(expr)
    }

    fn map(first: (Box<Expr>, Box<Expr>), rest: Vec<(Box<Expr>, Box<Expr>)>) -> Expr {
        Expr::Map(combine_one_with_many(first, rest))
    }

    fn map_entry(key: Expr, val: Expr) -> (Box<Expr>, Box<Expr>) {
        (Box::new(key), Box::new(val))
    }

    fn constant(first: Vec<char>, rest: Vec<char>) -> Expr {
        Expr::Const(Ident(to_string(combine(first, rest))))
    }

    fn ident(raw_text: Vec<char>) -> Ident {
        Ident(to_string(raw_text))
    }

    fn var(raw_text: Vec<char>) -> Expr {
        Expr::Var(Ident(to_string(raw_text)))
    }

    fn add_bin_op() -> BinOp { Add }
    fn sub_bin_op() -> BinOp { Sub }
    fn mul_bin_op() -> BinOp { Mul }
    fn div_bin_op() -> BinOp { Div }
    fn lt_bin_op() -> BinOp { Lt }
    fn lte_bin_op() -> BinOp { Lte }
    fn gt_bin_op() -> BinOp { Gt }
    fn gte_bin_op() -> BinOp { Gte }
    fn ne_bin_op() -> BinOp { Ne }
    fn eq_bin_op() -> BinOp { Eq }
    fn and_bin_op() -> BinOp { And }
    fn or_bin_op() -> BinOp { Or }

    fn function_call(func: Ident, args: Vec<Expr>) -> Expr {
        Expr::Message(None, func, args)
    }

    fn method_call(recv: Expr, call: Vec<(Ident, Vec<Expr>)>) -> Expr {
        call.into_iter().fold(recv, { |accu, (method, args)|
            Expr::Message(Some(Box::new(accu)), method, args)
        })
    }

    fn assign_stmt(var: Expr, expr: Expr) -> Stmt {
        Stmt::Assign(Box::new(var), Box::new(expr))
    }

    fn class_decl(class: Ident, methods: Vec<Decl>) -> Decl {
        Decl::Class(class, methods)
    }

    fn method_decl(meth: Ident, params: Vec<Ident>, block: Block) -> Decl {
        Decl::Method(meth, params, Box::new(block))
    }

    fn block(stmts: Vec<Stmt>) -> Block {
        Block { stmts: stmts }
    }

    fn program(first: Stmt, mut rest: Vec<Stmt>) -> Vec<Stmt> {
        combine_one_with_many(first, rest)
    }

    fn if_stmt(cond: Expr, true_blk: Block, false_blk: Option<Block>) -> Stmt {
        match false_blk {
            Some(blk) => Stmt::If(Box::new(cond), Box::new(true_blk), Some(Box::new(blk))),
            None => Stmt::If(Box::new(cond), Box::new(true_blk), None)
        }
    }

    fn while_stmt(cond: Expr, blk: Block) -> Stmt {
        Stmt::While(Box::new(cond), Box::new(blk))
    }

    fn arg_list(first: Expr, mut rest: Vec<Expr>) -> Vec<Expr> {
        combine_one_with_many(first, rest)
    }

    fn param_list(first: Ident, mut rest: Vec<Ident>) -> Vec<Ident> {
        combine_one_with_many(first, rest)
    }

    fn empty_param_list() -> Vec<Ident> {
        vec![]
    }

    fn stmt_list(first: Stmt, mut rest: Vec<Stmt>) -> Vec<Stmt> {
        combine_one_with_many(first, rest)
    }

    fn empty_list() -> Vec<Expr> {
        vec![]
    }

    fn empty_stmt_list() -> Vec<Stmt> {
        vec![]
    }

    fn to_string(raw_text: Vec<char>) -> String {
        raw_text.into_iter().collect()
    }

    fn to_number(raw_text: Vec<char>) -> i64 {
        i64::from_str(&*to_string(raw_text)).unwrap()
    }

    fn to_float(raw_text: Vec<char>) -> f64 {
        f64::from_str(&*to_string(raw_text)).unwrap()
    }

    fn fold_left(head: Expr, rest: Vec<(BinOp, Expr)>) -> Expr {
        rest.into_iter().fold(head,
          |accu, (op, expr)| Expr::Binary(op, Box::new(accu), Box::new(expr)))
    }

    fn combine<T: Clone>(mut left: Vec<T>, right: Vec<T>) -> Vec<T> {
        left.extend(right.into_iter());
        left
    }

    fn combine_one_with_many<T: Clone>(first: T, rest: Vec<T>) -> Vec<T> {
        combine(vec![first], rest)
    }
}

pub struct Parser {
    pub ast: Option<Vec<Stmt>>,
}

impl Parser {
    pub fn new() -> Parser {
        Parser { ast: None }
    }

    pub fn parse_file(&mut self, file_path: String) -> Result<Vec<Stmt>, String> {
        match File::open(file_path) {
            Ok(file) => {
                let mut reader = BufReader::new(file);
                let mut code = String::new();
                let _ = reader.read_to_string(&mut code);
                self.parse(code)
            }
            Err(error) => Err(format!("Error: {}", error)),
        }
    }

    pub fn parse(&mut self, code: String) -> Result<Vec<Stmt>, String> {
        let state = bailey::parse_program(code.into_state());

        match state.into_result() {
            Success(data) => Ok(data.clone()),
            Partial(data, expectation) => {
                Err(format!("Partial match: {:?} because: {:?}", data, expectation))
            }
            Failure(expectation) => {
                Err(format!("Error: {:?}", expectation))
            }
        }
    }
}

<commit_msg>Reworked if_stmt.<commit_after>use oak_runtime::parse_state::*;
use oak_runtime::parse_state::ParseResult::*;

use std::io::prelude::*;
use std::fs::File;
use std::io::BufReader;

use ast::Stmt;

grammar! bailey {
    use ast::Ident;
    use ast::Literal;
    use ast::Expr;
    use ast::Stmt;
    use ast::BinOp;
    use ast::Decl;
    use ast::Block;
    use ast::BinOp::*;
    use std::str::FromStr;

    program
        = newlines (stmt terminator)*

    stmt
        = assign_stmt
        / if_stmt
        / while_stmt
        / decl > decl_to_stmt
        / expr > expr_to_stmt

    assign_stmt
        = var bind_op expr > assign_stmt

    if_stmt
        = if_kw expr block (else_kw block)? > if_stmt

    while_stmt
        = while_kw expr block > while_stmt

    decl
        = class_decl
        / method_decl

    class_decl
        = class_kw ident class_body > class_decl

    class_body
        = lbracket (newlines method_decl)* rbracket

    method_decl
        = def_kw ident lparen param_list rparen block > method_decl

    block
        = newlines lbracket stmt_list rbracket spacing > block

    stmt_list
        = empty_stmt_list
        / stmt (terminator stmt)* > stmt_list

    function_call
        = newlines ident lparen arg_list rparen

    method_call
        = callable_expr (dot function_call)+

    expr
        = newlines cond_expr

    cond_expr
        = add_expr (cond_expr_op add_expr)* > fold_left

    add_expr
        = mult_expr (add_expr_op mult_expr)* > fold_left

    mult_expr
        = primary_expr (mult_expr_op primary_expr)* > fold_left

    primary_expr
        = method_call > method_call
        / callable_expr

    callable_expr
        = function_call > function_call
        / literal > lit_to_exp
        / constant
        / var
        / array
        / map
        / lparen expr rparen

    arg_list
        = empty_list
        / expr (comma expr)* > arg_list

    param_list
        = empty_param_list
        / ident (comma ident)* > param_list

    empty_list = &rparen > empty_list
    empty_param_list = &rparen > empty_param_list
    empty_stmt_list = &rbracket > empty_stmt_list

    digit = ["0-9"]
    ident_char = ["A-Za-z0-9_"]

    var = !digit !keyword ident_char+ spacing > var
    ident = !digit !keyword ident_char+ spacing > ident
    constant = !keyword !digit ["A-Z"]+ ident_char+ spacing > constant

    literal
        = string_lit
        / float_lit
        / int_lit

    int_lit = digit+ spacing > int_lit
    float_lit = digit+ dot digit+ spacing > float_lit
    string_lit = (dbl_quot_string_lit / sng_quot_string_lit) spacing > string_lit

    array_elem = expr > array_elem
    array = lsqbracket array_elem (comma array_elem)* rsqbracket > array

    map_entry =  (expr colon expr) > map_entry
    map = lbracket map_entry (comma map_entry)* rbracket > map

    dbl_quot_string_lit = dbl_quot (spacing_char / !dbl_quot .)* dbl_quot
    sng_quot_string_lit = sng_quot (spacing_char / !sng_quot .)* sng_quot

    spacing_char = [" \r\t"]
    spacing = spacing_char* -> ()
    newline = "\n" spacing -> ()
    semicolon = ";" spacing -> ()
    newlines = newline* spacing -> ()
    terminator = (newline / semicolon) newlines -> ()

    class_kw = "class" spacing
    def_kw = "def" spacing
    else_kw = "else" spacing
    false_kw = "false" spacing
    if_kw = "if" spacing
    nil_kw = "nil" spacing
    true_kw = "true" spacing
    while_kw = "while" spacing

    keyword
        = def_kw
        / if_kw
        / else_kw
        / class_kw
        / true_kw
        / false_kw
        / nil_kw

    add_expr_op
        = add_op > add_bin_op
        / sub_op > sub_bin_op

    mult_expr_op
        = mul_op > mul_bin_op
        / div_op > div_bin_op

    cond_expr_op
        = lt_op > lt_bin_op /
        lte_op > lte_bin_op /
        gt_op > gt_bin_op /
        gte_op > gte_bin_op /
        ne_op > ne_bin_op /
        eq_op > eq_bin_op /
        andand_op > and_bin_op /
        oror_op > or_bin_op

    bind_op = "=" spacing
    add_op = "+" spacing
    sub_op = "-" spacing
    mul_op = "*" spacing
    div_op = "/" spacing
    lt_op = "<" spacing
    lte_op = "<=" spacing
    gt_op = ">" spacing
    gte_op = ">=" spacing
    ne_op = "!=" spacing
    eq_op = "==" spacing
    andand_op  = "&&" spacing
    oror_op = "||" spacing

    lparen = "(" newlines -> ()
    rparen = newlines ")" -> ()
    lbracket = "{" newlines -> ()
    rbracket = newlines "}" -> ()
    lsqbracket = "[" newlines
    rsqbracket = newlines "]"
    dbl_quot = "\"" spacing
    sng_quot = "'" spacing
    dot = "." spacing
    comma = "," spacing
    colon = ":" spacing

    fn decl_to_stmt(decl: Decl) -> Stmt {
        Stmt::Decl(Box::new(decl))
    }

    fn expr_to_stmt(expr: Expr) -> Stmt {
        Stmt::Expr(Box::new(expr))
    }

    fn lit_to_exp(literal: Literal) -> Expr {
        Expr::Literal(Box::new(literal))
    }

    fn int_lit(raw_text: Vec<char>) -> Literal {
        Literal::Integer(to_number(raw_text))
    }

    fn float_lit(mut integer: Vec<char>, fractional: Vec<char>) -> Literal {
        integer.push('.');
        Literal::Float(to_float(combine(integer, fractional)))
    }

    fn string_lit(raw_text: Vec<char>) -> Literal {
        Literal::Str(to_string(raw_text))
    }

    fn array(first: Box<Expr>, rest: Vec<Box<Expr>>) -> Expr {
        Expr::Array(combine_one_with_many(first, rest))
    }

    fn array_elem(expr: Expr) -> Box<Expr> {
        Box::new(expr)
    }

    fn map(first: (Box<Expr>, Box<Expr>), rest: Vec<(Box<Expr>, Box<Expr>)>) -> Expr {
        Expr::Map(combine_one_with_many(first, rest))
    }

    fn map_entry(key: Expr, val: Expr) -> (Box<Expr>, Box<Expr>) {
        (Box::new(key), Box::new(val))
    }

    fn constant(first: Vec<char>, rest: Vec<char>) -> Expr {
        Expr::Const(Ident(to_string(combine(first, rest))))
    }

    fn ident(raw_text: Vec<char>) -> Ident {
        Ident(to_string(raw_text))
    }

    fn var(raw_text: Vec<char>) -> Expr {
        Expr::Var(Ident(to_string(raw_text)))
    }

    fn add_bin_op() -> BinOp { Add }
    fn sub_bin_op() -> BinOp { Sub }
    fn mul_bin_op() -> BinOp { Mul }
    fn div_bin_op() -> BinOp { Div }
    fn lt_bin_op() -> BinOp { Lt }
    fn lte_bin_op() -> BinOp { Lte }
    fn gt_bin_op() -> BinOp { Gt }
    fn gte_bin_op() -> BinOp { Gte }
    fn ne_bin_op() -> BinOp { Ne }
    fn eq_bin_op() -> BinOp { Eq }
    fn and_bin_op() -> BinOp { And }
    fn or_bin_op() -> BinOp { Or }

    fn function_call(func: Ident, args: Vec<Expr>) -> Expr {
        Expr::Message(None, func, args)
    }

    fn method_call(recv: Expr, call: Vec<(Ident, Vec<Expr>)>) -> Expr {
        call.into_iter().fold(recv, { |accu, (method, args)|
            Expr::Message(Some(Box::new(accu)), method, args)
        })
    }

    fn assign_stmt(var: Expr, expr: Expr) -> Stmt {
        Stmt::Assign(Box::new(var), Box::new(expr))
    }

    fn class_decl(class: Ident, methods: Vec<Decl>) -> Decl {
        Decl::Class(class, methods)
    }

    fn method_decl(meth: Ident, params: Vec<Ident>, block: Block) -> Decl {
        Decl::Method(meth, params, Box::new(block))
    }

    fn block(stmts: Vec<Stmt>) -> Block {
        Block { stmts: stmts }
    }

    fn program(first: Stmt, mut rest: Vec<Stmt>) -> Vec<Stmt> {
        combine_one_with_many(first, rest)
    }

    fn if_stmt(cond: Expr, true_blk: Block, false_blk: Option<Block>) -> Stmt {
        let false_blk = match false_blk {
            Some(blk) => Some(Box::new(blk)),
            None => None
        };

        Stmt::If(Box::new(cond), Box::new(true_blk), false_blk)
    }

    fn while_stmt(cond: Expr, blk: Block) -> Stmt {
        Stmt::While(Box::new(cond), Box::new(blk))
    }

    fn arg_list(first: Expr, mut rest: Vec<Expr>) -> Vec<Expr> {
        combine_one_with_many(first, rest)
    }

    fn param_list(first: Ident, mut rest: Vec<Ident>) -> Vec<Ident> {
        combine_one_with_many(first, rest)
    }

    fn empty_param_list() -> Vec<Ident> {
        vec![]
    }

    fn stmt_list(first: Stmt, mut rest: Vec<Stmt>) -> Vec<Stmt> {
        combine_one_with_many(first, rest)
    }

    fn empty_list() -> Vec<Expr> {
        vec![]
    }

    fn empty_stmt_list() -> Vec<Stmt> {
        vec![]
    }

    fn to_string(raw_text: Vec<char>) -> String {
        raw_text.into_iter().collect()
    }

    fn to_number(raw_text: Vec<char>) -> i64 {
        i64::from_str(&*to_string(raw_text)).unwrap()
    }

    fn to_float(raw_text: Vec<char>) -> f64 {
        f64::from_str(&*to_string(raw_text)).unwrap()
    }

    fn fold_left(head: Expr, rest: Vec<(BinOp, Expr)>) -> Expr {
        rest.into_iter().fold(head,
          |accu, (op, expr)| Expr::Binary(op, Box::new(accu), Box::new(expr)))
    }

    fn combine<T: Clone>(mut left: Vec<T>, right: Vec<T>) -> Vec<T> {
        left.extend(right.into_iter());
        left
    }

    fn combine_one_with_many<T: Clone>(first: T, rest: Vec<T>) -> Vec<T> {
        combine(vec![first], rest)
    }
}

pub struct Parser {
    pub ast: Option<Vec<Stmt>>,
}

impl Parser {
    pub fn new() -> Parser {
        Parser { ast: None }
    }

    pub fn parse_file(&mut self, file_path: String) -> Result<Vec<Stmt>, String> {
        match File::open(file_path) {
            Ok(file) => {
                let mut reader = BufReader::new(file);
                let mut code = String::new();
                let _ = reader.read_to_string(&mut code);
                self.parse(code)
            }
            Err(error) => Err(format!("Error: {}", error)),
        }
    }

    pub fn parse(&mut self, code: String) -> Result<Vec<Stmt>, String> {
        let state = bailey::parse_program(code.into_state());

        match state.into_result() {
            Success(data) => Ok(data.clone()),
            Partial(data, expectation) => {
                Err(format!("Partial match: {:?} because: {:?}", data, expectation))
            }
            Failure(expectation) => {
                Err(format!("Error: {:?}", expectation))
            }
        }
    }
}

<|endoftext|>


<commit_before>use std::collections::HashMap;
use lexer::{Token, Tokens};
use error::ParserError;
use constants::KEYWORDS;

type Operators = HashMap<&'static str, Operator>;
type Identifiers = HashMap<String, String>;

#[derive(PartialEq, Debug)]
enum Associativity {
    LeftToRight,
    RightToLeft,
}

#[derive(PartialEq, Debug)]
struct Operator(usize, Associativity);

impl Operator {
    fn new(precedence: usize, associativity: Associativity) -> Operator {
        Operator(precedence, associativity)
    }
}

pub struct Parser {
    operators: Operators,
    identifiers: Identifiers,
    stack: Tokens,
    output: Tokens,
}

impl Parser {
    fn new() -> Parser {
        Parser {
            operators: Operators::new(),
            identifiers: Identifiers::new(),
            stack: Tokens::with_capacity(3),
            output: Tokens::with_capacity(3),
        }
    }

    // fn is_keyword(&mut self, identifier: String) -> bool {
    //     for keyword in KEYWORDS {
    //         if keyword.to_string() == identifier.to_lowercase() {
    //             return true;
    //         }
    //     }
    //     return false;
    // }

    fn lower_precedence(&self, new_token: &Token, top_token: &Token) -> bool {
        let &Operator(new_token_prec, ref new_token_assoc) = match *new_token {
            Token::Operator(ref name) => self.operators.get::<str>(&name).unwrap(),
            _ => unreachable!(),
        };

        let &Operator(top_token_prec, _) = match *top_token {
            Token::Operator(ref name) => self.operators.get::<str>(&name).unwrap(),
            _ => unreachable!(),
        };

        (*new_token_assoc == Associativity::LeftToRight && new_token_prec <= top_token_prec) ||
        (*new_token_assoc == Associativity::RightToLeft && new_token_prec < top_token_prec)
    }

    pub fn parse(&mut self, tokens: &Tokens) -> Result<&Tokens, ParserError> {
        self.reset_parser();

        let mut iter = tokens.iter().peekable();
        while let Some(&(position, ref token)) = iter.next() {
            match *token {
                Token::Decimal(_) => self.output.push((position, token.clone())),
                Token::Operator(ref name) => {
                    // if the token is an operator, o1, then:
                    // while there is an operator token o2, at the top of the
                    // operator stack and either o1 is left-associative and its
                    // precedence is less than or equal to that of o2, or o1 is
                    // right associative, and has precedence less than that of
                    // o2, pop o2 off the operator stack, onto the output queue
                    loop {
                        match self.stack.last() {
                            Some(&(_, Token::Operator(_))) => {
                                if self.lower_precedence(&token, &self.stack.last().unwrap().1) {
                                    self.output.push(self.stack.pop().unwrap());
                                } else {
                                    break;
                                }
                            }
                            _ => break,
                        }
                    }

                    self.stack.push((position, token.clone()));
                }
                Token::OpenBracket => self.stack.push((position, token.clone())),
                Token::CloseBracket => {
                    let mut found = false;

                    loop {
                        match self.stack.last() {
                            Some(&(_, Token::OpenBracket)) => {
                                found = true;
                                self.stack.pop();
                                break;
                            }
                            None => break,
                            _ => self.output.push(self.stack.pop().unwrap()),
                        }
                    }
                    if !found {
                        return Err(ParserError::MissingBracket(position));
                    }
                }
                Token::Unknown(name) => {
                    return Err(ParserError::IllegalOperator(position, name));
                }
                _ => continue,

            }
        }
        loop {
            match self.stack.last() {
                Some(&(position, Token::OpenBracket)) => {
                    return Err(ParserError::MissingBracket(position))
                }
                Some(_) => self.output.push(self.stack.pop().unwrap()),
                None => break,
            }
        }

        Ok((&self.output))
    }

    fn reset_parser(&mut self) {
        self.stack.clear();
        self.output.clear();
    }
}

impl Default for Parser {
    fn default() -> Parser {
        let mut parser = Parser::new();

        parser.operators.insert("(", Operator::new(1, Associativity::LeftToRight));
        parser.operators.insert(")", Operator::new(1, Associativity::LeftToRight));
        parser.operators.insert("~", Operator::new(2, Associativity::RightToLeft));
        parser.operators.insert("-", Operator::new(2, Associativity::RightToLeft));
        parser.operators.insert(">>", Operator::new(3, Associativity::LeftToRight));
        parser.operators.insert("<<", Operator::new(3, Associativity::LeftToRight));
        parser.operators.insert("&", Operator::new(4, Associativity::LeftToRight));
        parser.operators.insert("^", Operator::new(5, Associativity::LeftToRight));
        parser.operators.insert("|", Operator::new(6, Associativity::LeftToRight));

        parser
    }
}
<commit_msg>Fix parsing errors from unknown operators<commit_after>use std::collections::HashMap;
use lexer::{Token, Tokens};
use error::ParserError;
use constants::KEYWORDS;

type Operators = HashMap<&'static str, Operator>;
type Identifiers = HashMap<String, String>;

#[derive(PartialEq, Debug)]
enum Associativity {
    LeftToRight,
    RightToLeft,
}

#[derive(PartialEq, Debug)]
struct Operator(usize, Associativity);

impl Operator {
    fn new(precedence: usize, associativity: Associativity) -> Operator {
        Operator(precedence, associativity)
    }
}

pub struct Parser {
    operators: Operators,
    identifiers: Identifiers,
    stack: Tokens,
    output: Tokens,
}

impl Parser {
    fn new() -> Parser {
        Parser {
            operators: Operators::new(),
            identifiers: Identifiers::new(),
            stack: Tokens::with_capacity(3),
            output: Tokens::with_capacity(3),
        }
    }

    fn lower_precedence(&self, new_token: &Token, top_token: &Token) -> bool {
        let &Operator(new_token_prec, ref new_token_assoc) = match *new_token {
            Token::Operator(ref name) => self.operators.get::<str>(&name).unwrap(),
            _ => unreachable!(),
        };

        let &Operator(top_token_prec, _) = match *top_token {
            Token::Operator(ref name) => self.operators.get::<str>(&name).unwrap(),
            _ => unreachable!(),
        };

        (*new_token_assoc == Associativity::LeftToRight && new_token_prec <= top_token_prec) ||
        (*new_token_assoc == Associativity::RightToLeft && new_token_prec < top_token_prec)
    }

    pub fn parse(&mut self, tokens: &Tokens) -> Result<&Tokens, ParserError> {
        self.reset_parser();

        let mut iter = tokens.iter().peekable();
        while let Some(&(position, ref token)) = iter.next() {
            match *token {
                Token::Decimal(_) => self.output.push((position, token.clone())),
                Token::Operator(ref name) => {
                    // if the token is an operator, o1, then:
                    // while there is an operator token o2, at the top of the
                    // operator stack and either o1 is left-associative and its
                    // precedence is less than or equal to that of o2, or o1 is
                    // right associative, and has precedence less than that of
                    // o2, pop o2 off the operator stack, onto the output queue
                    if !self.operators.contains_key::<str>(&name) {
                        return Err(ParserError::IllegalOperator(position));
                    }

                    loop {
                        match self.stack.last() {
                            Some(&(_, Token::Operator(_))) => {
                                if self.lower_precedence(&token, &self.stack.last().unwrap().1) {
                                    self.output.push(self.stack.pop().unwrap());
                                } else {
                                    break;
                                }
                            }
                            _ => break,
                        }
                    }

                    self.stack.push((position, token.clone()));
                }
                Token::OpenBracket => self.stack.push((position, token.clone())),
                Token::CloseBracket => {
                    let mut found = false;

                    loop {
                        match self.stack.last() {
                            Some(&(_, Token::OpenBracket)) => {
                                found = true;
                                self.stack.pop();
                                break;
                            }
                            None => break,
                            _ => self.output.push(self.stack.pop().unwrap()),
                        }
                    }
                    if !found {
                        return Err(ParserError::MissingBracket(position));
                    }
                }
                Token::Unknown(_) => {
                    return Err(ParserError::IllegalOperator(position));
                }
                _ => continue,

            }
        }
        loop {
            match self.stack.last() {
                Some(&(position, Token::OpenBracket)) => {
                    return Err(ParserError::MissingBracket(position))
                }
                Some(_) => self.output.push(self.stack.pop().unwrap()),
                None => break,
            }
        }

        Ok((&self.output))
    }

    fn reset_parser(&mut self) {
        self.stack.clear();
        self.output.clear();
    }
}

impl Default for Parser {
    fn default() -> Parser {
        let mut parser = Parser::new();

        parser.operators.insert("(", Operator::new(1, Associativity::LeftToRight));
        parser.operators.insert(")", Operator::new(1, Associativity::LeftToRight));
        parser.operators.insert("~", Operator::new(2, Associativity::RightToLeft));
        parser.operators.insert("-", Operator::new(2, Associativity::RightToLeft));
        parser.operators.insert(">>", Operator::new(3, Associativity::LeftToRight));
        parser.operators.insert("<<", Operator::new(3, Associativity::LeftToRight));
        parser.operators.insert("&", Operator::new(4, Associativity::LeftToRight));
        parser.operators.insert("^", Operator::new(5, Associativity::LeftToRight));
        parser.operators.insert("|", Operator::new(6, Associativity::LeftToRight));

        parser
    }
}
<|endoftext|>


<commit_before>use nom::{self, IResult};
use std::str;
use proto::{Address, AttributeValue, Envelope, MailboxDatum};
use proto::{RequestId, Response, ResponseCode, Status};

fn crlf(c: u8) -> bool {
    c == b'\r' || c == b'\n'
}

fn list_wildcards(c: u8) -> bool {
    c == b'%' || c == b'*'
}

fn quoted_specials(c: u8) -> bool {
    c == b'"' || c == b'\\'
}

fn resp_specials(c: u8) -> bool {
    c == b']'
}

fn atom_specials(c: u8) -> bool {
    c == b'(' || c == b')' || c == b'{' || c == b' ' || c < 32 ||
    list_wildcards(c) || quoted_specials(c) || resp_specials(c)
}

fn atom_char(c: u8) -> bool {
    !atom_specials(c)
}

fn astring_char(c: u8) -> bool {
    atom_char(c) || resp_specials(c)
}

fn tag_char(c: u8) -> bool {
    c != b'+' && astring_char(c)
}

named!(quoted_data<&[u8], &str, u32>, map!(
    //escaped!(take_till_s!(quoted_specials), '\\', one_of!("\"\\")),
    take_till_s!(quoted_specials),
    |s| str::from_utf8(s).unwrap()
));

named!(quoted<&str>, do_parse!(
    tag_s!("\"") >>
    data: quoted_data >>
    tag_s!("\"") >>
    (data)
));

named!(status_ok<Status>, map!(tag_no_case!("OK"),
    |s| Status::Ok
));
named!(status_no<Status>, map!(tag_no_case!("NO"),
    |s| Status::No
));
named!(status_bad<Status>, map!(tag_no_case!("BAD"),
    |s| Status::Bad
));
named!(status_preauth<Status>, map!(tag_no_case!("PREAUTH"),
    |s| Status::PreAuth
));
named!(status_bye<Status>, map!(tag_no_case!("BYE"),
    |s| Status::Bye
));

named!(status<Status>, alt!(
    status_ok |
    status_no |
    status_bad |
    status_preauth |
    status_bye
));

named!(number<u32>, map!(nom::digit,
    |s| str::parse(str::from_utf8(s).unwrap()).unwrap()
));

named!(number_64<u64>, map!(nom::digit,
    |s| str::parse(str::from_utf8(s).unwrap()).unwrap()
));

named!(text<&str>, map!(take_till_s!(crlf),
    |s| str::from_utf8(s).unwrap()
));

named!(atom<&str>, map!(take_while1_s!(atom_char),
    |s| str::from_utf8(s).unwrap()
));

fn flag_extension(i: &[u8]) -> IResult<&[u8], &str> {
    if i.len() < 1 || i[0] != b'\\' {
        return IResult::Error(nom::ErrorKind::Custom(0));
    }
    let mut last = 0;
    for (idx, c) in i[1..].iter().enumerate() {
        last = idx;
        if !atom_char(*c) {
            break;
        }
    }
    IResult::Done(&i[last + 1..], str::from_utf8(&i[..last + 1]).unwrap())
}

named!(flag<&str>, alt!(flag_extension | atom));

named!(flag_list<Vec<&str>>, do_parse!(
    tag_s!("(") >>
    elements: opt!(do_parse!(
        flag0: flag >>
        flags: many0!(do_parse!(
            tag_s!(" ") >>
            flag: flag >>
            (flag)
        )) >> ({
            let mut res = vec![flag0];
            res.extend(flags);
            res
        })
    )) >>
    tag_s!(")") >> ({
       if elements.is_some() {
           elements.unwrap()
       } else {
           Vec::new()
       }
    })
));

named!(flag_perm<&str>, alt!(
    map!(tag_s!("\\*"), |s| str::from_utf8(s).unwrap()) |
    flag
));

named!(resp_text_code_permanent_flags<ResponseCode>, do_parse!(
    tag_s!("PERMANENTFLAGS (") >>
    elements: dbg_dmp!(opt!(do_parse!(
        flag0: flag_perm >>
        flags: many0!(do_parse!(
            tag_s!(" ") >>
            flag: flag_perm >>
            (flag)
        )) >> ({
            let mut res = vec![flag0];
            res.extend(flags);
            res
        })
    ))) >>
    tag_s!(")") >> ({
        ResponseCode::PermanentFlags(if elements.is_some() {
            elements.unwrap()
        } else {
            Vec::new()
        })
    })
));

named!(resp_text_code_highest_mod_seq<ResponseCode>, dbg_dmp!(do_parse!(
    tag_s!("HIGHESTMODSEQ ") >>
    num: number_64 >>
    (ResponseCode::HighestModSeq(num))
)));

named!(resp_text_code_read_only<ResponseCode>, do_parse!(
    tag_s!("READ-ONLY") >>
    (ResponseCode::ReadOnly)
));

named!(resp_text_code_read_write<ResponseCode>, do_parse!(
    tag_s!("READ-WRITE") >>
    (ResponseCode::ReadWrite)
));

named!(resp_text_code_try_create<ResponseCode>, do_parse!(
    tag_s!("TRYCREATE") >>
    (ResponseCode::TryCreate)
));

named!(resp_text_code_uid_validity<ResponseCode>, do_parse!(
    tag_s!("UIDVALIDITY ") >>
    num: number >>
    (ResponseCode::UidValidity(num))
));

named!(resp_text_code_uid_next<ResponseCode>, do_parse!(
    tag_s!("UIDNEXT ") >>
    num: number >>
    (ResponseCode::UidNext(num))
));

named!(resp_text_code<ResponseCode>, do_parse!(
    tag_s!("[") >>
    coded: alt!(
        resp_text_code_permanent_flags |
        resp_text_code_uid_validity |
        resp_text_code_uid_next |
        resp_text_code_read_only |
        resp_text_code_read_write |
        resp_text_code_try_create |
        resp_text_code_highest_mod_seq
    ) >>
    // Per the spec, the closing tag should be "] ".
    // See `resp_text` for more on why this is done differently.
    tag_s!("]") >>
    (coded)
));

named!(capability<&str>, do_parse!(
    tag_s!(" ") >>
    atom: take_till1_s!(atom_specials) >>
    (str::from_utf8(atom).unwrap())
));

named!(capability_data<Response>, do_parse!(
    tag_s!("CAPABILITY") >>
    capabilities: many1!(capability) >>
    (Response::Capabilities(capabilities))
));

named!(mailbox_data_flags<Response>, do_parse!(
    tag_s!("FLAGS ") >>
    flags: flag_list >>
    (Response::MailboxData(MailboxDatum::Flags(flags)))
));

named!(mailbox_data_exists<Response>, do_parse!(
    num: number >>
    tag_s!(" EXISTS") >>
    (Response::MailboxData(MailboxDatum::Exists(num)))
));

named!(mailbox_data_recent<Response>, do_parse!(
    num: number >>
    tag_s!(" RECENT") >>
    (Response::MailboxData(MailboxDatum::Recent(num)))
));

named!(mailbox_data<Response>, alt!(
    mailbox_data_flags |
    mailbox_data_exists |
    mailbox_data_recent
));

named!(nstring<Option<&str>>, map!(
    alt!(
        map!(tag_s!("NIL"), |s| str::from_utf8(s).unwrap()) |
        quoted
    ),
    |s| if s == "NIL" { None } else { Some(s) }
));

named!(address<Address>, do_parse!(
    tag_s!("(") >>
    name: nstring >>
    tag_s!(" ") >>
    adl: nstring >>
    tag_s!(" ") >>
    mailbox: nstring >>
    tag_s!(" ") >>
    host: nstring >>
    tag_s!(")") >>
    (Address { name, adl, mailbox, host })
));

named!(opt_addresses<Option<Vec<Address>>>, alt!(
    map!(tag_s!("NIL"), |s| None) |
    do_parse!(
        tag_s!("(") >>
        addrs: many1!(address) >>
        tag_s!(")") >>
        (Some(addrs))
    )
));

named!(msg_att_envelope<AttributeValue>, do_parse!(
    tag_s!("ENVELOPE (") >>
    date: nstring >>
    tag_s!(" ") >>
    subject: nstring >>
    tag_s!(" ") >>
    from: opt_addresses >>
    tag_s!(" ") >>
    sender: opt_addresses >>
    tag_s!(" ") >>
    reply_to: opt_addresses >>
    tag_s!(" ") >>
    to: opt_addresses >>
    tag_s!(" ") >>
    cc: opt_addresses >>
    tag_s!(" ") >>
    bcc: opt_addresses >>
    tag_s!(" ") >>
    in_reply_to: nstring >>
    tag_s!(" ") >>
    message_id: nstring >>
    tag_s!(")") >> ({
        AttributeValue::Envelope(Envelope {
            date, subject, from, sender, reply_to, to, cc, bcc, in_reply_to, message_id
        })
    })
));

named!(msg_att_internal_date<AttributeValue>, do_parse!(
    tag_s!("INTERNALDATE ") >>
    date: nstring >>
    (AttributeValue::InternalDate(date.unwrap()))
));

named!(msg_att_flags<AttributeValue>, do_parse!(
    tag_s!("FLAGS ") >>
    flags: flag_list >>
    (AttributeValue::Flags(flags))
));

named!(msg_att_rfc822_size<AttributeValue>, do_parse!(
    tag_s!("RFC822.SIZE ") >>
    num: number >>
    (AttributeValue::Rfc822Size(num))
));

named!(msg_att_mod_seq<AttributeValue>, do_parse!(
    tag_s!("MODSEQ (") >>
    num: number_64 >>
    tag_s!(")") >>
    (AttributeValue::ModSeq(num))
));

named!(msg_att<AttributeValue>, alt!(
    msg_att_envelope |
    msg_att_internal_date |
    msg_att_flags |
    msg_att_mod_seq |
    msg_att_rfc822_size
));

named!(msg_att_list<Vec<AttributeValue>>, do_parse!(
    tag_s!("(") >>
    elements: do_parse!(
        attr0: msg_att >>
        attrs: many0!(do_parse!(
            tag_s!(" ") >>
            attr: msg_att >>
            (attr)
        )) >> ({
            let mut res = vec![attr0];
            res.extend(attrs);
            res
        })
    ) >>
    tag_s!(")") >>
    (elements)
));

named!(message_data_fetch<Response>, do_parse!(
    num: number >>
    tag_s!(" FETCH ") >>
    attrs: msg_att_list >>
    (Response::Fetch(num, attrs))
));

named!(message_data_expunge<Response>, do_parse!(
    num: number >>
    tag_s!(" EXPUNGE") >>
    (Response::Expunge(num))
));

named!(tag<RequestId>, map!(take_while1_s!(tag_char),
    |s| RequestId(str::from_utf8(s).unwrap().to_string())
));

// This is not quite according to spec, which mandates the following:
//     ["[" resp-text-code "]" SP] text
// However, examples in RFC 4551 (Conditional STORE) counteract this by giving
// examples of `resp-text` that do not include the trailing space and text.
named!(resp_text<(Option<ResponseCode>, Option<&str>)>, do_parse!(
    code: opt!(resp_text_code) >>
    text: text >>
    ({
        let res = if text.len() < 1 {
            None
        } else if code.is_some() {
            Some(&text[1..])
        } else {
            Some(text)
        };
        (code, res)
    })
));

named!(response_tagged<Response>, do_parse!(
    tag: tag >>
    tag_s!(" ") >>
    status: status >>
    tag_s!(" ") >>
    text: resp_text >>
    tag_s!("\r\n") >>
    (Response::Done(tag, status, text.0, text.1))
));

named!(resp_cond<Response>, do_parse!(
    status: status >>
    tag_s!(" ") >>
    text: resp_text >>
    (Response::Data(status, text.0, text.1))
));

named!(response_data<Response>, do_parse!(
    tag_s!("* ") >>
    contents: alt!(
        resp_cond |
        mailbox_data |
        message_data_expunge |
        message_data_fetch |
        capability_data
    ) >>
    tag_s!("\r\n") >>
    (contents)
));

named!(response<Response>, alt!(
    response_data |
    response_tagged
));

pub fn parse(msg: &[u8]) -> Option<(Response, usize)> {
    match response(msg) {
        IResult::Done(remaining, res) =>
            Some((res, msg.len() - remaining.len())),
        IResult::Incomplete(_) => None,
        IResult::Error(err) =>
            panic!("error {} during parsing of {:?}", err, msg),
    }
}
<commit_msg>Fix handling of escaped quote characters in quoted strings<commit_after>use nom::{self, IResult};
use std::str;
use proto::{Address, AttributeValue, Envelope, MailboxDatum};
use proto::{RequestId, Response, ResponseCode, Status};

fn crlf(c: u8) -> bool {
    c == b'\r' || c == b'\n'
}

fn list_wildcards(c: u8) -> bool {
    c == b'%' || c == b'*'
}

fn quoted_specials(c: u8) -> bool {
    c == b'"' || c == b'\\'
}

fn resp_specials(c: u8) -> bool {
    c == b']'
}

fn atom_specials(c: u8) -> bool {
    c == b'(' || c == b')' || c == b'{' || c == b' ' || c < 32 ||
    list_wildcards(c) || quoted_specials(c) || resp_specials(c)
}

fn atom_char(c: u8) -> bool {
    !atom_specials(c)
}

fn astring_char(c: u8) -> bool {
    atom_char(c) || resp_specials(c)
}

fn tag_char(c: u8) -> bool {
    c != b'+' && astring_char(c)
}

// Ideally this should use nom's `escaped` macro, but it suffers from broken
// type inference unless compiled with the verbose-errors feature enabled.
fn quoted_data(i: &[u8]) -> IResult<&[u8], &str> {
    let mut escape = false;
    let mut len = 0;
    for c in i {
        if *c == b'"' && !escape {
            break;
        }
        len += 1;
        if *c == b'\\' && !escape {
            escape = true
        } else if escape {
            escape = false;
        }
    }
    IResult::Done(&i[len..], str::from_utf8(&i[..len]).unwrap())
}

named!(quoted<&str>, do_parse!(
    tag_s!("\"") >>
    data: quoted_data >>
    tag_s!("\"") >>
    (data)
));

named!(status_ok<Status>, map!(tag_no_case!("OK"),
    |s| Status::Ok
));
named!(status_no<Status>, map!(tag_no_case!("NO"),
    |s| Status::No
));
named!(status_bad<Status>, map!(tag_no_case!("BAD"),
    |s| Status::Bad
));
named!(status_preauth<Status>, map!(tag_no_case!("PREAUTH"),
    |s| Status::PreAuth
));
named!(status_bye<Status>, map!(tag_no_case!("BYE"),
    |s| Status::Bye
));

named!(status<Status>, alt!(
    status_ok |
    status_no |
    status_bad |
    status_preauth |
    status_bye
));

named!(number<u32>, map!(nom::digit,
    |s| str::parse(str::from_utf8(s).unwrap()).unwrap()
));

named!(number_64<u64>, map!(nom::digit,
    |s| str::parse(str::from_utf8(s).unwrap()).unwrap()
));

named!(text<&str>, map!(take_till_s!(crlf),
    |s| str::from_utf8(s).unwrap()
));

named!(atom<&str>, map!(take_while1_s!(atom_char),
    |s| str::from_utf8(s).unwrap()
));

fn flag_extension(i: &[u8]) -> IResult<&[u8], &str> {
    if i.len() < 1 || i[0] != b'\\' {
        return IResult::Error(nom::ErrorKind::Custom(0));
    }
    let mut last = 0;
    for (idx, c) in i[1..].iter().enumerate() {
        last = idx;
        if !atom_char(*c) {
            break;
        }
    }
    IResult::Done(&i[last + 1..], str::from_utf8(&i[..last + 1]).unwrap())
}

named!(flag<&str>, alt!(flag_extension | atom));

named!(flag_list<Vec<&str>>, do_parse!(
    tag_s!("(") >>
    elements: opt!(do_parse!(
        flag0: flag >>
        flags: many0!(do_parse!(
            tag_s!(" ") >>
            flag: flag >>
            (flag)
        )) >> ({
            let mut res = vec![flag0];
            res.extend(flags);
            res
        })
    )) >>
    tag_s!(")") >> ({
       if elements.is_some() {
           elements.unwrap()
       } else {
           Vec::new()
       }
    })
));

named!(flag_perm<&str>, alt!(
    map!(tag_s!("\\*"), |s| str::from_utf8(s).unwrap()) |
    flag
));

named!(resp_text_code_permanent_flags<ResponseCode>, do_parse!(
    tag_s!("PERMANENTFLAGS (") >>
    elements: dbg_dmp!(opt!(do_parse!(
        flag0: flag_perm >>
        flags: many0!(do_parse!(
            tag_s!(" ") >>
            flag: flag_perm >>
            (flag)
        )) >> ({
            let mut res = vec![flag0];
            res.extend(flags);
            res
        })
    ))) >>
    tag_s!(")") >> ({
        ResponseCode::PermanentFlags(if elements.is_some() {
            elements.unwrap()
        } else {
            Vec::new()
        })
    })
));

named!(resp_text_code_highest_mod_seq<ResponseCode>, dbg_dmp!(do_parse!(
    tag_s!("HIGHESTMODSEQ ") >>
    num: number_64 >>
    (ResponseCode::HighestModSeq(num))
)));

named!(resp_text_code_read_only<ResponseCode>, do_parse!(
    tag_s!("READ-ONLY") >>
    (ResponseCode::ReadOnly)
));

named!(resp_text_code_read_write<ResponseCode>, do_parse!(
    tag_s!("READ-WRITE") >>
    (ResponseCode::ReadWrite)
));

named!(resp_text_code_try_create<ResponseCode>, do_parse!(
    tag_s!("TRYCREATE") >>
    (ResponseCode::TryCreate)
));

named!(resp_text_code_uid_validity<ResponseCode>, do_parse!(
    tag_s!("UIDVALIDITY ") >>
    num: number >>
    (ResponseCode::UidValidity(num))
));

named!(resp_text_code_uid_next<ResponseCode>, do_parse!(
    tag_s!("UIDNEXT ") >>
    num: number >>
    (ResponseCode::UidNext(num))
));

named!(resp_text_code<ResponseCode>, do_parse!(
    tag_s!("[") >>
    coded: alt!(
        resp_text_code_permanent_flags |
        resp_text_code_uid_validity |
        resp_text_code_uid_next |
        resp_text_code_read_only |
        resp_text_code_read_write |
        resp_text_code_try_create |
        resp_text_code_highest_mod_seq
    ) >>
    // Per the spec, the closing tag should be "] ".
    // See `resp_text` for more on why this is done differently.
    tag_s!("]") >>
    (coded)
));

named!(capability<&str>, do_parse!(
    tag_s!(" ") >>
    atom: take_till1_s!(atom_specials) >>
    (str::from_utf8(atom).unwrap())
));

named!(capability_data<Response>, do_parse!(
    tag_s!("CAPABILITY") >>
    capabilities: many1!(capability) >>
    (Response::Capabilities(capabilities))
));

named!(mailbox_data_flags<Response>, do_parse!(
    tag_s!("FLAGS ") >>
    flags: flag_list >>
    (Response::MailboxData(MailboxDatum::Flags(flags)))
));

named!(mailbox_data_exists<Response>, do_parse!(
    num: number >>
    tag_s!(" EXISTS") >>
    (Response::MailboxData(MailboxDatum::Exists(num)))
));

named!(mailbox_data_recent<Response>, do_parse!(
    num: number >>
    tag_s!(" RECENT") >>
    (Response::MailboxData(MailboxDatum::Recent(num)))
));

named!(mailbox_data<Response>, alt!(
    mailbox_data_flags |
    mailbox_data_exists |
    mailbox_data_recent
));

named!(nstring<Option<&str>>, map!(
    alt!(
        map!(tag_s!("NIL"), |s| str::from_utf8(s).unwrap()) |
        quoted
    ),
    |s| if s == "NIL" { None } else { Some(s) }
));

named!(address<Address>, do_parse!(
    tag_s!("(") >>
    name: nstring >>
    tag_s!(" ") >>
    adl: nstring >>
    tag_s!(" ") >>
    mailbox: nstring >>
    tag_s!(" ") >>
    host: nstring >>
    tag_s!(")") >>
    (Address { name, adl, mailbox, host })
));

named!(opt_addresses<Option<Vec<Address>>>, alt!(
    map!(tag_s!("NIL"), |s| None) |
    do_parse!(
        tag_s!("(") >>
        addrs: many1!(address) >>
        tag_s!(")") >>
        (Some(addrs))
    )
));

named!(msg_att_envelope<AttributeValue>, do_parse!(
    tag_s!("ENVELOPE (") >>
    date: nstring >>
    tag_s!(" ") >>
    subject: nstring >>
    tag_s!(" ") >>
    from: opt_addresses >>
    tag_s!(" ") >>
    sender: opt_addresses >>
    tag_s!(" ") >>
    reply_to: opt_addresses >>
    tag_s!(" ") >>
    to: opt_addresses >>
    tag_s!(" ") >>
    cc: opt_addresses >>
    tag_s!(" ") >>
    bcc: opt_addresses >>
    tag_s!(" ") >>
    in_reply_to: nstring >>
    tag_s!(" ") >>
    message_id: nstring >>
    tag_s!(")") >> ({
        AttributeValue::Envelope(Envelope {
            date, subject, from, sender, reply_to, to, cc, bcc, in_reply_to, message_id
        })
    })
));

named!(msg_att_internal_date<AttributeValue>, do_parse!(
    tag_s!("INTERNALDATE ") >>
    date: nstring >>
    (AttributeValue::InternalDate(date.unwrap()))
));

named!(msg_att_flags<AttributeValue>, do_parse!(
    tag_s!("FLAGS ") >>
    flags: flag_list >>
    (AttributeValue::Flags(flags))
));

named!(msg_att_rfc822_size<AttributeValue>, do_parse!(
    tag_s!("RFC822.SIZE ") >>
    num: number >>
    (AttributeValue::Rfc822Size(num))
));

named!(msg_att_mod_seq<AttributeValue>, do_parse!(
    tag_s!("MODSEQ (") >>
    num: number_64 >>
    tag_s!(")") >>
    (AttributeValue::ModSeq(num))
));

named!(msg_att<AttributeValue>, alt!(
    msg_att_envelope |
    msg_att_internal_date |
    msg_att_flags |
    msg_att_mod_seq |
    msg_att_rfc822_size
));

named!(msg_att_list<Vec<AttributeValue>>, do_parse!(
    tag_s!("(") >>
    elements: do_parse!(
        attr0: msg_att >>
        attrs: many0!(do_parse!(
            tag_s!(" ") >>
            attr: msg_att >>
            (attr)
        )) >> ({
            let mut res = vec![attr0];
            res.extend(attrs);
            res
        })
    ) >>
    tag_s!(")") >>
    (elements)
));

named!(message_data_fetch<Response>, do_parse!(
    num: number >>
    tag_s!(" FETCH ") >>
    attrs: msg_att_list >>
    (Response::Fetch(num, attrs))
));

named!(message_data_expunge<Response>, do_parse!(
    num: number >>
    tag_s!(" EXPUNGE") >>
    (Response::Expunge(num))
));

named!(tag<RequestId>, map!(take_while1_s!(tag_char),
    |s| RequestId(str::from_utf8(s).unwrap().to_string())
));

// This is not quite according to spec, which mandates the following:
//     ["[" resp-text-code "]" SP] text
// However, examples in RFC 4551 (Conditional STORE) counteract this by giving
// examples of `resp-text` that do not include the trailing space and text.
named!(resp_text<(Option<ResponseCode>, Option<&str>)>, do_parse!(
    code: opt!(resp_text_code) >>
    text: text >>
    ({
        let res = if text.len() < 1 {
            None
        } else if code.is_some() {
            Some(&text[1..])
        } else {
            Some(text)
        };
        (code, res)
    })
));

named!(response_tagged<Response>, do_parse!(
    tag: tag >>
    tag_s!(" ") >>
    status: status >>
    tag_s!(" ") >>
    text: resp_text >>
    tag_s!("\r\n") >>
    (Response::Done(tag, status, text.0, text.1))
));

named!(resp_cond<Response>, do_parse!(
    status: status >>
    tag_s!(" ") >>
    text: resp_text >>
    (Response::Data(status, text.0, text.1))
));

named!(response_data<Response>, do_parse!(
    tag_s!("* ") >>
    contents: alt!(
        resp_cond |
        mailbox_data |
        message_data_expunge |
        message_data_fetch |
        capability_data
    ) >>
    tag_s!("\r\n") >>
    (contents)
));

named!(response<Response>, alt!(
    response_data |
    response_tagged
));

pub fn parse(msg: &[u8]) -> Option<(Response, usize)> {
    match response(msg) {
        IResult::Done(remaining, res) =>
            Some((res, msg.len() - remaining.len())),
        IResult::Incomplete(_) => None,
        IResult::Error(err) =>
            panic!("error {} during parsing of {:?}", err, msg),
    }
}
<|endoftext|>


<commit_before>use ast::*;
use scanner::{Token, TokenWithContext};
use std::iter::Peekable;

/// This behave exactly as try! but wraps the returned result in a Some.
/// It's useful to remove some boilerplate in the code introduced by
/// the use of Option<Result<T, E>>
macro_rules! try_wrap_err {
    ($e:expr) => (match $e {Ok(e) => e, Err(e) => return Some(Err(e))})
}

#[derive(Debug)]
pub struct ParseError {
    message: String,
}

impl ParseError {
    fn from_message(message: String) -> ParseError {
        ParseError { message: message }
    }
}

pub fn parse(tokens: Vec<TokenWithContext>) -> Result<Expr, Vec<ParseError>> {
    let mut iter = tokens.iter().peekable();
    if let Some(result) = parse_expression(&mut iter) {
        match result {
            Ok(expr) => {
                if let None = iter.next() {
                    Ok(expr)
                } else {
                    Err(vec![ParseError::from_message("Parser didn't consume all the tokens"
                                 .into())])
                }
            }
            Err(error) => {
                {
                    synchronise(&mut iter);
                }
                Err(vec![error])
            }
        }

    } else {
        Err(vec![ParseError::from_message("Parser didn't return anything".into())])
    }
}

fn synchronise<'a, I>(tokens: &mut Peekable<I>)
    where I: Iterator<Item = &'a TokenWithContext>
{
    while let Some(token_with_context) = tokens.peek().cloned() {
        match token_with_context.token {
            Token::Semicolon => {
                let _ = tokens.next();
                break;
            }
            Token::Class => break,
            Token::Fun => break,
            Token::Var => break,
            Token::For => break,
            Token::If => break,
            Token::While => break,
            Token::Print => break,
            Token::Return => break,
            _ => {
                let _ = tokens.next();
            }
        }
    }
}

fn parse_expression<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    parse_equality(tokens)
}

fn parse_binary<'a, I>(tokens: &mut Peekable<I>,
                       map_operator: &Fn(&Token) -> Option<Operator>,
                       parse_subexpression: &Fn(&mut Peekable<I>)
                                                -> Option<Result<Expr, ParseError>>)
                       -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    let mut expr;
    {
        let result = parse_subexpression(tokens);
        if let Some(Ok(subexpression)) =  result{
            expr = subexpression;
        } else {
            return result;
        }
    };
    while let Some(Some(mapped_operator)) = tokens.peek().map(|pt| map_operator(&pt.token)) {
        let operator; // We know it's right, we read it just for error reporting
        {
            operator = tokens.next().unwrap();
        }
        let right;
        {
            if let Some(result) = parse_subexpression(tokens) {
                right = try_wrap_err!(result);
            } else {
                return Some(Err(ParseError::from_message(format!("Expected subexpression \
                                                                  after {:?} at {:?}",
                                                                 operator.lexeme,
                                                                 operator.position))));
            }
        };
        let binary_expression = BinaryExpr {
            left: expr,
            operator: mapped_operator,
            right: right,
        };
        expr = Expr::Binary(Box::new(binary_expression));
    }
    Some(Ok(expr))
}

fn parse_equality<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::BangEqual => Some(Operator::NotEqual),
            &Token::EqualEqual => Some(Operator::Equal),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_comparison)
}

fn parse_comparison<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::Greater => Some(Operator::Greater),
            &Token::GreaterEqual => Some(Operator::GreaterEqual),
            &Token::Less => Some(Operator::Less),
            &Token::LessEqual => Some(Operator::LessEqual),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_term)
}

fn parse_term<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::Minus => Some(Operator::Minus),
            &Token::Plus => Some(Operator::Plus),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_factor)
}

fn parse_factor<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::Slash => Some(Operator::Slash),
            &Token::Star => Some(Operator::Star),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_unary)
}

fn parse_unary<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::Minus => Some(Operator::Minus),
            &Token::Bang => Some(Operator::Bang),
            _ => None,
        }
    }
    if let Some(Some(mapped_operator)) = tokens.peek().cloned().map(|pt| map_operator(&pt.token)) {
        let operator; // For error reporting
        {
            operator = tokens.next().unwrap();
        }
        let right;
        {
            if let Some(result) = parse_unary(tokens) {
                right = try_wrap_err!(result);
            } else {
                return Some(Err(ParseError::from_message(format!("Expected subexpression \
                                                                  after {:?} at {:?}",
                                                                 operator.lexeme,
                                                                 operator.position))));
            }
        };
        let unary_expression = UnaryExpr {
            operator: mapped_operator,
            right: right,
        };
        return Some(Ok(Expr::Unary(Box::new(unary_expression))));
    } else {
        parse_primary(tokens)
    }
}

fn parse_primary<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    let primary_token;
    {
        primary_token = tokens.next();
    };
    if let Some(primary_token) = primary_token {
        let parsed_expression = match primary_token.token {
            Token::False => Expr::Literal(Literal::BoolLiteral(false)),
            Token::True => Expr::Literal(Literal::BoolLiteral(true)),
            Token::Nil => Expr::Literal(Literal::NilLiteral),
            Token::NumberLiteral(n) => Expr::Literal(Literal::NumberLiteral(n)),
            Token::StringLiteral(ref s) => Expr::Literal(Literal::StringLiteral(s.clone())),
            Token::LeftParen => {
                let expr;
                {
                    if let Some(result) = parse_expression(tokens) {
                        expr = try_wrap_err!(result);
                    } else {
                        return Some(Err(ParseError::from_message(format!("Unfinished grouping \
                                                                     expression near {:?} at \
                                                                     {:?}",
                                                                         primary_token.lexeme,
                                                                         primary_token.position))));
                    }
                };
                {
                    if let Some(token) = tokens.next() {
                        if token.token == Token::RightParen {
                            let grouping_expression = Grouping { expr: expr };
                            return Some(Ok(Expr::Grouping(Box::new(grouping_expression))));
                        } else {
                            return Some(Err(ParseError::from_message(format!("Missing ) near \
                                                                              {:?} at {:?}",
                                                                             token.lexeme,
                                                                             token.position))));
                        }

                    }
                    return Some(Err(ParseError::from_message(format!("Missing ) before end of \
                                                                      file"))));
                }
            }
            _ => {
                return Some(Err(ParseError::from_message(format!("Unexpected token {:?} at \
                                                                  {:?}",
                                                                 primary_token.lexeme,
                                                                 primary_token.position))));
            }
        };
        Some(Ok(parsed_expression))
    } else {
        None
    }
}

#[cfg(test)]
mod tests {
    use scanner::*;
    use parser::*;
    use pretty_printer::PrettyPrint;

    #[test]
    fn literal() {
        let (tokens, _) = scan(&"123".into());
        let expr = parse(tokens).unwrap();
        assert_eq!("123", &expr.pretty_print());
    }

    #[test]
    fn binary() {
        let (tokens, _) = scan(&"123+456".into());
        let expr = parse(tokens).unwrap();
        assert_eq!("(+ 123 456)", &expr.pretty_print());
    }

    #[test]
    fn precedence_add_mul() {
        let (tokens, _) = scan(&"123+456*789".into());
        let expr = parse(tokens).unwrap();
        assert_eq!("(+ 123 (* 456 789))", &expr.pretty_print());
    }

    #[test]
    fn precedence_mul_add() {
        let (tokens, _) = scan(&"123*456+789".into());
        let expr = parse(tokens).unwrap();
        assert_eq!("(+ (* 123 456) 789)", &expr.pretty_print());
    }

    #[test]
    fn precedence_mul_add_unary() {
        let (tokens, _) = scan(&"-123*456+789".into());
        let expr = parse(tokens).unwrap();
        assert_eq!("(+ (* (- 123) 456) 789)", &expr.pretty_print());
    }

    #[test]
    fn unclosed_group() {
        let (tokens, _) = scan(&"(2".into());
        assert!(parse(tokens).is_err());
    }

    #[test]
    fn unopened_group() {
        let (tokens, _) = scan(&"2)".into());
        assert!(parse(tokens).is_err());
    }
}
<commit_msg>Prevented unnecessary clone<commit_after>use ast::*;
use scanner::{Token, TokenWithContext};
use std::iter::Peekable;

/// This behave exactly as try! but wraps the returned result in a Some.
/// It's useful to remove some boilerplate in the code introduced by
/// the use of Option<Result<T, E>>
macro_rules! try_wrap_err {
    ($e:expr) => (match $e {Ok(e) => e, Err(e) => return Some(Err(e))})
}

#[derive(Debug)]
pub struct ParseError {
    message: String,
}

impl ParseError {
    fn from_message(message: String) -> ParseError {
        ParseError { message: message }
    }
}

pub fn parse(tokens: Vec<TokenWithContext>) -> Result<Expr, Vec<ParseError>> {
    let mut iter = tokens.iter().peekable();
    if let Some(result) = parse_expression(&mut iter) {
        match result {
            Ok(expr) => {
                if let None = iter.next() {
                    Ok(expr)
                } else {
                    Err(vec![ParseError::from_message("Parser didn't consume all the tokens"
                                 .into())])
                }
            }
            Err(error) => {
                {
                    synchronise(&mut iter);
                }
                Err(vec![error])
            }
        }

    } else {
        Err(vec![ParseError::from_message("Parser didn't return anything".into())])
    }
}

fn synchronise<'a, I>(tokens: &mut Peekable<I>)
    where I: Iterator<Item = &'a TokenWithContext>
{
    enum TokenKind{
        StartOfConstruct,
        BodyOfConstruct,
        EndOfConstruct,
    };
    fn classify(token: &Token) -> TokenKind{
        match token {
            &Token::Semicolon => TokenKind::EndOfConstruct,
            &Token::Class => TokenKind::StartOfConstruct,
            &Token::Fun => TokenKind::StartOfConstruct,
            &Token::Var => TokenKind::StartOfConstruct,
            &Token::For => TokenKind::StartOfConstruct,
            &Token::If => TokenKind::StartOfConstruct,
            &Token::While => TokenKind::StartOfConstruct,
            &Token::Print => TokenKind::StartOfConstruct,
            &Token::Return => TokenKind::StartOfConstruct,
            _ => TokenKind::BodyOfConstruct
    }
    }
    while let Some(token_kind) = tokens.peek().map(|t|classify(&t.token)) {
        match token_kind {
            TokenKind::StartOfConstruct => {
                break;
            },
            TokenKind::BodyOfConstruct =>{
                let _ = tokens.next();
            }
            TokenKind::EndOfConstruct => {
                let _ = tokens.next();
                break;
            },
        }
    }
}

fn parse_expression<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    parse_equality(tokens)
}

fn parse_binary<'a, I>(tokens: &mut Peekable<I>,
                       map_operator: &Fn(&Token) -> Option<Operator>,
                       parse_subexpression: &Fn(&mut Peekable<I>)
                                                -> Option<Result<Expr, ParseError>>)
                       -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    let mut expr;
    {
        let result = parse_subexpression(tokens);
        if let Some(Ok(subexpression)) =  result{
            expr = subexpression;
        } else {
            return result;
        }
    };
    while let Some(Some(mapped_operator)) = tokens.peek().map(|pt| map_operator(&pt.token)) {
        let operator; // We know it's right, we read it just for error reporting
        {
            operator = tokens.next().unwrap();
        }
        let right;
        {
            if let Some(result) = parse_subexpression(tokens) {
                right = try_wrap_err!(result);
            } else {
                return Some(Err(ParseError::from_message(format!("Expected subexpression \
                                                                  after {:?} at {:?}",
                                                                 operator.lexeme,
                                                                 operator.position))));
            }
        };
        let binary_expression = BinaryExpr {
            left: expr,
            operator: mapped_operator,
            right: right,
        };
        expr = Expr::Binary(Box::new(binary_expression));
    }
    Some(Ok(expr))
}

fn parse_equality<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::BangEqual => Some(Operator::NotEqual),
            &Token::EqualEqual => Some(Operator::Equal),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_comparison)
}

fn parse_comparison<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::Greater => Some(Operator::Greater),
            &Token::GreaterEqual => Some(Operator::GreaterEqual),
            &Token::Less => Some(Operator::Less),
            &Token::LessEqual => Some(Operator::LessEqual),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_term)
}

fn parse_term<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::Minus => Some(Operator::Minus),
            &Token::Plus => Some(Operator::Plus),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_factor)
}

fn parse_factor<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::Slash => Some(Operator::Slash),
            &Token::Star => Some(Operator::Star),
            _ => None,
        }
    }
    parse_binary(tokens, &map_operator, &parse_unary)
}

fn parse_unary<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    fn map_operator(token: &Token) -> Option<Operator> {
        match token {
            &Token::Minus => Some(Operator::Minus),
            &Token::Bang => Some(Operator::Bang),
            _ => None,
        }
    }
    if let Some(Some(mapped_operator)) = tokens.peek().cloned().map(|pt| map_operator(&pt.token)) {
        let operator; // For error reporting
        {
            operator = tokens.next().unwrap();
        }
        let right;
        {
            if let Some(result) = parse_unary(tokens) {
                right = try_wrap_err!(result);
            } else {
                return Some(Err(ParseError::from_message(format!("Expected subexpression \
                                                                  after {:?} at {:?}",
                                                                 operator.lexeme,
                                                                 operator.position))));
            }
        };
        let unary_expression = UnaryExpr {
            operator: mapped_operator,
            right: right,
        };
        return Some(Ok(Expr::Unary(Box::new(unary_expression))));
    } else {
        parse_primary(tokens)
    }
}

fn parse_primary<'a, I>(tokens: &mut Peekable<I>) -> Option<Result<Expr, ParseError>>
    where I: Iterator<Item = &'a TokenWithContext>
{
    let primary_token;
    {
        primary_token = tokens.next();
    };
    if let Some(primary_token) = primary_token {
        let parsed_expression = match primary_token.token {
            Token::False => Expr::Literal(Literal::BoolLiteral(false)),
            Token::True => Expr::Literal(Literal::BoolLiteral(true)),
            Token::Nil => Expr::Literal(Literal::NilLiteral),
            Token::NumberLiteral(n) => Expr::Literal(Literal::NumberLiteral(n)),
            Token::StringLiteral(ref s) => Expr::Literal(Literal::StringLiteral(s.clone())),
            Token::LeftParen => {
                let expr;
                {
                    if let Some(result) = parse_expression(tokens) {
                        expr = try_wrap_err!(result);
                    } else {
                        return Some(Err(ParseError::from_message(format!("Unfinished grouping \
                                                                     expression near {:?} at \
                                                                     {:?}",
                                                                         primary_token.lexeme,
                                                                         primary_token.position))));
                    }
                };
                {
                    if let Some(token) = tokens.next() {
                        if token.token == Token::RightParen {
                            let grouping_expression = Grouping { expr: expr };
                            return Some(Ok(Expr::Grouping(Box::new(grouping_expression))));
                        } else {
                            return Some(Err(ParseError::from_message(format!("Missing ) near \
                                                                              {:?} at {:?}",
                                                                             token.lexeme,
                                                                             token.position))));
                        }

                    }
                    return Some(Err(ParseError::from_message(format!("Missing ) before end of \
                                                                      file"))));
                }
            }
            _ => {
                return Some(Err(ParseError::from_message(format!("Unexpected token {:?} at \
                                                                  {:?}",
                                                                 primary_token.lexeme,
                                                                 primary_token.position))));
            }
        };
        Some(Ok(parsed_expression))
    } else {
        None
    }
}

#[cfg(test)]
mod tests {
    use scanner::*;
    use parser::*;
    use pretty_printer::PrettyPrint;

    #[test]
    fn literal() {
        let (tokens, _) = scan(&"123".into());
        let expr = parse(tokens).unwrap();
        assert_eq!("123", &expr.pretty_print());
    }

    #[test]
    fn binary() {
        let (tokens, _) = scan(&"123+456".into());
        let expr = parse(tokens).unwrap();
        assert_eq!("(+ 123 456)", &expr.pretty_print());
    }

    #[test]
    fn precedence_add_mul() {
        let (tokens, _) = scan(&"123+456*789".into());
        let expr = parse(tokens).unwrap();
        assert_eq!("(+ 123 (* 456 789))", &expr.pretty_print());
    }

    #[test]
    fn precedence_mul_add() {
        let (tokens, _) = scan(&"123*456+789".into());
        let expr = parse(tokens).unwrap();
        assert_eq!("(+ (* 123 456) 789)", &expr.pretty_print());
    }

    #[test]
    fn precedence_mul_add_unary() {
        let (tokens, _) = scan(&"-123*456+789".into());
        let expr = parse(tokens).unwrap();
        assert_eq!("(+ (* (- 123) 456) 789)", &expr.pretty_print());
    }

    #[test]
    fn unclosed_group() {
        let (tokens, _) = scan(&"(2".into());
        assert!(parse(tokens).is_err());
    }

    #[test]
    fn unopened_group() {
        let (tokens, _) = scan(&"2)".into());
        assert!(parse(tokens).is_err());
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 Maciej Piechotka
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

extern mod xml;

#[test]
fn test_simple_parse() {
    let xml = "<?xml version=\"1.0\"?> <test />".as_bytes();
    let doc = xml::read_memory(xml).unwrap();
    let root = doc.get_root_element().unwrap();
    assert_eq!(root.name(), ~"test");
    assert!(root.children_iter().next().is_none());
}

#[test]
fn test_simple_fail() {
    let xml = "<?xml version=\"1.0\"> <test />".as_bytes();
    let doc = xml::read_memory(xml);
    assert!(doc.is_none());
}

#[test]
fn test_subelements() {
    let xml = "<?xml version=\"1.0\"?> <test>  aaa<c/></test>".as_bytes();
    let doc = xml::read_memory(xml).unwrap();
    let root = doc.get_root_element().unwrap();
    assert_eq!(root.name(), ~"test");
    let mut iter = root.children_iter();
    {
        let cur = iter.next().unwrap().get_text().unwrap();
        assert_eq!(cur.content(), ~" ");
    }
    {
        let cur = iter.next().unwrap().get_element().unwrap();
        assert_eq!(cur.name(), ~"a");
        let mut iter = cur.children_iter();
        {
            let cur = iter.next().unwrap().get_text().unwrap();
            assert_eq!(cur.content(), ~" ");
        }
        {
            let cur = iter.next().unwrap().get_element().unwrap();
            assert_eq!(cur.name(), ~"b");
            assert!(cur.children_iter().next().is_none());
        }
        {
            let cur = iter.next().unwrap().get_text().unwrap();
            assert_eq!(cur.content(), ~"aaa");
        }
        assert!(iter.next().is_none());
    }
    {
        let cur = iter.next().unwrap().get_element().unwrap();
        assert_eq!(cur.name(), ~"c");
        assert!(cur.children_iter().next().is_none());
    }
    assert!(iter.next().is_none());
}
<commit_msg>Add macro DSL for testing<commit_after>/*
 * Copyright (C) 2014 Maciej Piechotka
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#[feature(macro_rules)];

extern mod xml;

macro_rules! expect_root_elem(
    ($root:expr, $iter:ident, $expected_name:expr, $elem_check:expr) => ({
        assert_eq!($root.name(), $expected_name);
        {
            let mut $iter = $root.children_iter();
            $elem_check;
            assert!($iter.next().is_none(), "Unexpected children");
        }
    })
)

macro_rules! expect_elem(
    ($iter:ident, $expected_name:expr, $elem_check:expr) => ({
        let next = ($iter).next();
        assert!(next.is_some(), "Expected element but there is no further element");
        let elem = next.unwrap().get_element();
        assert!(elem.is_some(), "Extected element but got other children");
        let cur = elem.unwrap();
        {
            let mut $iter = cur.children_iter();
            $elem_check;
            assert!($iter.next().is_none(), "Unexpected children");
        }
    })
)

macro_rules! expect_text(
    ($iter:ident, $expected_text:expr) => ({
        let next = ($iter).next();
        assert!(next.is_some(), "Expected text but there is no further element");
        let text = next.unwrap().get_text();
        assert!(text.is_some(), "Extected text but got other children");
        let cur = text.unwrap();
        assert_eq!(cur.content(), $expected_text);
    });
)

#[test]
fn test_simple_fail() {
    let xml = "<?xml version=\"1.0\"> <test />".as_bytes();
    let doc = xml::read_memory(xml);
    assert!(doc.is_none());
}

#[test]
fn test_simple_parse() {
    let xml = "<?xml version=\"1.0\"?> <test />".as_bytes();
    let doc = xml::read_memory(xml).unwrap();
    let root = doc.get_root_element().unwrap();
    expect_root_elem!(root, iter, ~"test", {});
}

#[test]
fn test_subelements() {
    let xml = "<?xml version=\"1.0\"?> <test>  aaa<c/></test>".as_bytes();
    let doc = xml::read_memory(xml).unwrap();
    let root = doc.get_root_element().unwrap();
    expect_root_elem!(root, iter, ~"test", {
        expect_text!(iter, ~" ");
        expect_elem!(iter, ~"a", {
            expect_text!(iter, ~" ");
            expect_elem!(iter, ~"b", {});
            expect_text!(iter, ~"aaa");
        });
        expect_elem!(iter, ~"c", {});
    });
}

<|endoftext|>


<commit_before>import xlib::*;
import libc::*;
import cairo_xlib::*;
import xlib::bindgen::*;
import cairo::*;
import cairo::bindgen::*;
import cairo_xlib::bindgen::*;

#[test]
fn sanity_check() {
    AzSanityCheck();
}

const SIZEX: c_uint = 400 as c_uint;
const SIZEY: c_uint = 400 as c_uint;

const ExposureMask: c_long = (1 << 15) as c_long;
const ButtonPressMask: c_long = (1 << 2) as c_long;

const Expose: c_int = 12 as c_int;
const ButtonPress: c_int = 4 as c_int;

type XEventStub = {
    type_: c_int,
    padding: (
        int, int, int, int, int, int, int, int,
        int, int, int, int, int, int, int, int,
        int, int, int, int, int, int, int, int,
        int, int, int, int, int, int, int, int,
        int, int, int, int, int, int, int, int,
        int, int, int, int, int, int, int, int,
        int, int, int, int, int, int, int, int,
        int, int, int, int, int, int, int, int
    )
};

fn xexpose(event: *XEventStub) -> *XExposeEvent unsafe {
    unsafe::reinterpret_cast(ptr::addr_of((*event).padding))
}

#[test]
#[ignore]
fn cairo_it_up() {
    let dpy = XOpenDisplay(ptr::null());
    assert(ptr::is_not_null(dpy));
    let scr = XDefaultScreen(dpy);
    let rootwin = XRootWindow(dpy, scr);
    let win = XCreateSimpleWindow(
        dpy, rootwin, 1 as c_int, 1 as c_int, SIZEX, SIZEY, 0 as c_uint,
        XBlackPixel(dpy, scr), XBlackPixel(dpy, scr));
    str::as_c_str("test") {|cstr|
        XStoreName(dpy, win, cstr);
    }
    XSelectInput(dpy, win, ExposureMask | ButtonPressMask);
    XMapWindow(dpy, win);

    let cs = cairo_xlib_surface_create(
        dpy, win, XDefaultVisual(dpy, 0 as c_int),
        SIZEX as c_int, SIZEY as c_int);

    let e = {
        type_: 0 as c_int,
        padding: (
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
        )
    };
    let ep = ptr::addr_of(e);

    let dt = AzCreateDrawTargetForCairoSurface(cs);

    loop unsafe {
        XNextEvent(dpy, unsafe::reinterpret_cast(ep));
        log(error, *ep);
        log(error, *xexpose(ep));
        if e.type_ == Expose && (*xexpose(ep)).count < 1 as c_int {
            paint(dt);
        } else if e.type_ == ButtonPress {
            break;
        } else {
            paint(dt);
        }
    }

    AzReleaseDrawTarget(dt);
    cairo_surface_destroy(cs);
    XCloseDisplay(dpy);
}

fn paint(dt: AzDrawTargetRef) {
    log(error, "painting");
    let rect = {
        x: 200f as AzFloat,
        y: 200f as AzFloat,
        width: 100f as AzFloat,
        height: 100f as AzFloat
    };
    let color = {
        r: 0f as AzFloat,
        g: 1f as AzFloat,
        b: 0f as AzFloat,
        a: 1f as AzFloat
    };
    let pattern = AzCreateColorPattern(ptr::addr_of(color));
    AzDrawTargetFillRect(
        dt,
        ptr::addr_of(rect),
        unsafe { unsafe::reinterpret_cast(pattern) });
    AzReleaseColorPattern(pattern);
}

#[test]
fn test_draw_target_get_size() {
    let surface = cairo_image_surface_create(
        CAIRO_FORMAT_RGB24, 100 as c_int, 200 as c_int);
    assert surface.is_not_null();
    let dt = AzCreateDrawTargetForCairoSurface(surface);
    assert dt.is_not_null();
    let size = AzDrawTargetGetSize(dt);
    assert size.width == 100 as int32_t;
    assert size.height == 200 as int32_t;
    AzReleaseDrawTarget(dt);
    cairo_surface_destroy(surface);
}

#[test]
#[ignore]
fn fonts() {
    import cairo::*;
    import cairo::bindgen::*;

    let dpy = XOpenDisplay(ptr::null());
    assert(ptr::is_not_null(dpy));
    let scr = XDefaultScreen(dpy);
    let rootwin = XRootWindow(dpy, scr);
    let win = XCreateSimpleWindow(
        dpy, rootwin, 1 as c_int, 1 as c_int, SIZEX, SIZEY, 0 as c_uint,
        XBlackPixel(dpy, scr), XBlackPixel(dpy, scr));
    str::as_c_str("test") {|cstr|
        XStoreName(dpy, win, cstr);
    }
    XSelectInput(dpy, win, ExposureMask | ButtonPressMask);
    XMapWindow(dpy, win);

    let cs = cairo_xlib_surface_create(
        dpy, win, XDefaultVisual(dpy, 0 as c_int),
        SIZEX as c_int, SIZEY as c_int);

    let e = {
        type_: 0 as c_int,
        padding: (
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
        )
    };
    let ep = ptr::addr_of(e);

    loop unsafe {
        XNextEvent(dpy, unsafe::reinterpret_cast(ep));
        log(error, *ep);
        log(error, *xexpose(ep));
        if e.type_ == Expose && (*xexpose(ep)).count < 1 as c_int {
            paint(cs);
        } else if e.type_ == ButtonPress {
            break;
        } else {
            paint(cs);
        }
    }

    cairo_surface_destroy(cs);
    XCloseDisplay(dpy);

    fn paint(surf: *cairo_surface_t) {
        import libc::c_double;
        import cairo::*;
        import cairo::bindgen::*;

        let cr: *cairo_t = cairo_create(surf);
        assert cr.is_not_null();

        cairo_set_source_rgb(cr, 0.5 as c_double, 0.1 as c_double, 0.1 as c_double);
        cairo_paint(cr);

        let te: cairo_text_extents_t = {
            x_bearing: 0 as c_double,
            y_bearing: 0 as c_double,
            width: 0 as c_double,
            height: 0 as c_double,
            x_advance: 0 as c_double,
            y_advance: 0 as c_double
        };
        cairo_set_source_rgb(cr, 0.9 as c_double, 0.5 as c_double, 0.5 as c_double);
        str::as_c_str("Georgia") {|fontname|
            cairo_select_font_face(cr, fontname, CAIRO_FONT_SLANT_NORMAL,
                                   CAIRO_FONT_WEIGHT_BOLD);
        }
        cairo_set_font_size(cr, 20.2 as c_double);
        str::as_c_str("a") {|text|
            cairo_text_extents(cr, text, ptr::addr_of(te));
            cairo_move_to(cr,
                          100.0 + 0.5 - te.width / 2.0 - te.x_bearing,
                          100.0 + 0.5 - te.height / 2.0 - te.y_bearing);
            cairo_show_text(cr, text);
        }

        cairo_destroy(cr);
    }
}

<commit_msg>Fix tests<commit_after>import xlib::*;
import libc::*;
import cairo_xlib::*;
import xlib::bindgen::*;
import cairo::*;
import cairo::bindgen::*;
import cairo_xlib::bindgen::*;

#[test]
fn sanity_check() {
    AzSanityCheck();
}

const SIZEX: c_uint = 400 as c_uint;
const SIZEY: c_uint = 400 as c_uint;

const ExposureMask: c_long = (1 << 15) as c_long;
const ButtonPressMask: c_long = (1 << 2) as c_long;

const Expose: c_int = 12 as c_int;
const ButtonPress: c_int = 4 as c_int;

type XEventStub = {
    type_: c_int,
    padding: (
        int, int, int, int, int, int, int, int,
        int, int, int, int, int, int, int, int,
        int, int, int, int, int, int, int, int,
        int, int, int, int, int, int, int, int,
        int, int, int, int, int, int, int, int,
        int, int, int, int, int, int, int, int,
        int, int, int, int, int, int, int, int,
        int, int, int, int, int, int, int, int
    )
};

fn xexpose(event: *XEventStub) -> *XExposeEvent unsafe {
    unsafe::reinterpret_cast(ptr::addr_of((*event).padding))
}

#[test]
#[ignore]
fn cairo_it_up() {
    let dpy = XOpenDisplay(ptr::null());
    assert(ptr::is_not_null(dpy));
    let scr = XDefaultScreen(dpy);
    let rootwin = XRootWindow(dpy, scr);
    let win = XCreateSimpleWindow(
        dpy, rootwin, 1 as c_int, 1 as c_int, SIZEX, SIZEY, 0 as c_uint,
        XBlackPixel(dpy, scr), XBlackPixel(dpy, scr));
    str::as_c_str("test") {|cstr|
        XStoreName(dpy, win, cstr);
    }
    XSelectInput(dpy, win, ExposureMask | ButtonPressMask);
    XMapWindow(dpy, win);

    let cs = cairo_xlib_surface_create(
        dpy, win, XDefaultVisual(dpy, 0 as c_int),
        SIZEX as c_int, SIZEY as c_int);

    let e = {
        type_: 0 as c_int,
        padding: (
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
        )
    };
    let ep = ptr::addr_of(e);

    let dt = AzCreateDrawTargetForCairoSurface(cs);

    loop unsafe {
        XNextEvent(dpy, unsafe::reinterpret_cast(ep));
        log(error, *ep);
        log(error, *xexpose(ep));
        if e.type_ == Expose && (*xexpose(ep)).count < 1 as c_int {
            paint(dt);
        } else if e.type_ == ButtonPress {
            break;
        } else {
            paint(dt);
        }
    }

    AzReleaseDrawTarget(dt);
    cairo_surface_destroy(cs);
    XCloseDisplay(dpy);
}

fn paint(dt: AzDrawTargetRef) {
    log(error, "painting");
    let rect = {
        x: 200f as AzFloat,
        y: 200f as AzFloat,
        width: 100f as AzFloat,
        height: 100f as AzFloat
    };
    let color = {
        r: 0f as AzFloat,
        g: 1f as AzFloat,
        b: 0f as AzFloat,
        a: 1f as AzFloat
    };
    let pattern = AzCreateColorPattern(ptr::addr_of(color));
    AzDrawTargetFillRect(
        dt,
        ptr::addr_of(rect),
        unsafe { unsafe::reinterpret_cast(pattern) });
    AzReleaseColorPattern(pattern);
}

#[test]
fn test_draw_target_get_size() {
    let surface = cairo_image_surface_create(
        CAIRO_FORMAT_RGB24, 100 as c_int, 200 as c_int);
    assert surface.is_not_null();
    let dt = AzCreateDrawTargetForCairoSurface(surface);
    assert dt.is_not_null();
    let size = AzDrawTargetGetSize(dt);
    assert size.width == 100 as int32_t;
    assert size.height == 200 as int32_t;
    AzReleaseDrawTarget(dt);
    cairo_surface_destroy(surface);
}

#[test]
#[ignore]
fn fonts() {
    import cairo::*;
    import cairo::bindgen::*;

    let dpy = XOpenDisplay(ptr::null());
    assert(ptr::is_not_null(dpy));
    let scr = XDefaultScreen(dpy);
    let rootwin = XRootWindow(dpy, scr);
    let win = XCreateSimpleWindow(
        dpy, rootwin, 1 as c_int, 1 as c_int, SIZEX, SIZEY, 0 as c_uint,
        XBlackPixel(dpy, scr), XBlackPixel(dpy, scr));
    str::as_c_str("test") {|cstr|
        XStoreName(dpy, win, cstr);
    }
    XSelectInput(dpy, win, ExposureMask | ButtonPressMask);
    XMapWindow(dpy, win);

    let cs = cairo_xlib_surface_create(
        dpy, win, XDefaultVisual(dpy, 0 as c_int),
        SIZEX as c_int, SIZEY as c_int);

    let e = {
        type_: 0 as c_int,
        padding: (
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
        )
    };
    let ep = ptr::addr_of(e);

    loop unsafe {
        XNextEvent(dpy, unsafe::reinterpret_cast(ep));
        log(error, *ep);
        log(error, *xexpose(ep));
        if e.type_ == Expose && (*xexpose(ep)).count < 1 as c_int {
            paint(cs);
        } else if e.type_ == ButtonPress {
            break;
        } else {
            paint(cs);
        }
    }

    cairo_surface_destroy(cs);
    XCloseDisplay(dpy);

    fn paint(surf: *cairo_surface_t) {
        import libc::c_double;
        import cairo::*;
        import cairo::bindgen::*;

        let cr: *cairo_t = cairo_create(surf);
        assert cr.is_not_null();

        cairo_set_source_rgb(cr, 0.5 as c_double, 0.1 as c_double, 0.1 as c_double);
        cairo_paint(cr);

        let te: cairo_text_extents_t = {
            x_bearing: 0 as c_double,
            y_bearing: 0 as c_double,
            width: 0 as c_double,
            height: 0 as c_double,
            x_advance: 0 as c_double,
            y_advance: 0 as c_double
        };
        cairo_set_source_rgb(cr, 0.9 as c_double, 0.5 as c_double, 0.5 as c_double);
        str::as_c_str("Georgia") {|fontname|
            cairo_select_font_face(cr, fontname, CAIRO_FONT_SLANT_NORMAL,
                                   CAIRO_FONT_WEIGHT_BOLD);
        }
        cairo_set_font_size(cr, 20.2 as c_double);
        str::as_c_str("a") {|text|
            cairo_text_extents(cr, text, ptr::addr_of(te));
            cairo_move_to(
                cr,
                (100.0 + 0.5) as c_double -
                te.width / (2.0 as c_double) - te.x_bearing,
                (100.0 + 0.5) as c_double -
                te.height / (2.0 as c_double) - te.y_bearing);
            cairo_show_text(cr, text);
        }

        cairo_destroy(cr);
    }
}

<|endoftext|>


<commit_before>extern crate mmap;

use std::fs::OpenOptions;
use std::os::unix::fs::OpenOptionsExt;
use mmap::{MemoryMap,MapOption};
use std::os::unix::prelude::AsRawFd;

const BCM2708_PERI_BASE: u32 = 0x20000000;
pub const GPIO_BASE: u8 = (BCM2708_PERI_BASE + 0x200000) as u8;
const O_SYNC: u32 = 1052672;
const MAP_SHARED: i32 = 0x0001;
const BLOCK_SIZE: usize = (4 * 1024);

#[allow(dead_code)]
pub struct Bcm2835Peripheral {
    pub addr_p: *const u8,
    pub mem_fd: ::std::fs::File,
    pub map: ::mmap::MemoryMap,
    pub addr: *mut u32
}

impl Bcm2835Peripheral {
    pub fn map_peripheral( & mut self) {
        self.mem_fd = OpenOptions::new()
            .read(true)
            .write(true)
            .mode(O_SYNC)
            .open("/dev/mem")
            .expect("unable to open /dev/mem, Are you root?");

        let map_opts = & [
            MapOption::MapNonStandardFlags(MAP_SHARED),
            MapOption::MapReadable,
            MapOption::MapWritable,
            // MapOption::MapAddr(self.addr_p),
            MapOption::MapFd(self.mem_fd.as_raw_fd())
        ];

        let mmap = match MemoryMap::new(BLOCK_SIZE, map_opts) {
            Ok(mmap) => mmap,
            Err(e) => panic!("ERR: {}", e)
        };
        self.map = mmap;
        self.addr = self.map.data() as *mut u32;
    }

    pub fn unmap_peripheral(self) {
        drop(self);
    }

    pub unsafe fn in_gpio(&self, y: isize) {
        let k = self.addr.offset(y / 10);
        *k &= !(7 << (((y) % 10) * 3));
    }

    pub unsafe fn out_gpio(&self, y: isize) {
        let k = self.addr.offset(y / 10);
        *k |= (7 << (((y) % 10) * 3));
    }

    pub unsafe fn set_gpio_alt(&self, y: isize, a: u8) {
        let k = self.addr.offset(y / 10); *k |= match a {
            a if a <= 3 => a as u32 + 4,
            4 => 3u32,
            _ => 2u32,
        } << ((y % 10) * 3);
    }

    pub unsafe fn set_gpio(&self, val: u8) {
        *self.addr.offset(7) = val as u32;
    }
    pub unsafe fn clear_gpio(&self, val: u8) {
        *self.addr.offset(10) = val as u32;
    }
}

impl Drop for Bcm2835Peripheral {
    fn drop( & mut self) {
        println!("Unmapped Peripheral {:?}", self.map.data())
    }
}
<commit_msg>Add volatile_loads and volatile_stores<commit_after>extern crate mmap;
extern crate core;

use std::fs::OpenOptions;
use std::os::unix::fs::OpenOptionsExt;
use mmap::{MemoryMap,MapOption};
use std::os::unix::prelude::AsRawFd;
use self::core::intrinsics::{volatile_load, volatile_store};

const BCM2708_PERI_BASE: u32 = 0x20000000;
pub const GPIO_BASE: u8 = (BCM2708_PERI_BASE + 0x200000) as u8;
const O_SYNC: u32 = 1052672;
const MAP_SHARED: i32 = 0x0001;
const BLOCK_SIZE: usize = (4 * 1024);

#[allow(dead_code)]
pub struct Bcm2835Peripheral {
    pub addr_p: *const u8,
    pub mem_fd: ::std::fs::File,
    pub map: ::mmap::MemoryMap,
    pub addr: *mut u32
}

impl Bcm2835Peripheral {
    pub fn map_peripheral( & mut self) {
        self.mem_fd = OpenOptions::new()
            .read(true)
            .write(true)
            .mode(O_SYNC)
            .open("/dev/mem")
            .expect("unable to open /dev/mem, Are you root?");

        let map_opts = & [
            MapOption::MapNonStandardFlags(MAP_SHARED),
            MapOption::MapReadable,
            MapOption::MapWritable,
            // MapOption::MapAddr(self.addr_p),
            MapOption::MapFd(self.mem_fd.as_raw_fd())
        ];

        let mmap = match MemoryMap::new(BLOCK_SIZE, map_opts) {
            Ok(mmap) => mmap,
            Err(e) => panic!("ERR: {}", e)
        };
        self.map = mmap;
        unsafe { volatile_store(self.addr, self.map.data() as u32); }
    }

    pub fn unmap_peripheral(self) {
        drop(self);
    }

    pub unsafe fn in_gpio(&self, y: isize) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k &= !(7 << (((y) % 10) * 3));
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn out_gpio(&self, y: isize) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k |= (7 << (((y) % 10) * 3));
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn set_gpio_alt(&self, y: isize, a: u32) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k |= match a {
            a if a <= 3 => a + 4,
            4 => 3,
            _ => 2,
        } << ((y % 10) * 3);
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn set_gpio(&self, val: u32) {
        volatile_store(self.addr.offset(7), val);
    }
    pub unsafe fn clear_gpio(&self, val: u32) {
        volatile_store(self.addr.offset(10), val);
    }
}

impl Drop for Bcm2835Peripheral {
    fn drop(&mut self) {
        println!("Unmapped Peripheral {:?}", self.map.data())
    }
}
<|endoftext|>