<commit_before>grammar! bailey {
    use ast::Node::*;
    use ast::BinOp;
    use ast::BinOp::*;
    use ast::PNode;
    use std::str::FromStr;

    program
        = ((expr / decl / stmt) terminator?)* > program

    decl
        = class_decl
        / method_decl

    class_decl
        = kw_class constant class_body > class_decl

    class_body
        = lbracket method_decl* rbracket

    method_decl
        = kw_def identifier lparen param_list? rparen block > method_decl

    block
        = lbracket ((stmt / expr) terminator?)* rbracket > block

    stmt
        = if_stmt
        / while_stmt

    if_stmt
        = kw_if expr block (kw_else block)? > if_stmt

    while_stmt
        = kw_while expr block > while_stmt

    msg_no_receiver
        = identifier lparen arg_list? rparen

    msg_with_receiver
        = receiver_expr ("." msg_no_receiver)* > msg_with_receiver

    assign_expr
        = identifier bind_op expr > assign_expr

    expr
        = spacing 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
        = assign_expr
          / msg_with_receiver
          / receiver_expr

    receiver_expr
        = msg_no_receiver > msg_no_receiver
        / literal
        / constant
        / identifier
        / lparen expr rparen

    arg_list
        = (expr ("," spacing expr)*) > arg_list

    param_list
        = (identifier ("," spacing identifier)*) > param_list

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

    identifier = !digit !keyword identifier_char+ spacing > identifier
    constant = !keyword !digit ["A-Z"]+ identifier_char+ spacing > constant

    literal
        = lit_string
        / lit_float
        / lit_int
        / lit_array
        / lit_map

    lit_int = digit+ spacing > lit_int
    lit_float = digit+ "." digit+ spacing > lit_float
    lit_string = (dbl_quot_lit_string / sng_quot_lit_string) spacing > lit_string
    lit_array = lsqbracket expr ("," expr)* rsqbracket > lit_array
    lit_map = lbracket (expr ":" expr)* rbracket > lit_map

    dbl_quot_lit_string = dbl_quot (spacing_char / !dbl_quot .)* dbl_quot
    sng_quot_lit_string = sng_quot (spacing_char / !sng_quot .)* sng_quot

    spacing_char = [" \n\r\t"]
    spacing = spacing_char* -> ()

    kw_class = "class" spacing
    kw_def = "def" spacing
    kw_else = "else" spacing
    kw_false = "false" spacing
    kw_if = "if" spacing
    kw_nil = "nil" spacing
    kw_true = "true" spacing
    kw_while = "while" spacing

    keyword
        = kw_def
        / kw_if
        / kw_else
        / kw_class
        / kw_true
        / kw_false
        / kw_nil

    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 = "(" spacing
    rparen = ")" spacing
    lbracket = "{" spacing
    rbracket = "}" spacing
    lsqbracket = "[" spacing
    rsqbracket = "]" spacing
    dbl_quot = "\"" spacing
    sng_quot = "'" spacing
    terminator = ";" spacing

    fn lit_int(raw_text: Vec<char>) -> PNode {
        PNode(IntegerLiteral { value: to_number(raw_text) })
    }

    // FIXME: Please remove this hacky wacky '.' thingy
    fn lit_float(integer: Vec<char>, fractional: Vec<char>) -> PNode {
        let mut buf = integer;
        buf.push('.');
        PNode(FloatLiteral { value: to_float(combine(buf, fractional)) })
    }

    fn lit_string(raw_text: Vec<char>) -> PNode {
        PNode(StringLiteral { value: to_string(raw_text) })
    }

    fn lit_array(first: PNode, rest: Vec<PNode>) -> PNode {
        PNode(ArrayLiteral { expressions: combine_one_with_many(first, rest) })
    }

    fn lit_map(entries: Vec<(PNode, PNode)>) -> PNode {
        PNode(MapLiteral { entries: entries })
    }

    fn constant(first: Vec<char>, rest: Vec<char>) -> PNode {
        PNode(Constant { name:to_string(combine(first, rest)) })
    }

    fn identifier(raw_text: Vec<char>) -> PNode {
        PNode(Identifier { name: 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 msg_no_receiver(method: PNode, args: Option<Vec<PNode>>) -> PNode {
        PNode(Message { receiver: None, method: method, args: args })
    }

    fn msg_with_receiver(receiver: PNode, call: Vec<(PNode, Option<Vec<PNode>>)>) -> PNode {
        call.into_iter().fold(receiver, { |accu, (method, args)|
            PNode(Message{ receiver: Some(accu), method: method, args: args })
        })
    }

    fn assign_expr(identifier: PNode, expr: PNode) -> PNode {
        PNode(AssingExpression { identifier: identifier, expression: expr })
    }

    fn class_decl(class_name: PNode, methods: Vec<PNode>) -> PNode {
        PNode(ClassDeclaration { identifier: class_name, methods: methods })
    }

    fn method_decl(method: PNode, params: Option<Vec<PNode>>, block: PNode) -> PNode {
        PNode(MethodDeclaration { method: method, params: params, block: block })
    }

    fn block(instructions: Vec<(PNode, Option<()>)>) -> PNode {
        let instructions = instructions.into_iter().map(|expr| {
            match expr { (e, _) => e }
        }).collect();

        PNode(Block {instructions: instructions})
    }

    fn program(instructions: Vec<(PNode, Option<()>)>) -> Vec<PNode> {
        instructions.into_iter().map(|inst| {
            match inst { (i, _) => i }
        }).collect()
    }

    fn if_stmt(condition: PNode, true_block: PNode, false_block: Option<PNode>) -> PNode {
        PNode(IfStatement{ condition: condition, true_block: true_block, false_block: false_block })
    }

    fn while_stmt(condition: PNode,  block: PNode) -> PNode {
      PNode(WhileStatement { condition: condition, block: block })
    }

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

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

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

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

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

    fn fold_left(head: PNode, rest: Vec<(BinOp, PNode)>) -> PNode {
        rest.into_iter().fold(head,
          |accu, (op, expr)| PNode(BinaryExpression { op: op, left: accu, right: expr }))
    }

    fn fold_right(front: Vec<(PNode, BinOp)>, last: PNode) -> PNode {
        front.into_iter().rev().fold(last,
          |accu, (expr, op)| PNode(BinaryExpression { op: op, left: expr, right: accu }))
    }

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

    fn combine_one_with_many<T: Clone>(first: T, rest: Vec<T>) -> Vec<T> {
        let mut result = vec![first];
        combine(result, rest)
    }
}
<commit_msg>More idiomatic Rust. Thanks to @ptal!<commit_after>grammar! bailey {
    use ast::Node::*;
    use ast::BinOp;
    use ast::BinOp::*;
    use ast::PNode;
    use std::str::FromStr;

    program
        = ((expr / decl / stmt) terminator?)* > program

    decl
        = class_decl
        / method_decl

    class_decl
        = kw_class constant class_body > class_decl

    class_body
        = lbracket method_decl* rbracket

    method_decl
        = kw_def identifier lparen param_list? rparen block > method_decl

    block
        = lbracket ((stmt / expr) terminator?)* rbracket > block

    stmt
        = if_stmt
        / while_stmt

    if_stmt
        = kw_if expr block (kw_else block)? > if_stmt

    while_stmt
        = kw_while expr block > while_stmt

    msg_no_receiver
        = identifier lparen arg_list? rparen

    msg_with_receiver
        = receiver_expr ("." msg_no_receiver)* > msg_with_receiver

    assign_expr
        = identifier bind_op expr > assign_expr

    expr
        = spacing 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
        = assign_expr
          / msg_with_receiver
          / receiver_expr

    receiver_expr
        = msg_no_receiver > msg_no_receiver
        / literal
        / constant
        / identifier
        / lparen expr rparen

    arg_list
        = (expr ("," spacing expr)*) > arg_list

    param_list
        = (identifier ("," spacing identifier)*) > param_list

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

    identifier = !digit !keyword identifier_char+ spacing > identifier
    constant = !keyword !digit ["A-Z"]+ identifier_char+ spacing > constant

    literal
        = lit_string
        / lit_float
        / lit_int
        / lit_array
        / lit_map

    lit_int = digit+ spacing > lit_int
    lit_float = digit+ "." digit+ spacing > lit_float
    lit_string = (dbl_quot_lit_string / sng_quot_lit_string) spacing > lit_string
    lit_array = lsqbracket expr ("," expr)* rsqbracket > lit_array
    lit_map = lbracket (expr ":" expr)* rbracket > lit_map

    dbl_quot_lit_string = dbl_quot (spacing_char / !dbl_quot .)* dbl_quot
    sng_quot_lit_string = sng_quot (spacing_char / !sng_quot .)* sng_quot

    spacing_char = [" \n\r\t"]
    spacing = spacing_char* -> ()

    kw_class = "class" spacing
    kw_def = "def" spacing
    kw_else = "else" spacing
    kw_false = "false" spacing
    kw_if = "if" spacing
    kw_nil = "nil" spacing
    kw_true = "true" spacing
    kw_while = "while" spacing

    keyword
        = kw_def
        / kw_if
        / kw_else
        / kw_class
        / kw_true
        / kw_false
        / kw_nil

    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 = "(" spacing
    rparen = ")" spacing
    lbracket = "{" spacing
    rbracket = "}" spacing
    lsqbracket = "[" spacing
    rsqbracket = "]" spacing
    dbl_quot = "\"" spacing
    sng_quot = "'" spacing
    terminator = ";" spacing
    dot = "." spacing
    comma = "," spacing

    fn lit_int(raw_text: Vec<char>) -> PNode {
        PNode(IntegerLiteral { value: to_number(raw_text) })
    }

    // FIXME: Please remove this hacky wacky '.' thingy
    fn lit_float(mut integer: Vec<char>, fractional: Vec<char>) -> PNode {
        integer.push('.');
        PNode(FloatLiteral { value: to_float(combine(integer, fractional)) })
    }

    fn lit_string(raw_text: Vec<char>) -> PNode {
        PNode(StringLiteral { value: to_string(raw_text) })
    }

    fn lit_array(first: PNode, rest: Vec<PNode>) -> PNode {
        PNode(ArrayLiteral { expressions: combine_one_with_many(first, rest) })
    }

    fn lit_map(entries: Vec<(PNode, PNode)>) -> PNode {
        PNode(MapLiteral { entries: entries })
    }

    fn constant(first: Vec<char>, rest: Vec<char>) -> PNode {
        PNode(Constant { name:to_string(combine(first, rest)) })
    }

    fn identifier(raw_text: Vec<char>) -> PNode {
        PNode(Identifier { name: 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 msg_no_receiver(method: PNode, args: Option<Vec<PNode>>) -> PNode {
        PNode(Message { receiver: None, method: method, args: args })
    }

    fn msg_with_receiver(receiver: PNode, call: Vec<(PNode, Option<Vec<PNode>>)>) -> PNode {
        call.into_iter().fold(receiver, { |accu, (method, args)|
            PNode(Message{ receiver: Some(accu), method: method, args: args })
        })
    }

    fn assign_expr(identifier: PNode, expr: PNode) -> PNode {
        PNode(AssingExpression { identifier: identifier, expression: expr })
    }

    fn class_decl(class_name: PNode, methods: Vec<PNode>) -> PNode {
        PNode(ClassDeclaration { identifier: class_name, methods: methods })
    }

    fn method_decl(method: PNode, params: Option<Vec<PNode>>, block: PNode) -> PNode {
        PNode(MethodDeclaration { method: method, params: params, block: block })
    }

    fn block(instructions: Vec<(PNode, Option<()>)>) -> PNode {
        let instructions = instructions.into_iter().map(|expr| {
            match expr { (e, _) => e }
        }).collect();

        PNode(Block {instructions: instructions})
    }

    fn program(instructions: Vec<(PNode, Option<()>)>) -> Vec<PNode> {
        instructions.into_iter().map(|inst| {
            match inst { (i, _) => i }
        }).collect()
    }

    fn if_stmt(condition: PNode, true_block: PNode, false_block: Option<PNode>) -> PNode {
        PNode(IfStatement{ condition: condition, true_block: true_block, false_block: false_block })
    }

    fn while_stmt(condition: PNode,  block: PNode) -> PNode {
      PNode(WhileStatement { condition: condition, block: block })
    }

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

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

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

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

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

    fn fold_left(head: PNode, rest: Vec<(BinOp, PNode)>) -> PNode {
        rest.into_iter().fold(head,
          |accu, (op, expr)| PNode(BinaryExpression { op: op, left: accu, right: expr }))
    }

    fn fold_right(front: Vec<(PNode, BinOp)>, last: PNode) -> PNode {
        front.into_iter().rev().fold(last,
          |accu, (expr, op)| PNode(BinaryExpression { op: op, left: expr, right: accu }))
    }

    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)
    }
}
<|endoftext|>


<commit_before>type BufferRef = Arc<Vec<u8>>;
/// change me if you want to parse files > 4GB
pub type FilePos = u32;

#[derive(Copy,Clone,Eq,PartialEq,Debug)]
pub struct Span {
    pub start: FilePos,
    pub end: FilePos,
}

impl Span {
    fn new(start: usize, end: usize) -> Span {
        Span { start: start as FilePos, end: end as FilePos }
    }

    fn new2(start: FilePos, end: FilePos) -> Span {
        Span { start, end }
    }

    fn as_ref(&self, buf: &[u8]) -> &[u8] {
        buf[self.start .. self.end]
    }
}

/// This is a "dense" segment, which must be fully rebuilt in order to make any change.  We may in
/// the future have an "unpacked" segment which is used for active editing, as well as a "lazy" or
/// "mmap" segment type for fast incremental startup.
struct Segment {
    // buffer: BufferRef,
    // segment_span: Span,
}

#[derive(Debug,Clone,Eq)]
pub enum Diagnostic {
    BadCharacter(Span, u8),
    CommentMarkerNotStart(Span),
    MidStatementCommentMarker(Span),
    NestedComment(Span, Span),
    BadCommentEnd(Span, Span),
    UnclosedComment(Span),
}

#[derive(Copy,Clone,Debug)]
enum StatementType {
    /// Psuedo statement used only to record end-of-file whitespace
    Eof,
    /// Statement is damaged enough that there's no sense passing it to later stages
    Invalid,
    Comment,
    TypesettingComment,
    FileInclude,
    Axiom,
    Provable,
    Essential,
    Floating,
    Disjoint,
    OpenGroup,
    CloseGroup,
    Constant,
    Variable,
}

#[derive(Clone,Debug)]
struct Statement {
    type: StatementType,
    span: Span,
    full_span: Span,
    label: Span,
    math: Vec<Span>,
    proof: Vec<Span>,
    diagnostics: Vec<Diagnostic>,
}

#[derive(Default)]
struct Scanner<'a> {
    buffer: &'a [u8],
    position: FilePos,
    diagnostics: Vec<Diagnostic>,
    unget: Option<Span>,
    labels: Vec<Span>,
}

const mm_valid_spaces: u64 = (1u64 << 9) | (1u64 << 10) | (1u64 << 12) | (1u64 << 13) |
    (1u64 << 32);

fn is_mm_space_c0(byte: u8) -> bool {
    (mm_valid_spaces & (1u64 << byte)) != 0
}

fn is_mm_space(byte: u8) -> bool {
    byte <= 32 && is_mm_space_c0(byte)
}

enum CommentType {
    Normal,
    Typesetting,
    Extra,
}

impl<'a> Scanner<'a> {
    fn get_raw(&mut self) -> Option<Span> {
        let len = self.buffer.len();
        let mut ix = self.position as usize;

        while ix < len && self.buffer[ix] <= 32 {
            // For the purpose of error recovery, we consider C0 control characters to be
            // whitespace (following SMM2)
            if !is_mm_space_c0(self.buffer[ix]) {
                self.diagnostics.push(Diagnostic::BadCharacter(
                    Span::new(ix, ix + 1), self.buffer[ix]));
            }
            ix += 1;
        }

        let mut start = ix;
        while ix < len && self.buffer[ix] > 32 {
            if self.buffer[ix] > 126 {
                // DEL or C1 control or non-ASCII bytes (presumably UTF-8)
                self.diagnostics.push(Diagnostic::BadCharacter(
                    Span::new(ix, ix + 1), self.buffer[ix]));
                // skip this "token"
                ix += 1;
                while ix < len && !is_mm_space(self.buffer[ix]) { ix += 1; }
                while ix < len && is_mm_space(self.buffer[ix]) { ix += 1; }
                start = ix;
                continue;
            }

            ix += 1;
        }

        self.position = ix as FilePos;
        if start == ix {
            None
        } else {
            Some(Span::new(start, ix))
        }
    }

    fn get_comment(&mut self, opener: Span, mid_statement: bool) -> (Span, CommentType) {
        let mut type = CommentType::Normal;
        let mut first = true;
        while let Some(tok) = self.get_raw() {
            let tok_ref = tok.as_ref(self.buffer);
            if tok_ref == b"$)" {
                return (Span::new2(opener.start, tok.end), type)
            } else if tok_ref == b"$j" || tok_ref == b"$t" {
                if !first {
                    self.diagnostics.push(Diagnostic::CommentMarkerNotStart(tok))
                } else if mid_statement {
                    self.diagnostics.push(Diagnostic::MidStatementCommentMarker(tok))
                } else {
                    if tok_ref == b"$j" {
                        type = CommentType::Extra;
                    } else {
                        type = CommentType::Typesetting;
                    }
                }
            } else if tok_ref.contains(b'$') {
                let tok_str = str::from(tok_ref).unwrap();
                if tok_str.contains("$)") {
                    self.diagnostics.push(Diagnostic::BadCommentEnd(tok, opener));
                }
                if tok_str.contains("$()") {
                    self.diagnostics.push(Diagnostic::NestedComment(tok, opener));
                }
            }

            first = false;
        }

        let cspan = Span::new2(opener.start, self.buffer.len());
        self.diagnostics.push(Diagnostic::UnclosedComment(cspan));
        (cspan, type)
    }

    fn get(&mut self) -> Option<Span> {
        if self.unget.is_some() {
            return self.unget.take()
        }

        while let Some(tok) = self.get_raw() {
            let tok_ref = tok.as_ref(self.buffer);
            if tok_ref == b"$(" {
                self.get_comment(tok, true);
            } else {
                return Some(tok);
            }
        }

        None
    }

    fn get_statement(&mut self) -> Option<Statement> {
        let start = self.position;
        let mut stmt = Statement {
            type: StatementType::Invalid,
            span: Span::new(0, 0),
            full_span: Span::new(0, 0)
            label: Span::new(0, 0),
            math: Vec::new(),
            proof: Vec::new(),
            diagnostics: Vec::new(),
        };

        // check if we can parse a statement-level comment
        if let Some(ftok) = self.get_raw() {
            let ftok_ref = ftok.as_ref(self.buffer);
            if ftok_ref == b"$(" {
                let (cspan, ctype) = self.get_comment(ftok, false);
                stmt.type = if ctype == CommentType::Typesetting {
                    StatementType::TypesettingComment
                } else {
                    StatementType::Comment
                };
                stmt.span = cspan;
                stmt.full_span = cspan;
                stmt.full_span.start = start;
                stmt.diagnostics = mem::swap(&mut self.diagnostics, Vec::new());
                return Some(stmt);
            } else {
                self.unget = Some(ftok);
            }
        }

        self.labels.clear();
        while let Some(ltok) = self.get() {
            if ltok.as_ref(self.buffer).contains(b'$') {
                self.unget = Some(ltok);
                break;
            } else {
                self.labels.push(ltok);
            }
        }

        if let Some(kwtok) = self.get() {
            let kwtok_ref = kwtok.as_ref(self.buffer);
            if kwtok_ref.len() == 2 && kwtok_ref[0] == b'$' {
                match kwtok_ref[1] {
                    b'[' => {
                        stmt.type = StatementType::FileInclude;
                    },
                    b'a' => {
                        stmt.type = StatementType::Axiom;
                    },
                    b'c' => {
                        stmt.type = StatementType::Constant;
                    },
                    b'd' => {
                        stmt.type = StatementType::Disjoint;
                    },
                    b'e' => {
                        stmt.type = StatementType::Essential;
                    },
                    b'f' => {
                        stmt.type = StatementType::Floating;
                    },
                    b'p' => {
                        stmt.type = StatementType::Provable;
                    },
                    b'v' => {
                        stmt.type = StatementType::Variable;
                    },
                    b'{}' => {
                        stmt.type = StatementType::OpenGroup;
                    },
                    b'}' => {
                        stmt.type = StatementType::CloseGroup;
                    },
                }
            }
        }
    }
}

/// This function implements parsing stage 1, which breaks down the metalanguage grammar, finding
/// all identifier definitions and inclusion statements.
///
/// There is an argument to be made that we shouldn't tokenize or store the math strings and proofs
/// at this stage, since they're bulky and can easily be generated on demand.
///
/// The current Metamath spec defines comments and file inclusions at the token level.  It is
/// useful for our purposes to parse comments that are strictly between statements as if they were
/// statements (SMM2 did this too; may revisit) and we require file inclusions to be between
/// statements at the top nesting level (this has been approved by Norman Megill).
pub fn parse_segments(input: &BufferRef) -> Vec<Segment> {
    let mut closed_spans = Vec::new();
    let mut scanner = Scanner { buffer: input, ..Scanner::default() };

    while let Some(token) = scanner.get_raw() {
        let tok_ref = tok.as_ref(self.buffer);

    }
}
<commit_msg>statement parsing<commit_after>type BufferRef = Arc<Vec<u8>>;
/// change me if you want to parse files > 4GB
pub type FilePos = u32;

#[derive(Copy,Clone,Eq,PartialEq,Debug)]
pub struct Span {
    pub start: FilePos,
    pub end: FilePos,
}

impl Span {
    fn new(start: usize, end: usize) -> Span {
        Span { start: start as FilePos, end: end as FilePos }
    }

    fn new2(start: FilePos, end: FilePos) -> Span {
        Span { start, end }
    }

    fn null() -> Span {
        Span::new(0, 0)
    }

    fn as_ref(&self, buf: &[u8]) -> &[u8] {
        buf[self.start .. self.end]
    }
}

/// This is a "dense" segment, which must be fully rebuilt in order to make any change.  We may in
/// the future have an "unpacked" segment which is used for active editing, as well as a "lazy" or
/// "mmap" segment type for fast incremental startup.
pub struct Segment {
    // straight outputs
    pub statements: Vec<Statement>,
    pub next_file: Span,
    // crossed outputs
}

#[derive(Debug,Clone,Eq)]
pub enum Diagnostic {
    BadCharacter(Span, u8),
    CommentMarkerNotStart(Span),
    MidStatementCommentMarker(Span),
    NestedComment(Span, Span),
    BadCommentEnd(Span, Span),
    UnclosedComment(Span),
    BadLabel(Span),
    UnclosedMath,
    UnclosedProof,
}

#[derive(Copy,Clone,Debug,Eq,PartialEq)]
enum StatementType {
    /// Psuedo statement used only to record end-of-file whitespace
    Eof,
    /// Statement is damaged enough that there's no sense passing it to later stages
    Invalid,
    Comment,
    TypesettingComment,
    FileInclude,
    Axiom,
    Provable,
    Essential,
    Floating,
    Disjoint,
    OpenGroup,
    CloseGroup,
    Constant,
    Variable,
}
use StatementType::*;

impl StatementType {
    fn takes_label(self) -> bool {
        match self {
            Axiom | Provable | Essential | Floating => true,
            _ => false,
        }
    }

    fn takes_math(self) -> bool {
        match self {
            Axiom | Provable | Essential | Floating | Disjoint | Constant | Variable => true,
            _ => false,
        }
    }
}

#[derive(Clone,Debug)]
struct Statement {
    type: StatementType,
    span: Span,
    label: Span,
    math: Vec<Span>,
    proof: Vec<Span>,
    diagnostics: Vec<Diagnostic>,
}

#[derive(Default)]
struct Scanner<'a> {
    buffer: &'a [u8],
    position: FilePos,
    diagnostics: Vec<Diagnostic>,
    unget: Option<Span>,
    labels: Vec<Span>,
    statement_start: FilePos,
}

const mm_valid_spaces: u64 = (1u64 << 9) | (1u64 << 10) | (1u64 << 12) | (1u64 << 13) |
    (1u64 << 32);

fn is_mm_space_c0(byte: u8) -> bool {
    (mm_valid_spaces & (1u64 << byte)) != 0
}

fn is_mm_space(byte: u8) -> bool {
    byte <= 32 && is_mm_space_c0(byte)
}

enum CommentType {
    Normal,
    Typesetting,
    Extra,
}

impl<'a> Scanner<'a> {
    fn get_raw(&mut self) -> Option<Span> {
        let len = self.buffer.len();
        let mut ix = self.position as usize;

        while ix < len && self.buffer[ix] <= 32 {
            // For the purpose of error recovery, we consider C0 control characters to be
            // whitespace (following SMM2)
            if !is_mm_space_c0(self.buffer[ix]) {
                self.diagnostics.push(Diagnostic::BadCharacter(
                    Span::new(ix, ix + 1), self.buffer[ix]));
            }
            ix += 1;
        }

        let mut start = ix;
        while ix < len && self.buffer[ix] > 32 {
            if self.buffer[ix] > 126 {
                // DEL or C1 control or non-ASCII bytes (presumably UTF-8)
                self.diagnostics.push(Diagnostic::BadCharacter(
                    Span::new(ix, ix + 1), self.buffer[ix]));
                // skip this "token"
                ix += 1;
                while ix < len && !is_mm_space(self.buffer[ix]) { ix += 1; }
                while ix < len && is_mm_space(self.buffer[ix]) { ix += 1; }
                start = ix;
                continue;
            }

            ix += 1;
        }

        self.position = ix as FilePos;
        if start == ix {
            None
        } else {
            Some(Span::new(start, ix))
        }
    }

    fn get_comment(&mut self, opener: Span, mid_statement: bool) -> (Span, CommentType) {
        let mut type = CommentType::Normal;
        let mut first = true;
        while let Some(tok) = self.get_raw() {
            let tok_ref = tok.as_ref(self.buffer);
            if tok_ref == b"$)" {
                return (Span::new2(opener.start, tok.end), type)
            } else if tok_ref == b"$j" || tok_ref == b"$t" {
                if !first {
                    self.diagnostics.push(Diagnostic::CommentMarkerNotStart(tok))
                } else if mid_statement {
                    self.diagnostics.push(Diagnostic::MidStatementCommentMarker(tok))
                } else {
                    if tok_ref == b"$j" {
                        type = CommentType::Extra;
                    } else {
                        type = CommentType::Typesetting;
                    }
                }
            } else if tok_ref.contains(b'$') {
                let tok_str = str::from(tok_ref).unwrap();
                if tok_str.contains("$)") {
                    self.diagnostics.push(Diagnostic::BadCommentEnd(tok, opener));
                }
                if tok_str.contains("$()") {
                    self.diagnostics.push(Diagnostic::NestedComment(tok, opener));
                }
            }

            first = false;
        }

        let cspan = Span::new2(opener.start, self.buffer.len());
        self.diagnostics.push(Diagnostic::UnclosedComment(cspan));
        (cspan, type)
    }

    fn get(&mut self) -> Option<Span> {
        if self.unget.is_some() {
            return self.unget.take()
        }

        while let Some(tok) = self.get_raw() {
            let tok_ref = tok.as_ref(self.buffer);
            if tok_ref == b"$(" {
                self.get_comment(tok, true);
            } else {
                return Some(tok);
            }
        }

        None
    }

    fn out_statement(&mut self, type: StatementType, label: Span, math: Vec<Span>, proof: Vec<Span>) -> Statement {
        Statement {
            type, label, math, proof,
            diagnostics: mem::replace(&mut self.diagnostics, Vec::new()),
            span: Span::new2(mem::replace(&mut self.statement_start, self.position), self.position),
        }
    }

    fn get_comment_statement(&mut self) -> Option<Statement> {
        if let Some(ftok) = self.get_raw() {
            let ftok_ref = ftok.as_ref(self.buffer);
            if ftok_ref == b"$(" {
                let (cspan, ctype) = self.get_comment(ftok, false);
                let type if ctype == CommentType::Typesetting {
                    TypesettingComment
                } else {
                    Comment
                };
                return Some(self.out_statement(type, Span::null(), Vec::new(), Vec::new()));
            } else {
                self.unget = Some(ftok);
            }
        }
        None
    }

    fn read_labels(&mut self) {
        self.has_bad_labels = false;
        self.labels.clear();
        while let Some(ltok) = self.get() {
            let lref = ltok.as_ref(self.buffer);
            if lref.contains(b'$') {
                self.unget = Some(ltok);
                break;
            } else if !is_valid_label(lref) {
                self.diagnostics.push(Diagnostic::BadLabel(ltok));
                self.has_bad_labels = true;
            } else {
                self.labels.push(ltok);
            }
        }
    }

    fn get_no_label(&mut self) {
        // none of these are invalidations...
        for lspan in &self.labels {
            self.diagnostics.push(Diagnostic::SpuriousLabel(lspan));
        }
    }

    fn get_label(&mut self) -> Span {
        if self.labels.len() == 1 {
            self.labels[0]
        } else if self.labels.len() == 0 {
            self.diagnostics.push(Diagnostic::MissingLabel);
            self.invalidated = true;
            Span::null()
        } else {
            for addl in self.labels.iter().skip(1) {
                self.diagnostics.push(Diagnostic::RepeatedLabel(addl, self.labels[0]));
            }
            // have to invalidate because we don't know which to use
            self.invalidated = true;
            Span::null()
        }
    }

    fn get_string(&mut self, expect_proof: bool, is_proof: bool) -> (Vec<Span>, bool) {
        let mut out = Vec::new();
        while let Some(tokn) = self.get() {
            let toknref = tokn.as_ref(self.buffer);
            if toknref.contains(b'$') {
                if toknref == b"$." {
                    // string is closed with no proof
                    if expect_proof {
                        self.diagnostics.push(Diagnostic::MissingProof(tokn));
                    }
                    return (out, false);
                } else if toknref == b"$=" && !is_proof {
                    // string is closed with a proof
                    if !expect_proof {
                        self.diagnostics.push(Diagnostic::SpuriousProof(tokn));
                    }
                    return (out, true);
                } else {
                    // string is closed with no proof and with an error, whoops
                    self.unget = true;
                    break;
                }
            } else {
                out.push(tokn);
            }
        }

        self.diagnostics.push(if is_proof { Diagnostic::UnclosedProof } else { Diagnostic::UnclosedMath });
        return (out, false);
    }

    fn get_strings(&mut self, want_proof: bool) -> (Vec<Span>, Vec<Span>) {
        let (math_str, has_proof) = self.get_string(want_proof, false);

        if math_str.len() == 0 {
            self.invalidated = true;
            // this is invalid for all types of math string
            self.diagnostics.push(Diagnostic::EmptyMathString);
        }

        let (proof_str, _) = if has_proof {
            // diagnostic already generated if unwanted, but we still need to eat the proof
            self.get_string(false, true)
        } else {
            // diagnostic already generated if unwanted.  this is NOT an invalidation as $p
            // statements don't need proofs (I mean you should have a ? but we know what you mean)
            (Vec::new(), false)
        }
        (math_str, proof_str)
    }

    fn eat_invalid(&mut self) {
        while let Some(tok) = self.get() {
            let tref = tok.as_ref(self.buffer);
            if tref == b"$." {
                // we're probably synchronized
                break;
            } else if tref == b"$=" {
                // this is definitely not it
            } else if tref.contains(b'$') {
                // might be the start of the next statement
                self.unget = true;
                break;
            }
        }
    }

    fn get_file_include(&mut self) -> Span {
        let mut res = Span::null();
        let mut count = 0;
        while let Some(tok) = self.get() {
            let tref = tok.as_ref(self.buffer);
            if tref == b"$]" {
                if count == 0 {
                    self.diagnostics.push(Diagnostic::EmptyFilename);
                    self.invalidated = true;
                } else if count > 1 {
                    self.diagnostics.push(Diagnostic::FilenameSpaces);
                    self.invalidated = true;
                } else if res.as_ref(self.buffer).contains(b'$') {
                    self.diagnostics.push(Diagnostic::FilenameDollar);
                }
                return res;
            } else if tref.len() > 0 && tref[0] == b'$' {
                break;
            } else {
                count += 1;
                res = tok;
            }
        }
        self.diagnostics.push(Diagnostic::UnclosedInclude);
        self.invalidated = true;
        return res;
    }

    fn get_statement(&mut self) -> Statement {
        self.statement_start = self.position;

        if let Some(stmt) = self.get_comment_statement() {
            return stmt;
        }

        self.read_labels();

        let mut type = Eof;
        if let Some(kwtok) = self.get() {
            let kwtok_ref = kwtok.as_ref(self.buffer);
            type = if kwtok_ref.len() == 2 && kwtok_ref[0] == b'$' {
                match kwtok_ref[1] {
                    b'[' => FileInclude,
                    b'a' => Axiom,
                    b'c' => Constant,
                    b'd' => Disjoint,
                    b'e' => Essential,
                    b'f' => Floating,
                    b'p' => Provable,
                    b'v' => Variable,
                    b'{' => OpenGroup,
                    b'}' => CloseGroup,
                    _ => Invalid,
                }
            } else {
                Invalid,
            };
        }
        self.invalidated = false;

        let label = if type.takes_label() {
            self.get_label()
        } else {
            self.get_no_label();
            Span::null()
        };

        let (math, proof) = if type.takes_math() {
            self.get_strings(type == Provable)
        } else {
            (Vec::new(), Vec::new())
        };

        match type {
            FileInclude => {
                label = self.get_file_include();
            }
            Disjoint => {
                // math.len = 1 was caught above
                if math.len() == 1 {
                    self.diagnostics.push(Diagnostic::DisjointSingle);
                    self.invalidated = true;
                }
            }
            Floating => {
                if math.len() != 0 && math.len() != 2 {
                    self.diagnostics.push(Diagnostics::BadFloating);
                    self.invalidated = true;
                }
            }
            Invalid => {
                // eat tokens to the next keyword rather than treating them as labels
                self.eat_invalid();
            }
            _ => {}
        }

        if self.invalidated {
            type = Invalid;
        }

        self.out_statement(type, label, math, proof)
    }
}

fn is_valid_label(label: &[u8]) -> bool {
    for c in label {
        if !(c == b'.' || c == b'-' || c == b'_' || (c >= b'a' && c <= b'z') || (c >= b'0' && c <= b'9') || (c >= b'A' && c <= b'Z')) {
            return false;
        }
    }
    true
}

/// This function implements parsing stage 1, which breaks down the metalanguage grammar, finding
/// all identifier definitions and inclusion statements.
///
/// There is an argument to be made that we shouldn't tokenize or store the math strings and proofs
/// at this stage, since they're bulky and can easily be generated on demand.
///
/// The current Metamath spec defines comments and file inclusions at the token level.  It is
/// useful for our purposes to parse comments that are strictly between statements as if they were
/// statements (SMM2 did this too; may revisit) and we require file inclusions to be between
/// statements at the top nesting level (this has been approved by Norman Megill).
pub fn parse_segments(input: &BufferRef) -> Vec<Segment> {
    let mut closed_spans = Vec::new();
    let mut scanner = Scanner { buffer: input, ..Scanner::default() };

    while let Some(token) = scanner.get_raw() {
        let tok_ref = tok.as_ref(self.buffer);

    }
}
<|endoftext|>


<commit_before>use expr::{Expr, BinOp, UnOp};

#[derive(Clone, Debug, PartialEq)]
enum Token {
  Plus,
  Minus,
  Times,
  Div,
  RParen,
  LParen,
  Eq,
  Ne,
  Leq,
  Geq,
  Lt,
  Gt,
  Not,
  And,
  Or,
  Mod,
  Seq,
  Ternary,
  Else,
  Var(String),
  Int(isize),
  Bool(bool),
  Let,
  Assign,
  FnDecl,
  FnCall(String),
  LBracket,
  RBracket,
}

impl Token {
  pub fn is_term_bop(&self) -> bool {
    match *self {
      Token::Times => true,
      Token::Div => true,
      _ => false,
    }

  }

  pub fn is_expr_bop(&self) -> bool {
    match *self {
      Token::Plus => true,
      Token::Minus => true,
      Token::Eq => true,
      Token::Ne => true,
      Token::Leq => true,
      Token::Geq => true,
      Token::Lt => true,
      Token::Gt => true,
      Token::And => true,
      Token::Or => true,
      Token::Mod => true,
      Token::Seq => true,
      _ => false,
    }
  }

  pub fn is_expr_op(&self) -> bool {
    match *self {
      Token::Ternary => true,
      _ => false,
    }
  }
}

struct Lexer {
  text: String,
}

impl Lexer {
  pub fn new(text: String) -> Lexer {
    Lexer {
      text: text,
    }
  }

  fn advance(&mut self, n: usize) {
    let text = self.text.clone();
    let (_, t) = text.split_at(n);
    self.text = t.to_string();
  }

  fn lex_integer(&mut self) -> Option<Token> {
    let int_str: String = self.text
      .chars()
      .take_while(|c| c.is_digit(10))
      .collect();

    match int_str.parse::<isize>() {
      Ok(n) => {
        self.advance(int_str.len());
        return Some(Token::Int(n));
      }
      Err(_) => panic!()
    }
  }

  fn lex_keyword(&mut self) -> Option<Token> {
    let keyword: String = self.text
      .chars()
      .take_while(|c| c.is_alphabetic())
      .collect();

    self.advance(keyword.len());

    let next_char = self.peek_next();

    match keyword.as_ref()  {
      "true" => Some(Token::Bool(true)),
      "false" => Some(Token::Bool(false)),
      "fn" => Some(Token::FnDecl),
      "let" => Some(Token::Let),
      s if next_char == Some('(') => Some(Token::FnCall(s.to_string())),
      s if s.len() > 0 => Some(Token::Var(s.to_string())),
      _ => panic!()
    }
  }

  fn skip_whitespace(&mut self) {
    let spaces_str: String = self.text
      .chars()
      .take_while(|c| c.is_whitespace())
      .collect();

    self.advance(spaces_str.len());
  }

  fn peek_next(&mut self) -> Option<char> {
    self.text.chars().next()
  }

  pub fn get_next_token(&mut self) -> Option<Token> {
    while self.peek_next() != None {
      debug!("get_next_token: {}", self.text);

      match self.peek_next() {
        Some('+') => {
          self.advance(1);
          return Some(Token::Plus)
        },
        Some('-') => {
          self.advance(1);
          return Some(Token::Minus)
        },
        Some('*') => {
          self.advance(1);
          return Some(Token::Times)
        },
        Some('/') => {
          self.advance(1);
          return Some(Token::Div)
        },
        Some('%') => {
          self.advance(1);
          return Some(Token::Mod)
        },
        Some('(') => {
          self.advance(1);
          return Some(Token::LParen)
        },
        Some(')') => {
          self.advance(1);
          return Some(Token::RParen)
        },
        Some('&') => {
          self.advance(2);
          return Some(Token::And)
        },
        Some('|') => {
          self.advance(2);
          return Some(Token::Or)
        },
        Some('=') if self.text.starts_with("==") => {
          self.advance(2);
          return Some(Token::Eq)
        },
        Some('=') => {
          self.advance(1);
          return Some(Token::Assign)
        },
        Some('!') if self.text.starts_with("!=") => {
          self.advance(2);
          return Some(Token::Ne)
        },
        Some('!') => {
          self.advance(1);
          return Some(Token::Not)
        },
        Some('>') if self.text.starts_with(">=") => {
          self.advance(2);
          return Some(Token::Geq)
        },
        Some('>') => {
          self.advance(1);
          return Some(Token::Gt)
        },
        Some('<') if self.text.starts_with("<=") => {
          self.advance(2);
          return Some(Token::Leq)
        },
        Some('<') => {
          self.advance(1);
          return Some(Token::Lt)
        },
        Some(';') => {
          self.advance(1);
          return Some(Token::Seq)
        },
        Some('?') => {
          self.advance(1);
          return Some(Token::Ternary)
        },
        Some(':') => {
          self.advance(1);
          return Some(Token::Else)
        },
        Some('{') => {
          self.advance(1);
          return Some(Token::LBracket)
        },
        Some('}') => {
          self.advance(1);
          return Some(Token::RBracket)
        },
        Some(c) if c.is_alphabetic() => return self.lex_keyword(),
        Some(c) if c.is_digit(10) => return self.lex_integer(),
        Some(c) if c.is_whitespace() => {
          self.skip_whitespace();
          continue;
        },
        None => return None,
        _ => panic!()
      }
    }

    None
  }
}

struct Parser {
  lexer: Lexer,
  current_token: Option<Token>,
}

impl Parser {
  pub fn new(text: String) -> Parser {
    let mut lexer = Lexer::new(text);

    let token = lexer.get_next_token();

    Parser {
      lexer: lexer,
      current_token: token,
    }
  }

  fn eat(&mut self, expected: Token) {
    let actual = self.current_token.clone().unwrap();

    if expected != actual {
      panic!("expected token: {:?} actual: {:?}", expected, actual)
    }

    self.current_token = self.lexer.get_next_token();
    debug!("new current token: {:?}", self.current_token);
  }

  fn ternary(&mut self, e1: Option<Expr>, e2: Option<Expr>, e3: Option<Expr>) -> Option<Expr> {
    Some(Expr::Ternary(to_box(e1), to_box(e2), to_box(e3)))
  }

  fn binop(&mut self, bop: BinOp, e1: Option<Expr>, e2: Option<Expr>) -> Option<Expr> {
    Some(Expr::BinOp(bop, to_box(e1), to_box(e2)))
  }

  fn factor(&mut self) -> Option<Expr> {
    match self.current_token.clone() {
      Some(Token::Int(n)) => {
        self.eat(Token::Int(n.clone()));
        return Some(Expr::Int(n));
      },
      Some(Token::Bool(b)) => {
        self.eat(Token::Bool(b.clone()));
        return Some(Expr::Bool(b));
      },
      Some(Token::Var(s)) => {
        self.eat(Token::Var(s.clone()));
        return Some(Expr::Var(s));
      },
      Some(Token::Let) => {
        self.eat(Token::Let);

        let var = self.statement();

        self.eat(Token::Assign);

        let seq = self.statement();

        // TODO: this is def hacky
        let (e1, e2) = match seq {
          Some(Expr::BinOp(BinOp::Seq, e1, e2)) => {
            (e1, e2)
          },
          _ => {
            debug!("expected seq, got {:?}", seq);
            panic!();
          }
        };

        debug!("var: {:?}", var);

        return Some(Expr::Let(to_box(var), e1, e2));
      },
      Some(Token::FnDecl) => {
        self.eat(Token::FnDecl);

        self.eat(Token::LParen);

        // TODO: grab params here

        self.eat(Token::RParen);

        self.eat(Token::LBracket);
        let body = self.statement();
        debug!("got fn body {:?}", body);
        self.eat(Token::RBracket);

        return Some(Expr::Func(to_box(body)));
      },
      Some(Token::FnCall(s)) => {
        self.eat(Token::FnCall(s.clone()));
        // TODO: grab any params

        self.eat(Token::LParen);
        self.eat(Token::RParen);

        return Some(Expr::FnCall(s));
      },
      Some(Token::LParen) => {
        self.eat(Token::LParen);
        let node = self.statement();
        self.eat(Token::RParen);
        return node;
      },
      Some(Token::LBracket) => {
        self.eat(Token::LBracket);
        let node = self.statement();
        self.eat(Token::RBracket);
        return node;
      },
      Some(Token::Not) => {
        self.eat(Token::Not);
        return Some(Expr::UnOp(UnOp::Not, to_box(self.statement())))
      },
      Some(Token::Minus) => {
        self.eat(Token::Minus);
        return Some(Expr::UnOp(UnOp::Neg, to_box(self.factor())))
      },
      _ => {
        debug!("invalid factor: {:?}", self.current_token);
        panic!();
      },
    }
  }

  pub fn term(&mut self) -> Option<Expr> {
    let mut node = self.factor();

    let mut op = self.current_token.clone();

    while op != None && op.clone().unwrap().is_term_bop() {
      self.eat(op.clone().unwrap());
      let right_node = self.term();

      node = match op {
        Some(Token::Times) => self.binop(BinOp::Times, node, right_node),
        Some(Token::Div) => self.binop(BinOp::Div, node, right_node),
        _ => panic!(),
      };

      op = self.current_token.clone();
    }

    node
  }

  pub fn binop_expr(&mut self) -> Option<Expr> {
    let mut node = self.term();

    let mut op = self.current_token.clone();

    while op != None && op.clone().unwrap().is_expr_bop() {
      debug!("expr looping on op {:?}", op);
      self.eat(op.clone().unwrap());

      let right_node = self.term();

      node = match op {
        Some(Token::Plus) => self.binop(BinOp::Plus, node, right_node),
        Some(Token::Minus) => self.binop(BinOp::Minus, node, right_node),
        Some(Token::Eq) => self.binop(BinOp::Eq, node, right_node),
        Some(Token::Ne) => self.binop(BinOp::Ne, node, right_node),
        Some(Token::Leq) => self.binop(BinOp::Leq, node, right_node),
        Some(Token::Geq) => self.binop(BinOp::Geq, node, right_node),
        Some(Token::Lt) => self.binop(BinOp::Lt, node, right_node),
        Some(Token::Gt) => self.binop(BinOp::Gt, node, right_node),
        Some(Token::And) => self.binop(BinOp::And, node, right_node),
        Some(Token::Or) => self.binop(BinOp::Or, node, right_node),
        Some(Token::Mod) => self.binop(BinOp::Mod, node, right_node),
        Some(Token::Seq) => self.binop(BinOp::Seq, node, right_node),
        _ => panic!(),
      };

      op = self.current_token.clone();
    }

    node
  }

  pub fn statement(&mut self) -> Option<Expr> {
    let mut node = self.binop_expr();

    let mut op = self.current_token.clone();

    while op != None && op.clone().unwrap().is_expr_op() {
      self.eat(op.clone().unwrap());
      let e2 = self.binop_expr();

      node = match op {
        Some(Token::Ternary) => {

          self.eat(Token::Else);

          let e3 = self.binop_expr();

          self.ternary(node, e2, e3)
        },
        _ => panic!(),
      };

      op = self.current_token.clone();
    }

    node
  }

  pub fn block(&mut self) -> Option<Expr> {
    self.statement()
  }

  pub fn program(&mut self) -> Option<Expr> {
    self.block()
  }
}

fn to_box(e: Option<Expr>) -> Box<Expr> {
  match e {
    Some(e) => Box::new(e),
    None => panic!("cannot turn to box: {:?}", e),
  }
}

pub fn parse(input: &str) -> Expr {
  let mut parser = Parser::new(input.to_string());
  let expr = parser.program().unwrap();

  debug!("parsed expr: {:#?}", expr);

  expr
}
<commit_msg>expr is not optional<commit_after>use expr::{Expr, BinOp, UnOp};

#[derive(Clone, Debug, PartialEq)]
enum Token {
  Plus,
  Minus,
  Times,
  Div,
  RParen,
  LParen,
  Eq,
  Ne,
  Leq,
  Geq,
  Lt,
  Gt,
  Not,
  And,
  Or,
  Mod,
  Seq,
  Ternary,
  Else,
  Var(String),
  Int(isize),
  Bool(bool),
  Let,
  Assign,
  FnDecl,
  FnCall(String),
  LBracket,
  RBracket,
}

impl Token {
  pub fn is_term_bop(&self) -> bool {
    match *self {
      Token::Times => true,
      Token::Div => true,
      _ => false,
    }

  }

  pub fn is_expr_bop(&self) -> bool {
    match *self {
      Token::Plus => true,
      Token::Minus => true,
      Token::Eq => true,
      Token::Ne => true,
      Token::Leq => true,
      Token::Geq => true,
      Token::Lt => true,
      Token::Gt => true,
      Token::And => true,
      Token::Or => true,
      Token::Mod => true,
      Token::Seq => true,
      _ => false,
    }
  }

  pub fn is_expr_op(&self) -> bool {
    match *self {
      Token::Ternary => true,
      _ => false,
    }
  }
}

struct Lexer {
  text: String,
}

impl Lexer {
  pub fn new(text: String) -> Lexer {
    Lexer {
      text: text,
    }
  }

  fn advance(&mut self, n: usize) {
    let text = self.text.clone();
    let (_, t) = text.split_at(n);
    self.text = t.to_string();
  }

  fn lex_integer(&mut self) -> Option<Token> {
    let int_str: String = self.text
      .chars()
      .take_while(|c| c.is_digit(10))
      .collect();

    match int_str.parse::<isize>() {
      Ok(n) => {
        self.advance(int_str.len());
        return Some(Token::Int(n));
      }
      Err(_) => panic!()
    }
  }

  fn lex_keyword(&mut self) -> Option<Token> {
    let keyword: String = self.text
      .chars()
      .take_while(|c| c.is_alphabetic())
      .collect();

    self.advance(keyword.len());

    let next_char = self.peek_next();

    match keyword.as_ref()  {
      "true" => Some(Token::Bool(true)),
      "false" => Some(Token::Bool(false)),
      "fn" => Some(Token::FnDecl),
      "let" => Some(Token::Let),
      s if next_char == Some('(') => Some(Token::FnCall(s.to_string())),
      s if s.len() > 0 => Some(Token::Var(s.to_string())),
      _ => panic!()
    }
  }

  fn skip_whitespace(&mut self) {
    let spaces_str: String = self.text
      .chars()
      .take_while(|c| c.is_whitespace())
      .collect();

    self.advance(spaces_str.len());
  }

  fn peek_next(&mut self) -> Option<char> {
    self.text.chars().next()
  }

  pub fn get_next_token(&mut self) -> Option<Token> {
    while self.peek_next() != None {
      debug!("get_next_token: {}", self.text);

      match self.peek_next() {
        Some('+') => {
          self.advance(1);
          return Some(Token::Plus)
        },
        Some('-') => {
          self.advance(1);
          return Some(Token::Minus)
        },
        Some('*') => {
          self.advance(1);
          return Some(Token::Times)
        },
        Some('/') => {
          self.advance(1);
          return Some(Token::Div)
        },
        Some('%') => {
          self.advance(1);
          return Some(Token::Mod)
        },
        Some('(') => {
          self.advance(1);
          return Some(Token::LParen)
        },
        Some(')') => {
          self.advance(1);
          return Some(Token::RParen)
        },
        Some('&') => {
          self.advance(2);
          return Some(Token::And)
        },
        Some('|') => {
          self.advance(2);
          return Some(Token::Or)
        },
        Some('=') if self.text.starts_with("==") => {
          self.advance(2);
          return Some(Token::Eq)
        },
        Some('=') => {
          self.advance(1);
          return Some(Token::Assign)
        },
        Some('!') if self.text.starts_with("!=") => {
          self.advance(2);
          return Some(Token::Ne)
        },
        Some('!') => {
          self.advance(1);
          return Some(Token::Not)
        },
        Some('>') if self.text.starts_with(">=") => {
          self.advance(2);
          return Some(Token::Geq)
        },
        Some('>') => {
          self.advance(1);
          return Some(Token::Gt)
        },
        Some('<') if self.text.starts_with("<=") => {
          self.advance(2);
          return Some(Token::Leq)
        },
        Some('<') => {
          self.advance(1);
          return Some(Token::Lt)
        },
        Some(';') => {
          self.advance(1);
          return Some(Token::Seq)
        },
        Some('?') => {
          self.advance(1);
          return Some(Token::Ternary)
        },
        Some(':') => {
          self.advance(1);
          return Some(Token::Else)
        },
        Some('{') => {
          self.advance(1);
          return Some(Token::LBracket)
        },
        Some('}') => {
          self.advance(1);
          return Some(Token::RBracket)
        },
        Some(c) if c.is_alphabetic() => return self.lex_keyword(),
        Some(c) if c.is_digit(10) => return self.lex_integer(),
        Some(c) if c.is_whitespace() => {
          self.skip_whitespace();
          continue;
        },
        None => return None,
        _ => panic!()
      }
    }

    None
  }
}

struct Parser {
  lexer: Lexer,
  current_token: Option<Token>,
}

impl Parser {
  pub fn new(text: String) -> Parser {
    let mut lexer = Lexer::new(text);

    let token = lexer.get_next_token();

    Parser {
      lexer: lexer,
      current_token: token,
    }
  }

  fn eat(&mut self, expected: Token) {
    let actual = self.current_token.clone().unwrap();

    if expected != actual {
      panic!("expected token: {:?} actual: {:?}", expected, actual)
    }

    self.current_token = self.lexer.get_next_token();
    debug!("new current token: {:?}", self.current_token);
  }

  fn ternary(&mut self, e1: Expr, e2: Expr, e3: Expr) -> Expr {
    Expr::Ternary(to_box(e1), to_box(e2), to_box(e3))
  }

  fn binop(&mut self, bop: BinOp, e1: Expr, e2: Expr) -> Expr {
    Expr::BinOp(bop, to_box(e1), to_box(e2))
  }

  fn factor(&mut self) -> Expr {
    match self.current_token.clone() {
      Some(Token::Int(n)) => {
        self.eat(Token::Int(n.clone()));
        return Expr::Int(n);
      },
      Some(Token::Bool(b)) => {
        self.eat(Token::Bool(b.clone()));
        return Expr::Bool(b);
      },
      Some(Token::Var(s)) => {
        self.eat(Token::Var(s.clone()));
        return Expr::Var(s);
      },
      Some(Token::Let) => {
        self.eat(Token::Let);

        let var = self.statement();

        self.eat(Token::Assign);

        let seq = self.statement();

        // TODO: this is def hacky
        let (e1, e2) = match seq {
          Expr::BinOp(BinOp::Seq, e1, e2) => {
            (e1, e2)
          },
          _ => {
            debug!("expected seq, got {:?}", seq);
            panic!();
          }
        };

        debug!("var: {:?}", var);

        return Expr::Let(to_box(var), e1, e2);
      },
      Some(Token::FnDecl) => {
        self.eat(Token::FnDecl);

        self.eat(Token::LParen);

        // TODO: grab params here

        self.eat(Token::RParen);

        self.eat(Token::LBracket);
        let body = self.statement();
        debug!("got fn body {:?}", body);
        self.eat(Token::RBracket);

        return Expr::Func(to_box(body));
      },
      Some(Token::FnCall(s)) => {
        self.eat(Token::FnCall(s.clone()));
        // TODO: grab any params

        self.eat(Token::LParen);
        self.eat(Token::RParen);

        return Expr::FnCall(s);
      },
      Some(Token::LParen) => {
        self.eat(Token::LParen);
        let node = self.statement();
        self.eat(Token::RParen);
        return node;
      },
      Some(Token::LBracket) => {
        self.eat(Token::LBracket);
        let node = self.statement();
        self.eat(Token::RBracket);
        return node;
      },
      Some(Token::Not) => {
        self.eat(Token::Not);
        return Expr::UnOp(UnOp::Not, to_box(self.statement()));
      },
      Some(Token::Minus) => {
        self.eat(Token::Minus);
        return Expr::UnOp(UnOp::Neg, to_box(self.factor()));
      },
      _ => {
        debug!("invalid factor: {:?}", self.current_token);
        panic!();
      },
    }
  }

  pub fn term(&mut self) -> Expr {
    let mut node = self.factor();

    let mut op = self.current_token.clone();

    while op != None && op.clone().unwrap().is_term_bop() {
      self.eat(op.clone().unwrap());
      let right_node = self.term();

      node = match op {
        Some(Token::Times) => self.binop(BinOp::Times, node, right_node),
        Some(Token::Div) => self.binop(BinOp::Div, node, right_node),
        _ => panic!(),
      };

      op = self.current_token.clone();
    }

    node
  }

  pub fn binop_expr(&mut self) -> Expr {
    let mut node = self.term();

    let mut op = self.current_token.clone();

    while op != None && op.clone().unwrap().is_expr_bop() {
      debug!("expr looping on op {:?}", op);
      self.eat(op.clone().unwrap());

      let right_node = self.term();

      node = match op {
        Some(Token::Plus) => self.binop(BinOp::Plus, node, right_node),
        Some(Token::Minus) => self.binop(BinOp::Minus, node, right_node),
        Some(Token::Eq) => self.binop(BinOp::Eq, node, right_node),
        Some(Token::Ne) => self.binop(BinOp::Ne, node, right_node),
        Some(Token::Leq) => self.binop(BinOp::Leq, node, right_node),
        Some(Token::Geq) => self.binop(BinOp::Geq, node, right_node),
        Some(Token::Lt) => self.binop(BinOp::Lt, node, right_node),
        Some(Token::Gt) => self.binop(BinOp::Gt, node, right_node),
        Some(Token::And) => self.binop(BinOp::And, node, right_node),
        Some(Token::Or) => self.binop(BinOp::Or, node, right_node),
        Some(Token::Mod) => self.binop(BinOp::Mod, node, right_node),
        Some(Token::Seq) => self.binop(BinOp::Seq, node, right_node),
        _ => panic!(),
      };

      op = self.current_token.clone();
    }

    node
  }

  pub fn statement(&mut self) -> Expr {
    let mut node = self.binop_expr();

    let mut op = self.current_token.clone();

    while op != None && op.clone().unwrap().is_expr_op() {
      self.eat(op.clone().unwrap());
      let e2 = self.binop_expr();

      node = match op {
        Some(Token::Ternary) => {

          self.eat(Token::Else);

          let e3 = self.binop_expr();

          self.ternary(node, e2, e3)
        },
        _ => panic!(),
      };

      op = self.current_token.clone();
    }

    node
  }

  pub fn block(&mut self) -> Expr {
    self.statement()
  }

  pub fn program(&mut self) -> Expr {
    self.block()
  }
}

fn to_box(e: Expr) -> Box<Expr> {
  Box::new(e)
}

pub fn parse(input: &str) -> Expr {
  let mut parser = Parser::new(input.to_string());
  let expr = parser.program();

  debug!("parsed expr: {:#?}", expr);

  expr
}
<|endoftext|>


<commit_before>//! The `parser` module contains structures and functions for parsing the VQA
//! (Vector Quantized Animation) format.
//!
//! Information on the VQA format found at:
//!
//! * https://wiki.multimedia.cx/index.php/VQA#Technical_Description
//! * https://multimedia.cx/HC-VQA.TXT

use nom::{be_u16, be_u32, IResult};

#[derive(Debug)]
pub struct FormChunk {
    size: u32
}

named!(pub form_chunk<FormChunk>,
    do_parse!(
        tag!("FORM") >>
        size: be_u32 >>
        (FormChunk {
            size: size
        })
    )
);

#[derive(Debug)]
pub struct VQAHeader {
    version       : VQAVersion, // VQA version number
    flags         : u16,        // VQA flags
    num_frames    : u16,        // Number of frames
    width         : u16,        // Movie width (pixels)
    height        : u16,        // Movie height (pixels)
    block_width   : u8,         // Width of each image block (pixels)
    block_height  : u8,         // Height of each image block (pixels)
    frame_rate    : u8,         // Frame rate of the VQA
    cbparts       : u8,         // How many images use the same lookup table
    colors        : u16,        // Max number of colors used in VQA
    maxblocks     : u16,        // Max number of image blocks
    unk1          : u32,        // Always 0?
    unk2          : u16,        // Some kind of size?
    freq          : u16,        // Sound sampling frequency
    channels      : u8,         // Number of sound channels
    bits          : u8,         // Sound resolution
    unk3          : u32,        // Always 0?
    unk4          : u16,        // 0 in old VQAs, 4 in HiColor VQAs?
    max_cbfz_size : u32,        // 0 in old VQAs, CBFZ size in HiColor
    unk5          : u32,        // Always 0?
}

#[derive(Debug)]
pub enum VQAVersion {
    One,
    Two,
    Three
}<commit_msg>add vqa header parser<commit_after>//! The `parser` module contains structures and functions for parsing the VQA
//! (Vector Quantized Animation) format.
//!
//! Information on the VQA format found at:
//!
//! * https://wiki.multimedia.cx/index.php/VQA#Technical_Description
//! * https://multimedia.cx/HC-VQA.TXT

use nom::{be_u32, le_u8, le_u16, le_u32, IResult};

#[derive(Debug)]
pub struct FormChunk {
    pub size: u32
}

named!(pub form_chunk<FormChunk>,
    do_parse!(
        tag!("FORM") >>
        size: be_u32 >>
        (FormChunk {
            size: size
        })
    )
);

#[derive(Debug)]
pub enum VQAVersion {
    One,
    Two,
    Three
}

named!(pub vqa_version<VQAVersion>,
    switch!(le_u16,
        1 => value!(VQAVersion::One) |
        2 => value!(VQAVersion::Two) |
        3 => value!(VQAVersion::Three)
    )
);

#[derive(Debug)]
pub struct VQAHeader {
    pub version       : VQAVersion, // VQA version number
    pub flags         : u16,        // VQA flags
    pub num_frames    : u16,        // Number of frames
    pub width         : u16,        // Movie width (pixels)
    pub height        : u16,        // Movie height (pixels)
    pub block_width   : u8,         // Width of each image block (pixels)
    pub block_height  : u8,         // Height of each image block (pixels)
    pub frame_rate    : u8,         // Frame rate of the VQA
    pub cbparts       : u8,         // How many images use the same lookup table
    pub colors        : u16,        // Max number of colors used in VQA
    pub maxblocks     : u16,        // Max number of image blocks
    pub unk1          : u32,        // Always 0?
    pub unk2          : u16,        // Some kind of size?
    pub freq          : u16,        // Sound sampling frequency
    pub channels      : u8,         // Number of sound channels
    pub bits          : u8,         // Sound resolution
    pub unk3          : u32,        // Always 0?
    pub unk4          : u16,        // 0 in old VQAs, 4 in HiColor VQAs?
    pub max_cbfz_size : u32,        // 0 in old VQAs, CBFZ size in HiColor
    pub unk5          : u32,        // Always 0?
}

named!(pub vqa_header<VQAHeader>,
    do_parse!(
        tag!("VQHD")              >>
        tag!(b"\x00\x00\x00\x2a") >> // VQAHeader is always 42 bytes long
        version: vqa_version      >>
        flags: le_u16             >>
        num_frames: le_u16        >>
        width: le_u16             >>
        height: le_u16            >>
        block_width: le_u8        >>
        block_height: le_u8       >>
        frame_rate: le_u8         >>
        cbparts: le_u8            >>
        colors: le_u16            >>
        maxblocks: le_u16         >>
        unk1: le_u32              >>
        unk2: le_u16              >>
        freq: le_u16              >>
        channels: le_u8           >>
        bits: le_u8               >>
        unk3: le_u32              >>
        unk4: le_u16              >>
        max_cbfz_size: le_u32     >>
        unk5: le_u32              >>
        (VQAHeader {
            version: version,
            flags: flags,
            num_frames: num_frames,
            width: width,
            height: height,
            block_width: block_width,
            block_height: block_height,
            frame_rate: frame_rate,
            cbparts: cbparts,
            colors: colors,
            maxblocks: maxblocks,
            unk1: unk1,
            unk2: unk2,
            freq: freq,
            channels: channels,
            bits: bits,
            unk3: unk3,
            unk4: unk4,
            max_cbfz_size: max_cbfz_size,
            unk5: unk5
        })
    )
);<|endoftext|>


<commit_before>use std::result:: { Result };
use lcov_parser:: { LCOVParser, LCOVRecord, RecordParseError };
use report:: { Report, FileResult };
use coverage:: { Coverage };

pub struct ReportParser {
    parser: LCOVParser,
    files: Vec<FileResult>,
    counter: Option<HitCounter>
}

impl ReportParser {
    pub fn new(report: &str) -> Self {
        let parser = LCOVParser::new(report);
        ReportParser { parser: parser, files: vec!(), counter: None }
    }
    pub fn parse(&mut self) -> Result<Report, RecordParseError> {
        let records = try!(self.parser.parse());

        for record in records.iter() {
            self.on_parsed(record);
        }

        let report = Report::new(self.files.clone());
        Ok(report)
    }

    pub fn on_parsed(&mut self, record: &LCOVRecord) {
        match record {
            &LCOVRecord::SourceFile(ref name) => self.on_source_file(name.clone()),
            &LCOVRecord::Data(_, excution_count, _) => self.on_data(excution_count),
            &LCOVRecord::EndOfRecord => self.on_end_of_record(),
            _ => {}
        }
    }

    pub fn on_source_file(&mut self, name: String) {
        println!("{}", name);
        self.counter = Some(HitCounter::new(name));
    }

    pub fn on_data(&mut self, excution_count: u32) {
        println!("{}", excution_count);
        match self.counter.as_mut() {
            Some(counter) => counter.proceed(excution_count),
            None => {}
        }
    }

    pub fn on_end_of_record(&mut self) {
        println!("{}", "excution_count");
        match self.counter.as_mut() {
            Some(counter) => self.files.push(FileResult::new(counter.name(), Coverage::new(0.1))),
            None => {}
        }
    }
}

pub struct HitCounter {
    name: String,
    found: u32,
    hit: u32
}

impl HitCounter {
    pub fn new(name: String) -> Self {
        HitCounter {
            name: name,
            found: 0,
            hit: 0
        }
    }
    pub fn name(&self) -> String {
        self.name.clone()
    }
    pub fn proceed(&mut self, excution_count: u32) {
        self.found += 1;
        if excution_count <= 0 {
            return;
        }
        self.hit += 1;
    }
}

#[cfg(test)]
mod tests {
    use std::fs:: { File };
    use parser:: { ReportParser };
    use std::io:: { Read };

    #[test]
    fn test_parse_report() {
        let mut buffer = String::new();
        let mut f = File::open("tests/fixtures/report.lcov").unwrap();
        let _ = f.read_to_string(&mut buffer);

        let mut parser = ReportParser::new(buffer.as_str());
        let report = parser.parse().unwrap();
        assert_eq!(report.files().len(), 2);
    }
}
<commit_msg>add to_file_result<commit_after>use std::result:: { Result };
use lcov_parser:: { LCOVParser, LCOVRecord, RecordParseError };
use report:: { Report, FileResult };
use coverage:: { Coverage };

pub struct ReportParser {
    parser: LCOVParser,
    files: Vec<FileResult>,
    counter: Option<HitCounter>
}

impl ReportParser {
    pub fn new(report: &str) -> Self {
        let parser = LCOVParser::new(report);
        ReportParser { parser: parser, files: vec!(), counter: None }
    }
    pub fn parse(&mut self) -> Result<Report, RecordParseError> {
        let records = try!(self.parser.parse());

        for record in records.iter() {
            self.on_parsed(record);
        }

        let report = Report::new(self.files.clone());
        Ok(report)
    }

    pub fn on_parsed(&mut self, record: &LCOVRecord) {
        match record {
            &LCOVRecord::SourceFile(ref name) => self.on_source_file(name.clone()),
            &LCOVRecord::Data(_, excution_count, _) => self.on_data(excution_count),
            &LCOVRecord::EndOfRecord => self.on_end_of_record(),
            _ => {}
        }
    }

    pub fn on_source_file(&mut self, name: String) {
        println!("{}", name);
        self.counter = Some(HitCounter::new(name));
    }

    pub fn on_data(&mut self, excution_count: u32) {
        println!("{}", excution_count);
        match self.counter.as_mut() {
            Some(counter) => counter.proceed(excution_count),
            None => {}
        }
    }

    pub fn on_end_of_record(&mut self) {
        println!("{}", "excution_count");
        match self.counter.as_mut() {
            Some(counter) => self.files.push(counter.to_file_result()),
            None => {}
        }
    }
}

pub struct HitCounter {
    name: String,
    found: u32,
    hit: u32
}

impl HitCounter {
    pub fn new(name: String) -> Self {
        HitCounter {
            name: name,
            found: 0,
            hit: 0
        }
    }
    pub fn name(&self) -> &String {
        &self.name
    }
    pub fn proceed(&mut self, excution_count: u32) {
        self.found += 1;
        if excution_count <= 0 {
            return;
        }
        self.hit += 1;
    }
    pub fn to_file_result(&self) -> FileResult {
        let value = f64::from(self.found) / f64::from(self.hit);
        FileResult::new(self.name.clone(), Coverage::new(value))
    }
}

#[cfg(test)]
mod tests {
    use std::fs:: { File };
    use parser:: { ReportParser };
    use std::io:: { Read };

    #[test]
    fn test_parse_report() {
        let mut buffer = String::new();
        let mut f = File::open("tests/fixtures/report.lcov").unwrap();
        let _ = f.read_to_string(&mut buffer);

        let mut parser = ReportParser::new(buffer.as_str());
        let report = parser.parse().unwrap();
        assert_eq!(report.files().len(), 2);
    }
}
<|endoftext|>


<commit_before>use nom::{IResult, not_line_ending, line_ending};

fn csv_line(input: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
	terminated!(input, separated_list!(filter!(apply!(check_characters, b"\n\r,")), not_line_ending), line_ending)
}

fn check_characters(data: &[u8], characters: &[u8]) -> bool {
	for i in 0..data.len() {
		for c in characters {
			if data[i] == *c {
				return false;
			}
		}
	}
	true
}

#[test]
fn check_file() {
	let f = b"nom,age\ncarles,30\nlaure,28";

	csv_line(f);
}<commit_msg>Update to nom 1.0<commit_after>use nom::{IResult, not_line_ending, line_ending};

fn csv_line(input: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
	terminated!(input, separated_list!(is_not_bytes!(&b"\n\r,"[..]), not_line_ending), line_ending)
}

#[test]
fn check_file() {
	let f = b"nom,age\ncarles,30\nlaure,28";

	csv_line(f);
}
<|endoftext|>


<commit_before>use codemap::Spanned;
use lexer::Token;
use std::iter::Peekable;
use std::slice::Iter;
use self::ParseErrorKind::*;

type ParseIter<'a> = Peekable<Iter<'a, Spanned<Token>>>;
type Parse = Result<Node, ParseErrorKind>;

#[derive(Debug, Clone, PartialEq)]
pub enum Node {
  Block(Vec<Node>),
  If{cond: Box<Node>},
  Stmt(Box<Node>),
  Break,
  Continue,
  Expr,
  Pass,

  BinExpr {
    lhs: Box<Node>,
    operator: Token,
    rhs: Box<Node>,
  },

  UnExpr {
    val: Box<Node>,
    operator: Token,
  },

  // Literals
  Null,
  Bool(bool),
  Float(f64),
  Int(i64),
  Str(String),
  Name(String),
  Table,
}

#[derive(Debug, Clone, PartialEq)]
pub enum ParseErrorKind {
  UnexpectedToken(Token),
  UnexpectedEOF,
  UnknownBinaryOperator,
  UnknownUnaryOperator,
}

// Return true if the next token in `it` is `kind`
fn peek_token(it: &mut ParseIter, kind: Token) -> bool {
  if let Some(&c) = it.peek() {
    c.node == kind
  }
  else {
    false
  }
}

// Return true if the next token in `it` is `kind` *and* consume the token
fn use_token(it: &mut ParseIter, kind: Token) -> bool {
  if let Some(&c) = it.peek() {
    if c.node == kind {
      it.next();
    }
    c.node == kind
  }
  else {
    false
  }
}

// Panic if the next token in `it` is *not* `kind`
fn require_token(it: &mut ParseIter, kind: Token) -> Result<(), ParseErrorKind> {
  if let Some(&c) = it.peek() {
    it.next();

    if c.node == kind {
      return Ok(());
    }

    return Err(UnexpectedToken(c.node.clone()));
  }

  return Err(UnexpectedEOF);
}

fn parse_expr(it: &mut ParseIter) -> Parse {
  if let Some(&c) = it.peek() {
    return match c.node {
      Token::Null => {it.next(); Ok(Node::Null)},
      Token::Bool(x) => {it.next(); Ok(Node::Bool(x))},
      Token::Float(x) => {it.next(); Ok(Node::Float(x))},
      Token::Int(x) => {it.next(); Ok(Node::Int(x))},
      Token::Str(ref x) => {it.next(); Ok(Node::Str(x.clone()))},
      Token::Name(ref x) => {it.next(); Ok(Node::Name(x.clone()))},
      _ => Err(UnexpectedToken(c.node.clone())),
    }
  }

  Err(UnexpectedEOF)
}

fn parse_stmt(it: &mut ParseIter) -> Parse {
  if let Some(&c) = it.peek() {
    return match c.node {
      Token::Break => {
        it.next();
        Ok(Node::Break)
      }

      Token::Continue => {
        it.next();
        Ok(Node::Continue)
      }

      Token::Pass => {
        it.next();
        Ok(Node::Pass)
      }

      Token::If => {
        it.next();
        parse_expr(it).map(|expr| Node::If{cond: Box::new(expr)})
      }

      _ => {
        parse_expr(it).map(|expr| Node::Stmt(Box::new(expr)))
      }
    }
  }

  Err(UnexpectedEOF)
}

pub fn parse(tokens: Vec<Spanned<Token>>) -> Parse {
  let mut it: ParseIter = tokens.iter().peekable();
  let mut nodes: Vec<Node> = vec![];

  while !peek_token(&mut it, Token::EOF) {
    nodes.push(parse_stmt(&mut it)?);
    require_token(&mut it, Token::End)?;
  }

  Ok(Node::Block(nodes))
}
<commit_msg>parser: Add naive binary expression parser<commit_after>use codemap::Spanned;
use lexer::Token;
use std::iter::Peekable;
use std::slice::Iter;
use self::ParseErrorKind::*;

type ParseIter<'a> = Peekable<Iter<'a, Spanned<Token>>>;
type Parse = Result<Node, ParseErrorKind>;

#[derive(Debug, Clone, PartialEq)]
pub enum Node {
  Block(Vec<Node>),
  If{cond: Box<Node>},
  Stmt(Box<Node>),
  Break,
  Continue,
  Expr,
  Pass,

  BinExpr {
    lhs: Box<Node>,
    op: Token,
    rhs: Box<Node>,
  },

  UnExpr {
    val: Box<Node>,
    op: Token,
  },

  // Literals
  Null,
  Bool(bool),
  Float(f64),
  Int(i64),
  Str(String),
  Name(String),
  Table,
}

#[derive(Debug, Clone, PartialEq)]
pub enum Op {
  Right(u32),
  Left(u32),
  None,
}

#[derive(Debug, Clone, PartialEq)]
pub enum ParseErrorKind {
  UnexpectedToken(Token),
  UnexpectedEOF,
  UnknownBinaryOperator,
  UnknownUnaryOperator,
}

// Return true if the next token in `it` is `kind`
fn peek_token(it: &mut ParseIter, kind: Token) -> bool {
  if let Some(&c) = it.peek() {
    c.node == kind
  }
  else {
    false
  }
}

// Return true if the next token in `it` is `kind` *and* consume the token
fn use_token(it: &mut ParseIter, kind: Token) -> bool {
  if let Some(&c) = it.peek() {
    if c.node == kind {
      it.next();
    }
    c.node == kind
  }
  else {
    false
  }
}

// Panic if the next token in `it` is *not* `kind`
fn require_token(it: &mut ParseIter, kind: Token) -> Result<(), ParseErrorKind> {
  if let Some(&c) = it.peek() {
    it.next();

    if c.node == kind {
      return Ok(());
    }

    return Err(UnexpectedToken(c.node.clone()));
  }

  return Err(UnexpectedEOF);
}

fn op_precedence(op: &Token) -> Op {
  match *op {
    Token::Add | Token::Sub => Op::Left(10),
    Token::Div | Token::Mul => Op::Left(20),
    Token::Car => Op::Right(30),
    _ => Op::None,
  }
}

fn parse_binexpr(it: &mut ParseIter) -> Parse {
  let mut expr = parse_unexpr(it)?;

  while let Some(&c) = it.peek() {
    let prec = op_precedence(&c.node);

    if let Op::None = prec {
      break;
    }

    it.next();

    let rhs = parse_unexpr(it)?;

    if let Node::BinExpr{lhs: cur_lhs, op: cur_op, rhs: cur_rhs} = expr.clone() {
      let cur_prec = op_precedence(&cur_op);
      match (cur_prec, prec) {
        // these should never happen
        (_, Op::None) => {break}
        (Op::None, _) => {break}

        (Op::Left(n), Op::Left(m)) => {
          // left-to-right if n >= m
          if n >= m {
            expr = Node::BinExpr {lhs: Box::new(expr), op: c.node.clone(), rhs: Box::new(rhs)};
          }
          // right-to-left if n < m
          else {
            expr = Node::BinExpr {
              lhs: cur_lhs,
              op: cur_op,
              rhs: Box::new(Node::BinExpr {lhs: cur_rhs, op: c.node.clone(), rhs: Box::new(rhs)}),
            };
          }
        }

        (Op::Right(n), Op::Right(m)) => {
          // left-to-right if n > m
          if n > m {
            expr = Node::BinExpr {lhs: Box::new(expr), op: c.node.clone(), rhs: Box::new(rhs)};
          }
          // right-to-left if n <= m
          else {
            expr = Node::BinExpr {
              lhs: cur_lhs,
              op: cur_op,
              rhs: Box::new(Node::BinExpr {lhs: cur_rhs, op: c.node.clone(), rhs: Box::new(rhs)}),
            };
          }
        }

        (Op::Right(n), Op::Left(m)) => {
          // left-to-right if n >= m
          if n >= m {
            expr = Node::BinExpr {lhs: Box::new(expr), op: c.node.clone(), rhs: Box::new(rhs)};
          }
          // right-to-left if n < m
          else {
            expr = Node::BinExpr {
              lhs: cur_lhs,
              op: cur_op,
              rhs: Box::new(Node::BinExpr {lhs: cur_rhs, op: c.node.clone(), rhs: Box::new(rhs)}),
            };
          }
        }

        (Op::Left(n), Op::Right(m)) => {
          // left-to-right if n >= m
          if n >= m {
            expr = Node::BinExpr {lhs: Box::new(expr), op: c.node.clone(), rhs: Box::new(rhs)};
          }
          // right-to-left if n < m
          else {
            expr = Node::BinExpr {
              lhs: cur_lhs,
              op: cur_op,
              rhs: Box::new(Node::BinExpr {lhs: cur_rhs, op: c.node.clone(), rhs: Box::new(rhs)}),
            };
          }
        }
      };
    }
    else {
      expr = Node::BinExpr {lhs: Box::new(expr), op: c.node.clone(), rhs: Box::new(rhs)};
    }
  };

  Ok(expr)
}

fn parse_unexpr(it: &mut ParseIter) -> Parse {
  parse_simple(it)
}

fn parse_simple(it: &mut ParseIter) -> Parse {
  parse_prefix(it)
}

fn parse_prefix(it: &mut ParseIter) -> Parse {
  if let Some(&c) = it.peek() {
    return match c.node {
      Token::Null => {it.next(); Ok(Node::Null)},
      Token::Bool(x) => {it.next(); Ok(Node::Bool(x))},
      Token::Float(x) => {it.next(); Ok(Node::Float(x))},
      Token::Int(x) => {it.next(); Ok(Node::Int(x))},
      Token::Str(ref x) => {it.next(); Ok(Node::Str(x.clone()))},
      Token::Name(ref x) => {it.next(); Ok(Node::Name(x.clone()))},
      Token::Table => {it.next(); Ok(Node::Table)},
      Token::Pal => {
        it.next();
        let out = parse_binexpr(it)?;
        require_token(it, Token::Par)?;
        Ok(out)
      }
      _ => Err(UnexpectedToken(c.node.clone())),
    }
  }

  Err(UnexpectedEOF)
}

fn parse_stmt(it: &mut ParseIter) -> Parse {
  if let Some(&c) = it.peek() {
    return match c.node {
      Token::Break => {
        it.next();
        Ok(Node::Break)
      }

      Token::Continue => {
        it.next();
        Ok(Node::Continue)
      }

      Token::Pass => {
        it.next();
        Ok(Node::Pass)
      }

      _ => {
        parse_binexpr(it).map(|expr| Node::Stmt(Box::new(expr)))
      }
    }
  }

  Err(UnexpectedEOF)
}

pub fn parse(tokens: Vec<Spanned<Token>>) -> Parse {
  let mut it: ParseIter = tokens.iter().peekable();
  let mut nodes: Vec<Node> = vec![];

  while !peek_token(&mut it, Token::EOF) {
    nodes.push(parse_stmt(&mut it)?);
    require_token(&mut it, Token::End)?;
  }

  Ok(Node::Block(nodes))
}
<|endoftext|>


<commit_before>use pyo3::prelude::*;
use pyo3::wrap_pyfunction;

use crate::atom;
use crate::lebedev;
use crate::radial;

#[pyfunction]
fn angular_grid(num_points: usize) -> (Vec<(f64, f64, f64)>, Vec<f64>) {
    lebedev::angular_grid(num_points)
}

#[pyfunction]
fn radial_grid(
    radial_precision: f64,
    alpha_min: Vec<f64>,
    alpha_max: f64,
    max_l_quantum_number: usize,
    proton_charge: i32,
) -> (Vec<f64>, Vec<f64>) {
    radial::radial_grid(
        radial_precision,
        alpha_min,
        alpha_max,
        max_l_quantum_number,
        proton_charge,
    )
}

#[pyfunction]
fn atom_grid(
    radial_precision: f64,
    alpha_min: Vec<f64>,
    alpha_max: f64,
    max_l_quantum_number: usize,
    num_angular_points: usize,
    num_centers: usize,
    proton_charges: Vec<i32>,
    center_index: usize,
    center_coordinates_bohr: Vec<(f64, f64, f64)>,
    hardness: usize,
) -> (Vec<(f64, f64, f64)>, Vec<f64>) {
    atom::atom_grid(
        radial_precision,
        alpha_min,
        alpha_max,
        max_l_quantum_number,
        num_angular_points,
        num_centers,
        proton_charges,
        center_index,
        center_coordinates_bohr,
        hardness,
    )
}

#[pymodule]
fn demo(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(angular_grid, m)?)?;
    m.add_function(wrap_pyfunction!(radial_grid, m)?)?;
    m.add_function(wrap_pyfunction!(atom_grid, m)?)?;

    Ok(())
}
<commit_msg>fix module name<commit_after>use pyo3::prelude::*;
use pyo3::wrap_pyfunction;

use crate::atom;
use crate::lebedev;
use crate::radial;

#[pyfunction]
fn angular_grid(num_points: usize) -> (Vec<(f64, f64, f64)>, Vec<f64>) {
    lebedev::angular_grid(num_points)
}

#[pyfunction]
fn radial_grid(
    radial_precision: f64,
    alpha_min: Vec<f64>,
    alpha_max: f64,
    max_l_quantum_number: usize,
    proton_charge: i32,
) -> (Vec<f64>, Vec<f64>) {
    radial::radial_grid(
        radial_precision,
        alpha_min,
        alpha_max,
        max_l_quantum_number,
        proton_charge,
    )
}

#[pyfunction]
fn atom_grid(
    radial_precision: f64,
    alpha_min: Vec<f64>,
    alpha_max: f64,
    max_l_quantum_number: usize,
    num_angular_points: usize,
    num_centers: usize,
    proton_charges: Vec<i32>,
    center_index: usize,
    center_coordinates_bohr: Vec<(f64, f64, f64)>,
    hardness: usize,
) -> (Vec<(f64, f64, f64)>, Vec<f64>) {
    atom::atom_grid(
        radial_precision,
        alpha_min,
        alpha_max,
        max_l_quantum_number,
        num_angular_points,
        num_centers,
        proton_charges,
        center_index,
        center_coordinates_bohr,
        hardness,
    )
}

#[pymodule]
fn numgrid(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(angular_grid, m)?)?;
    m.add_function(wrap_pyfunction!(radial_grid, m)?)?;
    m.add_function(wrap_pyfunction!(atom_grid, m)?)?;

    Ok(())
}
<|endoftext|>


<commit_before>extern crate rand;

pub use self::rand::Rng;

use super::structure::{Program,Condition,Command,Expression,Sensor};

#[macro_export]
macro_rules! pick {
    ($( $weight: expr, $expression: expr),+) => {{
        let total = 0 $(+ $weight)+;
        let mut bound = 0;

        let mut rng = rand::thread_rng();
        let random_number = rng.gen_range(0, total);
        let result = $( if bound <= random_number && random_number < { bound += $weight; bound } {
            $expression
        } else )+ {
           panic!();
        };
        result
    }}
}

impl rand::Rand for Program {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 2) {
			i @ 0...1 if i < 1 => Program::If(Condition::rand(rng), Box::new(Program::rand(rng)), Box::new(Program::rand(rng))),
			i @ 1...2 if i < 2 => Program::Command(Command::rand(rng)),
			_ => panic!(),
		}
	}
}

impl rand::Rand for Condition {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 10) {
			i @ 0...1  if i < 1  => Condition::True,
			i @ 1...2  if i < 2  => Condition::False,
			i @ 2...3  if i < 3  => Condition::Not(Box::new(Condition::rand(rng))),
			i @ 3...4  if i < 4  => Condition::Or(Box::new(Condition::rand(rng)), Box::new(Condition::rand(rng))),
			i @ 4...5  if i < 5  => Condition::And(Box::new(Condition::rand(rng)), Box::new(Condition::rand(rng))),
			i @ 5...6  if i < 6  => Condition::Less(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 6...7  if i < 7  => Condition::LessEqual(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 7...8  if i < 8  => Condition::Equal(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 8...9  if i < 9  => Condition::GreaterEqual(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 9...10 if i < 10 => Condition::Greater(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			_ => panic!(),
		}
	}
}

impl rand::Rand for Command {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 4) {
			i @ 0...1 if i < 1 => Command::Skip,
			i @ 1...2 if i < 2 => Command::Left,
			i @ 2...3 if i < 3 => Command::Right,
			i @ 3...4 if i < 4 => Command::Up,
			_ => panic!(),
		}
	}
}

impl rand::Rand for Expression {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 6) {
			i @ 0...1 if i < 1 => Expression::Constant(rng.next_f32()),
			i @ 1...2 if i < 2 => Expression::Sensor(Sensor::rand(rng)),
			i @ 2...3 if i < 3 => Expression::Plus(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 3...4 if i < 4 => Expression::Minus(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 4...5 if i < 5 => Expression::Multiply(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 5...6 if i < 6 => Expression::Divide(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			_ => panic!(),
		}
	}
}

impl rand::Rand for Sensor {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 6) {
			i @ 0...1 if i < 1 => Sensor::X,
			i @ 1...2 if i < 2 => Sensor::Y,
			i @ 2...3 if i < 3 => Sensor::Vx,
			i @ 3...4 if i < 4 => Sensor::Vy,
			i @ 4...5 if i < 5 => Sensor::O,
			i @ 5...6 if i < 6 => Sensor::W,
			_ => panic!(),
		}
	}
}
<commit_msg>Use pick macro<commit_after>extern crate rand;

pub use self::rand::Rng;

use super::structure::{Program,Condition,Command,Expression,Sensor};

#[macro_export]
macro_rules! pick {
    ($( $weight: expr, $expression: expr),+) => {{
        let total = 0 $(+ $weight)+;
        let mut bound = 0;

        let mut rng = rand::thread_rng();
        let random_number = rng.gen_range(0, total);
        let result = $( if bound <= random_number && random_number < { bound += $weight; bound } {
            $expression
        } else )+ {
           panic!();
        };
        result
    }}
}

impl rand::Rand for Program {
	  fn rand<R: rand::Rng>(rng: &mut R) -> Self {
        pick![
            1, Program::If(Condition::rand(rng), Box::new(Program::rand(rng)), Box::new(Program::rand(rng))),
            1, Program::Command(Command::rand(rng))
        ]
	  }
}

impl rand::Rand for Condition {
	  fn rand<R: rand::Rng>(rng: &mut R) -> Self {
        pick![
            1, Condition::True,
			      1, Condition::False,
			      1, Condition::Not(Box::new(Condition::rand(rng))),
			      1, Condition::Or(Box::new(Condition::rand(rng)), Box::new(Condition::rand(rng))),
			      1, Condition::And(Box::new(Condition::rand(rng)), Box::new(Condition::rand(rng))),
			      1, Condition::Less(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			      1, Condition::LessEqual(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			      1, Condition::Equal(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			      1, Condition::GreaterEqual(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			      1, Condition::Greater(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng)))
		    ]
	  }
}

impl rand::Rand for Command {
	fn rand<R: rand::Rng>(_: &mut R) -> Self {
		  pick![1, Command::Skip, 1, Command::Left, 1, Command::Right, 1, Command::Up]
  }
}

impl rand::Rand for Expression {
	  fn rand<R: rand::Rng>(rng: &mut R) -> Self {
        pick![
            1, Expression::Constant(rng.next_f32()),
            1, Expression::Sensor(Sensor::rand(rng)),
            1, Expression::Plus(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
            1, Expression::Minus(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
            1, Expression::Multiply(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
            1, Expression::Divide(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng)))
        ]
	  }
}

impl rand::Rand for Sensor {
	  fn rand<R: rand::Rng>(_: &mut R) -> Self {
        pick![1, Sensor::X, 1, Sensor::Y, 1, Sensor::Vx, 1, Sensor::Vy, 1, Sensor::O, 1, Sensor::W]
	}
}
<|endoftext|>


<commit_before>use ::*;

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

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

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

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

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

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

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

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

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

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

        screen.flush().unwrap();
    }

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

<commit_msg>Simplify<commit_after>use ::*;

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

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

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

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

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

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

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

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

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

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

        screen.flush().unwrap();
    }

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

<|endoftext|>