<commit_before>use grammar::*;
use asm_ops::*;
use asm_ops::AsmOperand::*;
use asm_ops::AsmOp::*;
use asm_ops::Register::*;

struct AsmProgram {
    contents : Vec<AsmOp>
}

///A wrapper on Vec<AsmOp>
///Prints every addition for debugging purposes
impl AsmProgram{
    fn add(&mut self, op: AsmOp){
        println!("{:?}", &op);
        self.contents.push(op);
    }

    fn new() -> AsmProgram {
        AsmProgram {contents: Vec::new()}
    }
}

impl Extend<AsmOp> for AsmProgram {
    fn extend<T: IntoIterator<Item=AsmOp>>(&mut self, iterable: T) {
        for elem in iterable {
            self.add(elem);
        }
    }
}

///Indicates that a struct can be translated into IR code
trait AsmableExpression{
    fn get_ops(&self, var_store: &VarStore) -> Vec<AsmOp>;
}

impl AsmableExpression for Expr{
    fn get_ops(&self, var_store: &VarStore) -> Vec<AsmOp>{
        let mut ops = Vec::new();
        fn add(terms: &[AddTerm], var_store: &VarStore) -> Vec<AsmOp>{
            let mut ops = Vec::new();
            for term in terms {
                ops.extend(term.get_ops(var_store));
            }
            ops.push(Push(RegisterOperand(Register::RAX)));
            ops
        }
        fn mult(terms: &[MultTerm], var_store: &VarStore) -> Vec<AsmOp>{
            let mut ops = Vec::new();
            for term in terms {
                ops.extend(term.get_ops(var_store));
            }
            ops.push(Push(RegisterOperand(Register::RAX)));
            ops
        }
        match *self {
            Expr::AddSub(ref terms) => ops.extend(add(terms.as_slice(), var_store)),
            Expr::MultDiv(ref terms) => ops.extend(mult(terms.as_slice(), var_store)),
            Expr::Num(ref num) => ops.push(Push(Value(*num))),
            Expr::Variable(ref name) => ops.push(Push(Memory(var_store.get_var_address_r(name)))),
        }
        ops
    }
}

impl AsmableExpression for AddTerm{
    fn get_ops(&self, var_store: &VarStore) -> Vec<AsmOp>{
        let &AddTerm(ref op, ref expr) = self;
        let mut ops = Vec::new();
        match *op{
            AddOp::Start => {
                ops.extend(expr.get_ops(var_store));
                ops.push(Pop(RegisterOperand(Register::RAX)));
            },
            _ => {
                ops.push(Push(RegisterOperand(Register::RAX)));
                ops.extend(expr.get_ops(var_store));
                ops.push(Pop(RegisterOperand(Register::RBX)));
                ops.push(Pop(RegisterOperand(Register::RAX)));
                match *op{
                    AddOp::Add => ops.push(Add(Register::RAX, RegisterOperand(Register::RBX))),
                    AddOp::Subtract => ops.push(Sub(Register::RAX, RegisterOperand(Register::RBX))),
                    _ => panic!()
                }
            }
        }
        ops
    }
}

impl AsmableExpression for MultTerm{
    fn get_ops(&self, var_store: &VarStore) -> Vec<AsmOp>{
        let &MultTerm(ref op, ref expr) = self;
        let mut ops = Vec::new();
        match *op{
            MultOp::Start => {
                ops.extend(expr.get_ops(var_store));
                ops.push(Pop(RegisterOperand(Register::RAX)));
            },
            _ => {
                ops.push(Push(RegisterOperand(Register::RAX)));
                ops.extend(expr.get_ops(var_store));
                ops.push(Pop(RegisterOperand(Register::RBX)));
                ops.push(Pop(RegisterOperand(Register::RAX)));
                match *op{
                    MultOp::Multiply => ops.push(Mul(Register::RAX, RegisterOperand(Register::RBX))),
                    MultOp::Divide => ops.push(Div(Register::RAX, RegisterOperand(Register::RBX))),
                    MultOp::Modulo => ops.push(Mod(Register::RAX, RegisterOperand(Register::RBX))),
                    _ => panic!()
                }
            }
        }
        ops
    }
}

trait AsmableStatement{
    fn get_ops(&self, mut env: &mut Environment) -> Vec<AsmOp>;
}

impl AsmableStatement for Statement{
    fn get_ops(&self, mut env: &mut Environment) -> Vec<AsmOp>{
        let mut ops = Vec::new();
        println!("\n{:?}\nIs translated into:", self);
        match *self {
            Statement::Assign(ref name, ref expr) => {
                ops.extend(expr.get_ops(&env.var_store));
                ops.push(Pop(Memory(env.var_store.get_var_address_l(name))));
            }
            Statement::Output(ref expr) => {
                ops.extend(expr.get_ops(&env.var_store));
                ops.push(Pop(Memory(env.out_store.get_next_output_adress())));
            },
            Statement::Loop(ref expr, ref block) =>{
                ops.extend(expr.get_ops(&env.var_store));
                ops.push(Pop(RegisterOperand(RCX)));

                let label = env.loopl_store.get_next_loop_label();
                ops.push(Label(label.clone()));
                ops.extend(translate_stmts(&block.0, &mut env));
                ops.push(Loop(label));
            }
            _ => {}
        }
        ops
    }
}

use std::collections::HashMap;

struct VarStore{
    variables: HashMap<String, u16>,
    current_address: u16
}

///Stores addresses for variables
impl VarStore{
    fn new() -> VarStore{
        VarStore{variables: HashMap::new(), current_address: 500}
    }

    fn get_var_address_r(&self, name: &String) -> u16{
        match self.variables.get(name){
            Some(address) => *address,
            None => panic!("No variable named {}.", name)
        }
    }
    fn get_var_address_l(&mut self, name: &String) -> u16{
        if !self.variables.contains_key(name){
            let result = self.variables.insert(name.to_string(), self.current_address);
            match result{
                Some(_) => panic!(),
                None =>{
                    self.current_address += 8;
                    self.get_var_address_r(name)
                }
            }
        }else{
            self.get_var_address_r(name)
        }
    }
}

struct OutputStore(u16);

///Stores adresses for output values
impl OutputStore{
    fn get_next_output_adress(&mut self) -> u16{
        let address = self.0;
        self.0 += 8;
        address
    }
    fn new() -> OutputStore{
        OutputStore(1000)
    }
}

struct LoopLabelStore(u16);

impl LoopLabelStore{
    fn new() -> LoopLabelStore{
        LoopLabelStore(0)
    }
    fn get_next_loop_label(&mut self) -> String{
        let num = self.0;
        self.0 += 1;
        format!("label{}", num).to_string()
    }
}

struct Environment{
    var_store: VarStore,
    out_store: OutputStore,
    loopl_store: LoopLabelStore
}

impl Environment{
    fn new() -> Environment{
        Environment{var_store: VarStore::new(), out_store: OutputStore::new(), loopl_store: LoopLabelStore::new()}
    }
}

fn translate_stmts(block: &Vec<Statement>, mut env: &mut Environment) -> Vec<AsmOp>{
    let mut ops = Vec::new();
    for stmt in block {
        ops.extend(stmt.get_ops(&mut env));
    }
    ops
}
///Translates AST into a sequence of asm instructions
pub fn translate(block: &Vec<Statement>) -> Box<Vec<AsmOp>>{
    let mut ops =  AsmProgram::new();
    let mut env = Environment::new();
    ops.extend(translate_stmts(block, &mut env));
    Box::new(ops.contents)
}
<commit_msg>Fixed IR code ouput<commit_after>use grammar::*;
use asm_ops::*;
use asm_ops::AsmOperand::*;
use asm_ops::AsmOp::*;
use asm_ops::Register::*;

struct AsmProgram {
    contents : Vec<AsmOp>
}

///A wrapper on Vec<AsmOp>
///Prints every addition for debugging purposes
impl AsmProgram{
    fn add(&mut self, op: AsmOp){
        println!("{:?}", &op);
        self.contents.push(op);
    }

    fn new() -> AsmProgram {
        AsmProgram {contents: Vec::new()}
    }
}

impl Extend<AsmOp> for AsmProgram {
    fn extend<T: IntoIterator<Item=AsmOp>>(&mut self, iterable: T) {
        for elem in iterable {
            self.add(elem);
        }
    }
}

///Indicates that a struct can be translated into IR code
trait AsmableExpression{
    fn get_ops(&self, var_store: &VarStore) -> Vec<AsmOp>;
}

impl AsmableExpression for Expr{
    fn get_ops(&self, var_store: &VarStore) -> Vec<AsmOp>{
        let mut ops = Vec::new();
        fn add(terms: &[AddTerm], var_store: &VarStore) -> Vec<AsmOp>{
            let mut ops = Vec::new();
            for term in terms {
                ops.extend(term.get_ops(var_store));
            }
            ops.push(Push(RegisterOperand(Register::RAX)));
            ops
        }
        fn mult(terms: &[MultTerm], var_store: &VarStore) -> Vec<AsmOp>{
            let mut ops = Vec::new();
            for term in terms {
                ops.extend(term.get_ops(var_store));
            }
            ops.push(Push(RegisterOperand(Register::RAX)));
            ops
        }
        match *self {
            Expr::AddSub(ref terms) => ops.extend(add(terms.as_slice(), var_store)),
            Expr::MultDiv(ref terms) => ops.extend(mult(terms.as_slice(), var_store)),
            Expr::Num(ref num) => ops.push(Push(Value(*num))),
            Expr::Variable(ref name) => ops.push(Push(Memory(var_store.get_var_address_r(name)))),
        }
        ops
    }
}

impl AsmableExpression for AddTerm{
    fn get_ops(&self, var_store: &VarStore) -> Vec<AsmOp>{
        let &AddTerm(ref op, ref expr) = self;
        let mut ops = Vec::new();
        match *op{
            AddOp::Start => {
                ops.extend(expr.get_ops(var_store));
                ops.push(Pop(RegisterOperand(Register::RAX)));
            },
            _ => {
                ops.push(Push(RegisterOperand(Register::RAX)));
                ops.extend(expr.get_ops(var_store));
                ops.push(Pop(RegisterOperand(Register::RBX)));
                ops.push(Pop(RegisterOperand(Register::RAX)));
                match *op{
                    AddOp::Add => ops.push(Add(Register::RAX, RegisterOperand(Register::RBX))),
                    AddOp::Subtract => ops.push(Sub(Register::RAX, RegisterOperand(Register::RBX))),
                    _ => panic!()
                }
            }
        }
        ops
    }
}

impl AsmableExpression for MultTerm{
    fn get_ops(&self, var_store: &VarStore) -> Vec<AsmOp>{
        let &MultTerm(ref op, ref expr) = self;
        let mut ops = Vec::new();
        match *op{
            MultOp::Start => {
                ops.extend(expr.get_ops(var_store));
                ops.push(Pop(RegisterOperand(Register::RAX)));
            },
            _ => {
                ops.push(Push(RegisterOperand(Register::RAX)));
                ops.extend(expr.get_ops(var_store));
                ops.push(Pop(RegisterOperand(Register::RBX)));
                ops.push(Pop(RegisterOperand(Register::RAX)));
                match *op{
                    MultOp::Multiply => ops.push(Mul(Register::RAX, RegisterOperand(Register::RBX))),
                    MultOp::Divide => ops.push(Div(Register::RAX, RegisterOperand(Register::RBX))),
                    MultOp::Modulo => ops.push(Mod(Register::RAX, RegisterOperand(Register::RBX))),
                    _ => panic!()
                }
            }
        }
        ops
    }
}

trait AsmableStatement{
    fn get_ops(&self, mut env: &mut Environment, mut program: &mut AsmProgram);
}

impl AsmableStatement for Statement{
    fn get_ops(&self, mut env: &mut Environment, mut program: &mut AsmProgram) {
        println!("\n{:?}\nIs translated into:", self);
        match *self {
            Statement::Assign(ref name, ref expr) => {
                program.extend(expr.get_ops(&env.var_store));
                program.add(Pop(Memory(env.var_store.get_var_address_l(name))));
            }
            Statement::Output(ref expr) => {
                program.extend(expr.get_ops(&env.var_store));
                program.add(Pop(Memory(env.out_store.get_next_output_adress())));
            },
            Statement::Loop(ref expr, ref block) =>{
                program.extend(expr.get_ops(&env.var_store));
                program.add(Pop(RegisterOperand(RCX)));

                let label = env.loopl_store.get_next_loop_label();
                program.add(Label(label.clone()));
                translate_stmts(&block.0, &mut env, &mut program);
                program.add(Loop(label));
            }
            _ => {}
        }
    }
}

use std::collections::HashMap;

struct VarStore{
    variables: HashMap<String, u16>,
    current_address: u16
}

///Stores addresses for variables
impl VarStore{
    fn new() -> VarStore{
        VarStore{variables: HashMap::new(), current_address: 500}
    }

    fn get_var_address_r(&self, name: &String) -> u16{
        match self.variables.get(name){
            Some(address) => *address,
            None => panic!("No variable named {}.", name)
        }
    }
    fn get_var_address_l(&mut self, name: &String) -> u16{
        if !self.variables.contains_key(name){
            let result = self.variables.insert(name.to_string(), self.current_address);
            match result{
                Some(_) => panic!(),
                None =>{
                    self.current_address += 8;
                    self.get_var_address_r(name)
                }
            }
        }else{
            self.get_var_address_r(name)
        }
    }
}

struct OutputStore(u16);

///Stores adresses for output values
impl OutputStore{
    fn get_next_output_adress(&mut self) -> u16{
        let address = self.0;
        self.0 += 8;
        address
    }
    fn new() -> OutputStore{
        OutputStore(1000)
    }
}

struct LoopLabelStore(u16);

impl LoopLabelStore{
    fn new() -> LoopLabelStore{
        LoopLabelStore(0)
    }
    fn get_next_loop_label(&mut self) -> String{
        let num = self.0;
        self.0 += 1;
        format!("label{}", num).to_string()
    }
}

struct Environment{
    var_store: VarStore,
    out_store: OutputStore,
    loopl_store: LoopLabelStore
}

impl Environment{
    fn new() -> Environment{
        Environment{var_store: VarStore::new(), out_store: OutputStore::new(), loopl_store: LoopLabelStore::new()}
    }
}

fn translate_stmts(block: &Vec<Statement>, mut env: &mut Environment, mut program: &mut AsmProgram){
    for stmt in block {
        stmt.get_ops(&mut env, &mut program);
    }
}
///Translates AST into a sequence of asm instructions
pub fn translate(block: &Vec<Statement>) -> Box<Vec<AsmOp>>{
    let mut ops =  AsmProgram::new();
    let mut env = Environment::new();
    translate_stmts(block, &mut env, &mut ops);
    Box::new(ops.contents)
}
<|endoftext|>


<commit_before>// Intermediate representation
#![allow(dead_code, non_camel_case_types)]

use crate::parse::*;
use std::collections::HashMap;
use std::sync::Mutex;

fn to_ir_type(node_type: &NodeType) -> IRType {
    match node_type {
        NodeType::ADD => IRType::ADD,
        NodeType::SUB => IRType::SUB,
        NodeType::MUL => IRType::MUL,
        NodeType::DIV => IRType::DIV,
        _ => {
            panic!(format!("unknown NodeType {:?}", node_type));
        }
    }
}

lazy_static! {
    static ref CODE: Mutex<Vec<IR>> = Mutex::new(Vec::new());
    static ref REGNO: Mutex<i32> = Mutex::new(1);
    static ref BASEREG: Mutex<i32> = Mutex::new(0);
    static ref VARS: Mutex<HashMap<String, i32>> = Mutex::new(HashMap::new());
    static ref BPOFF: Mutex<i32> = Mutex::new(0);
    static ref LABEL: Mutex<i32> = Mutex::new(0);
    static ref IRINFO: Mutex<Vec<IRInfo>> = Mutex::new(vec![
        IRInfo {
            op: IRType::ADD,
            name: String::from("+"),
            ty: IRInfoType::REG_REG
        },
        IRInfo {
            op: IRType::SUB,
            name: String::from("-"),
            ty: IRInfoType::REG_REG
        },
        IRInfo {
            op: IRType::MUL,
            name: String::from("*"),
            ty: IRInfoType::REG_REG
        },
        IRInfo {
            op: IRType::DIV,
            name: String::from("/"),
            ty: IRInfoType::REG_REG
        },
        IRInfo {
            op: IRType::IMM,
            name: String::from("MOV"),
            ty: IRInfoType::REG_IMM
        },
        IRInfo {
            op: IRType::ADD_IMM,
            name: String::from("ADD"),
            ty: IRInfoType::REG_IMM
        },
        IRInfo {
            op: IRType::MOV,
            name: String::from("MOV"),
            ty: IRInfoType::REG_REG
        },
        IRInfo {
            op: IRType::LABEL,
            name: String::new(),
            ty: IRInfoType::LABEL
        },
        IRInfo {
            op: IRType::JMP,
            name: String::from("JMP"),
            ty: IRInfoType::LABEL
        },
        IRInfo {
            op: IRType::UNLESS,
            name: String::from("UNLESS"),
            ty: IRInfoType::REG_LABEL
        },
        IRInfo {
            op: IRType::RETURN,
            name: String::from("RET"),
            ty: IRInfoType::REG
        },
        IRInfo {
            op: IRType::ALLOCA,
            name: String::from("ALLOCA"),
            ty: IRInfoType::REG_IMM
        },
        IRInfo {
            op: IRType::LOAD,
            name: String::from("LOAD"),
            ty: IRInfoType::REG_REG
        },
        IRInfo {
            op: IRType::STORE,
            name: String::from("STORE"),
            ty: IRInfoType::REG_REG
        },
        IRInfo {
            op: IRType::KILL,
            name: String::from("KILL"),
            ty: IRInfoType::REG
        },
        IRInfo {
            op: IRType::NOP,
            name: String::from("NOP"),
            ty: IRInfoType::NOARG
        },
        IRInfo {
            op: IRType::NULL,
            name: String::new(),
            ty: IRInfoType::NULL
        },
    ]);
}

fn basereg() -> i32 {
    *BASEREG.lock().unwrap()
}

#[derive(Clone, Debug, PartialEq)]
pub enum IRType {
    IMM,
    ADD_IMM,
    MOV,
    RETURN,
    LABEL,
    JMP,
    UNLESS,
    ALLOCA,
    LOAD,
    STORE,
    KILL,
    ADD,
    SUB,
    MUL,
    DIV,
    NOP,
    NULL,
}

#[derive(Clone, Debug)]
pub struct IR {
    pub op: IRType,
    pub lhs: i32,
    pub rhs: i32,
}

#[derive(Clone, Debug)]
pub enum IRInfoType {
    NOARG,
    REG,
    LABEL,
    REG_REG,
    REG_IMM,
    REG_LABEL,
    NULL,
}

#[derive(Clone, Debug)]
pub struct IRInfo {
    pub op: IRType,
    pub name: String,
    pub ty: IRInfoType,
}

pub fn get_irinfo(ir: &IR) -> IRInfo {
    let irinfo = IRINFO.lock().unwrap();
    for i in 0..irinfo.len() {
        if irinfo[i].op == ir.op {
            return irinfo[i].clone();
        }
    }
    panic!("invalid instruction");
}

fn tostr(ir: IR) -> String {
    let info = get_irinfo(&ir);
    return match info.ty {
        IRInfoType::LABEL => format!("{}:", ir.lhs),
        IRInfoType::REG => format!("{} r{}", info.name, ir.lhs),
        IRInfoType::REG_REG => format!("{} r{}, r{}", info.name, ir.lhs, ir.rhs),
        IRInfoType::REG_IMM => format!("{} r{}, {}", info.name, ir.lhs, ir.rhs),
        IRInfoType::REG_LABEL => format!("{} r{}, .L{}", info.name, ir.lhs, ir.rhs),
        IRInfoType::NOARG => format!("{}", info.name),
        _ => {
            panic!("unknown ir");
        }
    };
}

fn dump_ir(irv: Vec<IR>) {
    for i in irv {
        eprintln!("{}", tostr(i));
    }
}

fn add(op: IRType, lhs: i32, rhs: i32) -> usize {
    let ir = IR {
        op: op,
        lhs: lhs,
        rhs: rhs,
    };

    match CODE.lock() {
        Ok(mut code) => {
            (*code).push(ir);
            return code.len() - 1;
        }
        Err(_) => {
            panic!();
        }
    }
}

fn gen_lval(node: Node) -> i32 {
    if node.ty != NodeType::IDENT {
        panic!("not an lvaue");
    }

    let mut vars = VARS.lock().unwrap();
    if None == vars.get(&node.name) {
        let mut bpoff = BPOFF.lock().unwrap();
        (*vars).insert(node.name.clone(), *bpoff);
        *bpoff += 8;
    }

    let mut regno = REGNO.lock().unwrap();
    let r = *regno;
    *regno += 1;

    let off = *vars.get(&node.name).unwrap();
    let basereg = BASEREG.lock().unwrap();

    add(IRType::MOV, r, *basereg);
    add(IRType::ADD_IMM, r, off);
    return r;
}

fn gen_expr(node: Node) -> i32 {
    if node.ty == NodeType::NUM {
        let mut regno = REGNO.lock().unwrap();

        let r = *regno;
        *regno += 1;
        add(IRType::IMM, r, node.val);
        return r;
    }

    if node.ty == NodeType::IDENT {
        let r = gen_lval(node);
        add(IRType::LOAD, r, r);
        return r;
    }

    if node.ty == NodeType::EQ {
        let rhs = gen_expr(*node.rhs.unwrap());
        let lhs = gen_lval(*node.lhs.unwrap());
        add(IRType::STORE, lhs, rhs);
        add(IRType::KILL, rhs, -1);
        return lhs;
    }

    assert!(
        node.ty == NodeType::ADD
            || node.ty == NodeType::SUB
            || node.ty == NodeType::MUL
            || node.ty == NodeType::DIV,
        format!("not op: {:?}", node)
    );

    let lhs = gen_expr(*node.lhs.unwrap());
    let rhs = gen_expr(*node.rhs.unwrap());

    add(to_ir_type(&node.ty), lhs, rhs);
    add(IRType::KILL, rhs, -1);
    return lhs;
}

fn gen_stmt(node: Node) {
    match node.ty {
        NodeType::IF => {
            let r = gen_expr(*node.cond.unwrap());
            let mut label = LABEL.lock().unwrap();
            let x = *label;
            *label += 1;

            add(IRType::UNLESS, r, x);
            add(IRType::KILL, r, -1);

            gen_stmt(*node.then.unwrap());

            if node.els.is_none() {
                add(IRType::LABEL, x, -1);
                return;
            }

            let y = *label;
            *label += 1;
            add(IRType::JMP, y, -1);
            add(IRType::LABEL, x, -1);
            gen_stmt(*node.els.unwrap());
            add(IRType::LABEL, y, -1);
        }
        NodeType::RETURN => {
            let r = gen_expr(*node.expr.unwrap());
            add(IRType::RETURN, r, -1);
            add(IRType::KILL, r, -1);
        }
        NodeType::EXPR_STMT => {
            let r = gen_expr(*node.expr.unwrap());
            add(IRType::KILL, r, -1);
        }
        NodeType::COMP_STMT => {
            for n in node.stmts {
                gen_stmt(n);
            }
        }
        _ => {
            panic!(format!("unknown node: {:?}", node.ty));
        }
    }
}

pub fn gen_ir(node: Node) -> Vec<IR> {
    assert!(node.ty == NodeType::COMP_STMT, "");

    let alloca_idx = add(IRType::ALLOCA, basereg(), -1);
    gen_stmt(node);

    let mut code = CODE.lock().unwrap();
    code[alloca_idx].rhs = *BPOFF.lock().unwrap();
    return code.clone();
}
<commit_msg>Fix crash bug.<commit_after>// Intermediate representation
#![allow(dead_code, non_camel_case_types)]

use crate::parse::*;
use std::collections::HashMap;
use std::sync::Mutex;

fn to_ir_type(node_type: &NodeType) -> IRType {
    match node_type {
        NodeType::ADD => IRType::ADD,
        NodeType::SUB => IRType::SUB,
        NodeType::MUL => IRType::MUL,
        NodeType::DIV => IRType::DIV,
        _ => {
            panic!(format!("unknown NodeType {:?}", node_type));
        }
    }
}

lazy_static! {
    static ref CODE: Mutex<Vec<IR>> = Mutex::new(Vec::new());
    static ref REGNO: Mutex<i32> = Mutex::new(1);
    static ref BASEREG: Mutex<i32> = Mutex::new(0);
    static ref VARS: Mutex<HashMap<String, i32>> = Mutex::new(HashMap::new());
    static ref BPOFF: Mutex<i32> = Mutex::new(0);
    static ref LABEL: Mutex<i32> = Mutex::new(0);
    static ref IRINFO: Mutex<Vec<IRInfo>> = Mutex::new(vec![
        IRInfo {
            op: IRType::ADD,
            name: String::from("+"),
            ty: IRInfoType::REG_REG
        },
        IRInfo {
            op: IRType::SUB,
            name: String::from("-"),
            ty: IRInfoType::REG_REG
        },
        IRInfo {
            op: IRType::MUL,
            name: String::from("*"),
            ty: IRInfoType::REG_REG
        },
        IRInfo {
            op: IRType::DIV,
            name: String::from("/"),
            ty: IRInfoType::REG_REG
        },
        IRInfo {
            op: IRType::IMM,
            name: String::from("MOV"),
            ty: IRInfoType::REG_IMM
        },
        IRInfo {
            op: IRType::ADD_IMM,
            name: String::from("ADD"),
            ty: IRInfoType::REG_IMM
        },
        IRInfo {
            op: IRType::MOV,
            name: String::from("MOV"),
            ty: IRInfoType::REG_REG
        },
        IRInfo {
            op: IRType::LABEL,
            name: String::new(),
            ty: IRInfoType::LABEL
        },
        IRInfo {
            op: IRType::JMP,
            name: String::from("JMP"),
            ty: IRInfoType::LABEL
        },
        IRInfo {
            op: IRType::UNLESS,
            name: String::from("UNLESS"),
            ty: IRInfoType::REG_LABEL
        },
        IRInfo {
            op: IRType::RETURN,
            name: String::from("RET"),
            ty: IRInfoType::REG
        },
        IRInfo {
            op: IRType::ALLOCA,
            name: String::from("ALLOCA"),
            ty: IRInfoType::REG_IMM
        },
        IRInfo {
            op: IRType::LOAD,
            name: String::from("LOAD"),
            ty: IRInfoType::REG_REG
        },
        IRInfo {
            op: IRType::STORE,
            name: String::from("STORE"),
            ty: IRInfoType::REG_REG
        },
        IRInfo {
            op: IRType::KILL,
            name: String::from("KILL"),
            ty: IRInfoType::REG
        },
        IRInfo {
            op: IRType::NOP,
            name: String::from("NOP"),
            ty: IRInfoType::NOARG
        },
        IRInfo {
            op: IRType::NULL,
            name: String::new(),
            ty: IRInfoType::NULL
        },
    ]);
}

fn basereg() -> i32 {
    *BASEREG.lock().unwrap()
}

#[derive(Clone, Debug, PartialEq)]
pub enum IRType {
    IMM,
    ADD_IMM,
    MOV,
    RETURN,
    LABEL,
    JMP,
    UNLESS,
    ALLOCA,
    LOAD,
    STORE,
    KILL,
    ADD,
    SUB,
    MUL,
    DIV,
    NOP,
    NULL,
}

#[derive(Clone, Debug)]
pub struct IR {
    pub op: IRType,
    pub lhs: i32,
    pub rhs: i32,
}

#[derive(Clone, Debug)]
pub enum IRInfoType {
    NOARG,
    REG,
    LABEL,
    REG_REG,
    REG_IMM,
    REG_LABEL,
    NULL,
}

#[derive(Clone, Debug)]
pub struct IRInfo {
    pub op: IRType,
    pub name: String,
    pub ty: IRInfoType,
}

pub fn get_irinfo(ir: &IR) -> IRInfo {
    let irinfo = IRINFO.lock().unwrap();
    for i in 0..irinfo.len() {
        if irinfo[i].op == ir.op {
            return irinfo[i].clone();
        }
    }
    panic!("invalid instruction");
}

fn tostr(ir: IR) -> String {
    let info = get_irinfo(&ir);
    return match info.ty {
        IRInfoType::LABEL => format!(".L{}:", ir.lhs),
        IRInfoType::REG => format!("{} r{}", info.name, ir.lhs),
        IRInfoType::REG_REG => format!("{} r{}, r{}", info.name, ir.lhs, ir.rhs),
        IRInfoType::REG_IMM => format!("{} r{}, {}", info.name, ir.lhs, ir.rhs),
        IRInfoType::REG_LABEL => format!("{} r{}, .L{}", info.name, ir.lhs, ir.rhs),
        IRInfoType::NOARG => format!("{}", info.name),
        _ => {
            panic!("unknown ir");
        }
    };
}

fn dump_ir(irv: Vec<IR>) {
    for i in irv {
        eprintln!("{}", tostr(i));
    }
}

fn add(op: IRType, lhs: i32, rhs: i32) -> usize {
    let ir = IR {
        op: op,
        lhs: lhs,
        rhs: rhs,
    };

    match CODE.lock() {
        Ok(mut code) => {
            (*code).push(ir);
            return code.len() - 1;
        }
        Err(_) => {
            panic!();
        }
    }
}

fn gen_lval(node: Node) -> i32 {
    if node.ty != NodeType::IDENT {
        panic!("not an lvaue");
    }

    let mut vars = VARS.lock().unwrap();
    if None == vars.get(&node.name) {
        let mut bpoff = BPOFF.lock().unwrap();
        (*vars).insert(node.name.clone(), *bpoff);
        *bpoff += 8;
    }

    let mut regno = REGNO.lock().unwrap();
    let r = *regno;
    *regno += 1;

    let off = *vars.get(&node.name).unwrap();
    let basereg = BASEREG.lock().unwrap();

    add(IRType::MOV, r, *basereg);
    add(IRType::ADD_IMM, r, off);
    return r;
}

fn gen_expr(node: Node) -> i32 {
    if node.ty == NodeType::NUM {
        let mut regno = REGNO.lock().unwrap();

        let r = *regno;
        *regno += 1;
        add(IRType::IMM, r, node.val);
        return r;
    }

    if node.ty == NodeType::IDENT {
        let r = gen_lval(node);
        add(IRType::LOAD, r, r);
        return r;
    }

    if node.ty == NodeType::EQ {
        let rhs = gen_expr(*node.rhs.unwrap());
        let lhs = gen_lval(*node.lhs.unwrap());
        add(IRType::STORE, lhs, rhs);
        add(IRType::KILL, rhs, -1);
        return lhs;
    }

    assert!(
        node.ty == NodeType::ADD
            || node.ty == NodeType::SUB
            || node.ty == NodeType::MUL
            || node.ty == NodeType::DIV,
        format!("not op: {:?}", node)
    );

    let lhs = gen_expr(*node.lhs.unwrap());
    let rhs = gen_expr(*node.rhs.unwrap());

    add(to_ir_type(&node.ty), lhs, rhs);
    add(IRType::KILL, rhs, -1);
    return lhs;
}

fn gen_stmt(node: Node) {
    match node.ty {
        NodeType::IF => {
            let r = gen_expr(*node.cond.unwrap());
            let mut label = LABEL.lock().unwrap();
            let x = *label;
            *label += 1;

            add(IRType::UNLESS, r, x);
            add(IRType::KILL, r, -1);

            gen_stmt(*node.then.unwrap());

            if node.els.is_none() {
                add(IRType::LABEL, x, -1);
                return;
            }

            let y = *label;
            *label += 1;
            add(IRType::JMP, y, -1);
            add(IRType::LABEL, x, -1);
            gen_stmt(*node.els.unwrap());
            add(IRType::LABEL, y, -1);
        }
        NodeType::RETURN => {
            let r = gen_expr(*node.expr.unwrap());
            add(IRType::RETURN, r, -1);
            add(IRType::KILL, r, -1);
        }
        NodeType::EXPR_STMT => {
            let r = gen_expr(*node.expr.unwrap());
            add(IRType::KILL, r, -1);
        }
        NodeType::COMP_STMT => {
            for n in node.stmts {
                gen_stmt(n);
            }
        }
        _ => {
            panic!(format!("unknown node: {:?}", node.ty));
        }
    }
}

pub fn gen_ir(node: Node) -> Vec<IR> {
    assert!(node.ty == NodeType::COMP_STMT, "");

    let alloca_idx = add(IRType::ALLOCA, basereg(), -1);
    gen_stmt(node);

    let mut code = CODE.lock().unwrap();
    code[alloca_idx].rhs = *BPOFF.lock().unwrap();
    return code.clone();
}
<|endoftext|>


<commit_before>extern crate pkg_config;
extern crate gcc;

use std::env;

fn main() {
    match pkg_config::find_library("lua5.2") {
        Ok(_) => return,
        Err(..) => {}
    };

    let mut config = gcc::Config::new();

    if env::var("CARGO_CFG_TARGET_OS") == Ok("linux".to_string()) {
        // Enable `io.popen` support
        config.define("LUA_USE_LINUX", None);
    }

    config
        .file("lua/src/lapi.c")
        .file("lua/src/lcode.c")
        .file("lua/src/lctype.c")
        .file("lua/src/ldebug.c")
        .file("lua/src/ldo.c")
        .file("lua/src/ldump.c")
        .file("lua/src/lfunc.c")
        .file("lua/src/lgc.c")
        .file("lua/src/llex.c")
        .file("lua/src/lmem.c")
        .file("lua/src/lobject.c")
        .file("lua/src/lopcodes.c")
        .file("lua/src/lparser.c")
        .file("lua/src/lstate.c")
        .file("lua/src/lstring.c")
        .file("lua/src/ltable.c")
        .file("lua/src/ltm.c")
        .file("lua/src/lundump.c")
        .file("lua/src/lvm.c")
        .file("lua/src/lzio.c")
        .file("lua/src/lauxlib.c")
        .file("lua/src/lbaselib.c")
        .file("lua/src/lbitlib.c")
        .file("lua/src/lcorolib.c")
        .file("lua/src/ldblib.c")
        .file("lua/src/liolib.c")
        .file("lua/src/lmathlib.c")
        .file("lua/src/loslib.c")
        .file("lua/src/lstrlib.c")
        .file("lua/src/ltablib.c")
        .file("lua/src/loadlib.c")
        .file("lua/src/linit.c")
        .define("LUA_COMPAT_ALL", None)
        .include("lua/src")
        .compile("liblua.a");
}
<commit_msg>Rename deprecated gcc::Config to gcc::Build.<commit_after>extern crate pkg_config;
extern crate gcc;

use std::env;

fn main() {
    match pkg_config::find_library("lua5.2") {
        Ok(_) => return,
        Err(..) => {}
    };

    let mut build = gcc::Build::new();

    if env::var("CARGO_CFG_TARGET_OS") == Ok("linux".to_string()) {
        // Enable `io.popen` support
        build.define("LUA_USE_LINUX", None);
    }

    build
        .file("lua/src/lapi.c")
        .file("lua/src/lcode.c")
        .file("lua/src/lctype.c")
        .file("lua/src/ldebug.c")
        .file("lua/src/ldo.c")
        .file("lua/src/ldump.c")
        .file("lua/src/lfunc.c")
        .file("lua/src/lgc.c")
        .file("lua/src/llex.c")
        .file("lua/src/lmem.c")
        .file("lua/src/lobject.c")
        .file("lua/src/lopcodes.c")
        .file("lua/src/lparser.c")
        .file("lua/src/lstate.c")
        .file("lua/src/lstring.c")
        .file("lua/src/ltable.c")
        .file("lua/src/ltm.c")
        .file("lua/src/lundump.c")
        .file("lua/src/lvm.c")
        .file("lua/src/lzio.c")
        .file("lua/src/lauxlib.c")
        .file("lua/src/lbaselib.c")
        .file("lua/src/lbitlib.c")
        .file("lua/src/lcorolib.c")
        .file("lua/src/ldblib.c")
        .file("lua/src/liolib.c")
        .file("lua/src/lmathlib.c")
        .file("lua/src/loslib.c")
        .file("lua/src/lstrlib.c")
        .file("lua/src/ltablib.c")
        .file("lua/src/loadlib.c")
        .file("lua/src/linit.c")
        .define("LUA_COMPAT_ALL", None)
        .include("lua/src")
        .compile("liblua.a");
}
<|endoftext|>


<commit_before>use std;
use std::ops::Add;
use std::io::{self, Write, Read};
use time::{self, Timespec, Duration};

macro_rules! printfl {
    ($($tt:tt)*) => {{
        use std::io::{self, Write};
        print!($($tt)*);
        io::stdout().flush().ok().expect("flush() fail");
    }}
}

macro_rules! kb_fmt {
    ($n: ident) => {{
        let kb = 1024f64;
        match $n {
            $n if $n > kb.powf(4_f64) => format!("{:.*} TG", 2, $n / kb.powf(4_f64)),
            $n if $n > kb.powf(3_f64) => format!("{:.*} GB", 2, $n / kb.powf(3_f64)),
            $n if $n > kb => format!("{:.*} KB", 2, $n / kb),
            _ => format!("{:.*} B", 0, $n)
        }
    }}
}

macro_rules! repeat {
    ($s: expr, $n: expr) => {{
        &std::iter::repeat($s).take($n).collect::<String>()
    }}
}

static FORMAT: &'static str = "[=>-]";

// Output type format, indicate which format wil be used in
// the speed box.
pub enum Units {
    Default,
    Bytes
}

pub struct ProgressBar {
    start_time: Timespec,
    units: Units,
    total: usize,
    current: usize,
    is_finish: bool,
    show_bar: bool,
    show_speed: bool,
    show_percent: bool,
    show_counter: bool,
    show_time_left: bool,
    bar_start: String,
    bar_current: String,
    bar_current_n: String,
    bar_remain: String,
    bar_end: String,
}

impl ProgressBar {

    pub fn new(total: usize) -> ProgressBar {
        let mut pb = ProgressBar {
            total: total,
            current: 0,
            start_time: time::get_time(),
            units: Units::Default,
            is_finish: false,
            show_bar: true,
            show_speed: false,
            show_percent: true,
            show_counter: true,
            show_time_left: true,
            bar_start: String::new(),
            bar_current: String::new(),
            bar_current_n: String::new(),
            bar_remain: String::new(),
            bar_end: String::new(),
        };
        pb.format(FORMAT);
        pb
    }

    pub fn set_units(&mut self, u: Units) {
        self.units = u;
    }

    fn format(&mut self, fmt: &str) {
        if fmt.len() >= 5 {
            let v: Vec<&str> = fmt.split("").collect();
            self.bar_start = v[1].to_string();
            self.bar_current = v[2].to_string();
            self.bar_current_n = v[3].to_string();
            self.bar_remain = v[4].to_string();
            self.bar_end = v[5].to_string();
        }
    }

    pub fn add(&mut self, i: usize) -> usize {
        self.current += i;
        if self.current <= self.total {
            self.draw()
        };
        self.current
    }

    fn draw(&self) {
        let width = 145;    // replace to -> get_tty_size()
        let mut base = String::new();
        let mut suffix = String::new();
        let mut prefix = String::new();
        let mut out;
        // precent box
        if self.show_percent {
            let percent = self.current as f64 / (self.total as f64 / 100f64);
            suffix = suffix + &format!(" {:.*} % ", 2, percent);
        }
        // speed box
        if !self.show_speed {
            let from_start = (time::get_time() - self.start_time).num_nanoseconds().unwrap() as f64;
            let sec_nano = Duration::seconds(1).num_nanoseconds().unwrap() as f64;
            let speed = self.current as f64 / (from_start / sec_nano);
            suffix = match self.units {
                Units::Default => suffix + &format!("{}/s ", speed),
                Units::Bytes => suffix + &format!("{}/s ", kb_fmt!(speed)),
            };
        }
        // time left box
        if self.show_time_left {
            let from_start = time::get_time() - self.start_time;
            let sec_nano = Duration::seconds(1).num_nanoseconds().unwrap() as i32;
            let per_entry = from_start / self.current as i32;
            let mut left = per_entry * (self.total - self.current) as i32;
            left = (left / sec_nano) * sec_nano;
            if left.num_seconds() > 0 {
                if left.num_seconds() < Duration::minutes(1).num_seconds() {
                    suffix = suffix + &format!("{}s", left.num_seconds());
                } else {
                    suffix = suffix + &format!("{}m", left.num_minutes());
                }
            }
        }
        // counter box
        if self.show_counter {
            let (c, t) = (self.current as f64, self.total as f64);
            prefix = match self.units {
                Units::Default => format!("{} / {} ", c, t),
                Units::Bytes => format!("{} / {} ", kb_fmt!(c), kb_fmt!(t)),
            };
        }
        // bar box
        if self.show_bar {
            let size = width - (prefix.len() + suffix.len() + 3);
            if size > 0 {
                let curr_count =
                    ((self.current as f64 / self.total as f64) * size as f64).ceil() as usize;
                let rema_count = size - curr_count;
                base = self.bar_start.to_string();
                if rema_count > 0 {
                    base = base + repeat!(self.bar_current.as_ref(), curr_count - 1) +
                           &self.bar_current_n;
                } else {
                    base = base + repeat!(self.bar_current.as_ref(), curr_count);
                }
                base = base + repeat!(self.bar_remain.as_ref(), rema_count) + &self.bar_end;
            }
        }
        out = prefix + &base + &suffix;
        // pad
        if out.len() < width {
            let gap = width - out.len();
            out = out + repeat!(" ", gap);
        }
        // print
        printfl!("\r{}", out);
    }

    pub fn finish(&mut self) {
        if self.current < self.total {
            self.current = self.total;
            self.draw();
        }
        println!("");
        self.is_finish = true;
    }
}

// Implement io::Writer
impl Write for ProgressBar {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let n = buf.len();
        self.add(n);
        Ok(buf.len())
    }
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

// TODO: Implement io::Reader
<commit_msg>rustfmt<commit_after>use std;
use std::ops::Add;
use std::io::{self, Write, Read};
use time::{self, Timespec, Duration};

macro_rules! printfl {
    ($($tt:tt)*) => {{
        use std::io::{self, Write};
        print!($($tt)*);
        io::stdout().flush().ok().expect("flush() fail");
    }}
}

macro_rules! kb_fmt {
    ($n: ident) => {{
        let kb = 1024f64;
        match $n {
            $n if $n > kb.powf(4_f64) => format!("{:.*} TG", 2, $n / kb.powf(4_f64)),
            $n if $n > kb.powf(3_f64) => format!("{:.*} GB", 2, $n / kb.powf(3_f64)),
            $n if $n > kb => format!("{:.*} KB", 2, $n / kb),
            _ => format!("{:.*} B", 0, $n)
        }
    }}
}

macro_rules! repeat {
    ($s: expr, $n: expr) => {{
        &std::iter::repeat($s).take($n).collect::<String>()
    }}
}

static FORMAT: &'static str = "[=>-]";

// Output type format, indicate which format wil be used in
// the speed box.
pub enum Units {
    Default,
    Bytes,
}

pub struct ProgressBar {
    start_time: Timespec,
    units: Units,
    total: usize,
    current: usize,
    is_finish: bool,
    show_bar: bool,
    show_speed: bool,
    show_percent: bool,
    show_counter: bool,
    show_time_left: bool,
    bar_start: String,
    bar_current: String,
    bar_current_n: String,
    bar_remain: String,
    bar_end: String,
}

impl ProgressBar {

    pub fn new(total: usize) -> ProgressBar {
        let mut pb = ProgressBar {
            total: total,
            current: 0,
            start_time: time::get_time(),
            units: Units::Default,
            is_finish: false,
            show_bar: true,
            show_speed: false,
            show_percent: true,
            show_counter: true,
            show_time_left: true,
            bar_start: String::new(),
            bar_current: String::new(),
            bar_current_n: String::new(),
            bar_remain: String::new(),
            bar_end: String::new(),
        };
        pb.format(FORMAT);
        pb
    }

    pub fn set_units(&mut self, u: Units) {
        self.units = u;
    }

    fn format(&mut self, fmt: &str) {
        if fmt.len() >= 5 {
            let v: Vec<&str> = fmt.split("").collect();
            self.bar_start = v[1].to_string();
            self.bar_current = v[2].to_string();
            self.bar_current_n = v[3].to_string();
            self.bar_remain = v[4].to_string();
            self.bar_end = v[5].to_string();
        }
    }

    pub fn add(&mut self, i: usize) -> usize {
        self.current += i;
        if self.current <= self.total {
            self.draw()
        };
        self.current
    }

    fn draw(&self) {
        let width = 145;    // replace to -> get_tty_size()
        let mut base = String::new();
        let mut suffix = String::new();
        let mut prefix = String::new();
        let mut out;
        // precent box
        if self.show_percent {
            let percent = self.current as f64 / (self.total as f64 / 100f64);
            suffix = suffix + &format!(" {:.*} % ", 2, percent);
        }
        // speed box
        if !self.show_speed {
            let from_start = (time::get_time() - self.start_time).num_nanoseconds().unwrap() as f64;
            let sec_nano = Duration::seconds(1).num_nanoseconds().unwrap() as f64;
            let speed = self.current as f64 / (from_start / sec_nano);
            suffix = match self.units {
                Units::Default => suffix + &format!("{}/s ", speed),
                Units::Bytes => suffix + &format!("{}/s ", kb_fmt!(speed)),
            };
        }
        // time left box
        if self.show_time_left {
            let from_start = time::get_time() - self.start_time;
            let sec_nano = Duration::seconds(1).num_nanoseconds().unwrap() as i32;
            let per_entry = from_start / self.current as i32;
            let mut left = per_entry * (self.total - self.current) as i32;
            left = (left / sec_nano) * sec_nano;
            if left.num_seconds() > 0 {
                if left.num_seconds() < Duration::minutes(1).num_seconds() {
                    suffix = suffix + &format!("{}s", left.num_seconds());
                } else {
                    suffix = suffix + &format!("{}m", left.num_minutes());
                }
            }
        }
        // counter box
        if self.show_counter {
            let (c, t) = (self.current as f64, self.total as f64);
            prefix = match self.units {
                Units::Default => format!("{} / {} ", c, t),
                Units::Bytes => format!("{} / {} ", kb_fmt!(c), kb_fmt!(t)),
            };
        }
        // bar box
        if self.show_bar {
            let size = width - (prefix.len() + suffix.len() + 3);
            if size > 0 {
                let curr_count =
                    ((self.current as f64 / self.total as f64) * size as f64).ceil() as usize;
                let rema_count = size - curr_count;
                base = self.bar_start.to_string();
                if rema_count > 0 {
                    base = base + repeat!(self.bar_current.as_ref(), curr_count - 1) +
                           &self.bar_current_n;
                } else {
                    base = base + repeat!(self.bar_current.as_ref(), curr_count);
                }
                base = base + repeat!(self.bar_remain.as_ref(), rema_count) + &self.bar_end;
            }
        }
        out = prefix + &base + &suffix;
        // pad
        if out.len() < width {
            let gap = width - out.len();
            out = out + repeat!(" ", gap);
        }
        // print
        printfl!("\r{}", out);
    }

    pub fn finish(&mut self) {
        if self.current < self.total {
            self.current = self.total;
            self.draw();
        }
        println!("");
        self.is_finish = true;
    }
}

// Implement io::Writer
impl Write for ProgressBar {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let n = buf.len();
        self.add(n);
        Ok(buf.len())
    }
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

// TODO: Implement io::Reader
<|endoftext|>


<commit_before>use fillings::{BitsVec, ReprUsize};
use num_traits::{Num, NumCast, cast};

use std::mem;
use std::usize;

// Prefer this for marking, instead of Option<usize> (as it requires additional byte of memory)
const MARKER: usize = usize::MAX;

#[repr(usize)]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum SuffixType {
    Small,
    Large,
    LeftMostSmall,
}

impl ReprUsize for SuffixType {
    fn into_usize(self) -> usize { self as usize }
    fn from_usize(i: usize) -> SuffixType {
        unsafe { mem::transmute(i) }
    }
}

fn induced_sort_large<T>(input: &[T], approx_sa: &mut [usize],
                         mut bucket_heads: BitsVec<usize>, type_map: &BitsVec<SuffixType>)
    where T: Num + NumCast + PartialOrd + Copy
{
    for i in 0..approx_sa.len() {
        if approx_sa[i] == MARKER || approx_sa[i] == 0 {
            continue
        }

        let j = approx_sa[i] - 1;
        if type_map.get(j) != SuffixType::Large {
            continue    // only the L-types
        }

        let bucket_idx = cast(input[j]).unwrap();
        let bucket_value = bucket_heads.get(bucket_idx);
        approx_sa[bucket_value] = j;
        bucket_heads.set(bucket_idx, bucket_value + 1);
    }
}

fn induced_sort_small<T>(input: &[T], approx_sa: &mut [usize],
                         mut bucket_tails: BitsVec<usize>, type_map: &BitsVec<SuffixType>)
    where T: Num + NumCast + PartialOrd + Copy
{
    for i in (0..approx_sa.len()).rev() {
        if approx_sa[i] == MARKER || approx_sa[i] == 0 {
            continue
        }

        let j = approx_sa[i] - 1;
        if type_map.get(j) == SuffixType::Large {
            continue    // only the S-types (and LMS-types as per our grouping)
        }

        let bucket_idx = cast(input[j]).unwrap();
        let bucket_value = bucket_tails.get(bucket_idx);
        approx_sa[bucket_value] = j;
        bucket_tails.set(bucket_idx, bucket_value - 1);
    }
}

// Check whether the string between two LMS bytes have the same lengths and same contents
fn is_equal_lms<T>(input: &[T], type_map: &BitsVec<SuffixType>, j: usize, k: usize) -> bool
    where T: Num + NumCast + PartialOrd + Copy
{
    if j == input.len() || k == input.len() {
        return false    // null byte
    }

    for i in 0..(input.len() + 1) {
        let first_lms = type_map.get(i + j) == SuffixType::LeftMostSmall;
        let second_lms = type_map.get(i + k) == SuffixType::LeftMostSmall;
        if first_lms && second_lms && i > 0 {
            return true
        } else if (first_lms != second_lms) || (input[i + j] != input[i + k]) {
            return false
        }
    }

    false
}

// Increment the counter at an index
pub fn insert<T>(vec: &mut BitsVec<usize>, value: T) -> usize
    where T: Num + NumCast + PartialOrd + Copy
{
    let idx = cast(value).unwrap();
    if vec.len() <= idx {
        vec.extend_with_element(idx + 1, 0);
    }

    let old = vec.get(idx);
    vec.set(idx, old + 1);
    old + 1
}

// Generates a suffix array and sorts them using the "induced sorting" method
// (Thanks to the python implementation in http://zork.net/~st/jottings/sais.html)
pub fn suffix_array<T>(input: &[T]) -> Vec<usize>  where T: Num + NumCast + PartialOrd + Copy {
    let mut type_map = BitsVec::with_elements(2, input.len() + 1, SuffixType::Small);
    // We'll be adding the frequencies, so input.len() would be the worst case
    // (i.e., same character throughout the string)
    let input_marker = input.len().next_power_of_two() - 1;
    let input_bits = input_marker.count_ones() as usize;
    let mut bucket_sizes = BitsVec::new(input_bits);      // byte frequency (HashMap will be a killer in recursions)

    type_map.set(input.len(), SuffixType::LeftMostSmall);      // null byte
    type_map.set(input.len() - 1, SuffixType::Large);          // should be L-type
    insert(&mut bucket_sizes, input[input.len() - 1]);

    // 1. Group the bytes into S-type or L-type (also mark LMS types)
    for i in (0..input.len() - 1).rev() {
        let prev_type = type_map.get(i + 1);
        insert(&mut bucket_sizes, input[i]);

        if input[i] > input[i + 1] ||
           (input[i] == input[i + 1] && prev_type == SuffixType::Large) {
            if prev_type == SuffixType::Small {
                type_map.set(i + 1, SuffixType::LeftMostSmall);
            }

            type_map.set(i, SuffixType::Large);
        }
    }

    let mut idx = 1;
    let mut bytes = bucket_sizes.iter().enumerate().filter_map(|(i, c)| {
        if c == 0 { None } else { Some(i) }
    }).collect::<Vec<_>>();
    bytes.sort();

    // BitsVec always requires the max number of bits it should hold. Using the size of `usize`
    // would probably render it useless (as it'd be no different from a vector). So, we get the
    // maximum value from our collection (say, MAX), get its size (MAX::bits) and pass it to BitsVec.
    // This way, we can reduce the memory consumed by more than half.
    let max_byte = bytes[bytes.len() - 1];
    let mut bucket_tails = BitsVec::with_elements(input_bits, max_byte + 1, 0);
    // (bits + 1) would be worst case, since we'll be incrementing the values again in `induced_sort_large`
    let mut bucket_heads = BitsVec::with_elements(input_bits + 1, max_byte + 1, 0);

    // 2. Fill the bucket heads and tails (heads for L-types and tails for S-types)
    let mut j = 0;
    for i in 0..(max_byte + 1) {
        bucket_heads.set(i, idx);
        if i == bytes[j] {
            idx += bucket_sizes.get(bytes[j]);
            j += 1;
        }

        bucket_tails.set(i, idx - 1);
    }

    drop(bytes);
    drop(bucket_sizes);

    // 3. Build the approximate SA for initial induced sorting
    let mut approx_sa = {
        let mut vec = vec![MARKER; input.len() + 1];
        let mut bucket_tails = bucket_tails.clone();
        for (i, byte) in input.iter().enumerate() {
            if type_map.get(i) != SuffixType::LeftMostSmall {
                continue        // ignore the L and S types (for now)
            }

            let bucket_idx = cast(*byte).unwrap();
            let bucket_value = bucket_tails.get(bucket_idx);
            vec[bucket_value] = i;
            bucket_tails.set(bucket_idx, bucket_value - 1);
        }

        vec[0] = input.len();       // null byte
        vec
    };

    // 4. Induced sort with respect to L & S types (using the buckets)
    induced_sort_large(&input, &mut approx_sa, bucket_heads.clone(), &type_map);
    induced_sort_small(&input, &mut approx_sa, bucket_tails.clone(), &type_map);

    // 5. Record the indices that share LMS substrings
    let mut label = 0;
    let lms_bytes = {
        // Approx SA is no longer needed (it'll be dropped when it goes out of scope)
        let mut approx_sa = approx_sa;
        let mut last_idx = approx_sa[0];
        let mut lms_vec = BitsVec::with_elements(input_bits, input.len() + 1, input.len());
        lms_vec.set(last_idx, 0);

        for count in approx_sa.drain(1..) {
            let idx = if count == MARKER { input.len() } else { count };
            if type_map.get(idx) != SuffixType::LeftMostSmall {
                continue
            }

            if !is_equal_lms(&input, &type_map, last_idx, idx) {
                label += 1;
            }

            last_idx = idx;
            lms_vec.set(idx, label);
        }

        lms_vec
    };

    // ... and filter the unnecessary bytes
    let lms_bits = (lms_bytes.len().next_power_of_two() - 1).count_ones() as usize;
    let mut summary_index = BitsVec::new(lms_bits);
    for (i, b) in lms_bytes.iter().enumerate() {
        if b != input.len() {
            summary_index.push(i);
        }
    }

    // 6. Build the final SA
    let mut final_sa = {
        let mut bucket_tails = bucket_tails.clone();
        let summary_sa = if label + 1 < summary_index.len() {
            // recursion (we don't have enough labels - multiple LMS substrings are same)
            let mapped = summary_index.iter().map(|i| lms_bytes.get(i)).collect::<Vec<_>>();
            drop(lms_bytes);
            suffix_array(&mapped)
        } else {
            let mut sum_sa = vec![0; summary_index.len() + 1];
            sum_sa[0] = summary_index.len();
            for (i, val) in summary_index.iter().enumerate() {
                let idx = lms_bytes.get(val);
                sum_sa[idx + 1] = i;
            }

            drop(lms_bytes);
            sum_sa      // recursion begins to unwind (peek of memory consumption)
        };

        let mut suffix_idx = vec![MARKER; input.len() + 1];
        for i in (2..summary_sa.len()).rev() {
            let idx = summary_index.get(summary_sa[i]);
            let bucket_idx = cast(input[idx]).unwrap();
            let bucket_value = bucket_tails.get(bucket_idx);
            suffix_idx[bucket_value] = idx;
            bucket_tails.set(bucket_idx, bucket_value - 1);
        }

        suffix_idx[0] = input.len();
        suffix_idx
    };

    // ... and sort it one last time
    induced_sort_large(&input, &mut final_sa, bucket_heads, &type_map);
    induced_sort_small(&input, &mut final_sa, bucket_tails, &type_map);

    final_sa
}

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

    #[test]
    fn test_suffix_array() {
        let text = b"ATCGAATCGAGAGATCATCGAATCGAGATCATCGAAATCATCGAATCGTC";
        let sa = suffix_array(text);

        let mut rotations = (0..text.len()).map(|i| &text[i..]).collect::<Vec<_>>();
        rotations.sort();

        assert_eq!(sa.into_iter().skip(1).map(|i| &text[i..]).collect::<Vec<_>>(),
                   rotations);
    }
}
<commit_msg>Advantage of switching to a vector: sorting not necessary<commit_after>use fillings::{BitsVec, ReprUsize};
use num_traits::{Num, NumCast, cast};

use std::mem;
use std::usize;

// Prefer this for marking, instead of Option<usize> (as it requires additional byte of memory)
const MARKER: usize = usize::MAX;

#[repr(usize)]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum SuffixType {
    Small,
    Large,
    LeftMostSmall,
}

impl ReprUsize for SuffixType {
    fn into_usize(self) -> usize { self as usize }
    fn from_usize(i: usize) -> SuffixType {
        unsafe { mem::transmute(i) }
    }
}

fn induced_sort_large<T>(input: &[T], approx_sa: &mut [usize],
                         mut bucket_heads: BitsVec<usize>, type_map: &BitsVec<SuffixType>)
    where T: Num + NumCast + PartialOrd + Copy
{
    for i in 0..approx_sa.len() {
        if approx_sa[i] == MARKER || approx_sa[i] == 0 {
            continue
        }

        let j = approx_sa[i] - 1;
        if type_map.get(j) != SuffixType::Large {
            continue    // only the L-types
        }

        let bucket_idx = cast(input[j]).unwrap();
        let bucket_value = bucket_heads.get(bucket_idx);
        approx_sa[bucket_value] = j;
        bucket_heads.set(bucket_idx, bucket_value + 1);
    }
}

fn induced_sort_small<T>(input: &[T], approx_sa: &mut [usize],
                         mut bucket_tails: BitsVec<usize>, type_map: &BitsVec<SuffixType>)
    where T: Num + NumCast + PartialOrd + Copy
{
    for i in (0..approx_sa.len()).rev() {
        if approx_sa[i] == MARKER || approx_sa[i] == 0 {
            continue
        }

        let j = approx_sa[i] - 1;
        if type_map.get(j) == SuffixType::Large {
            continue    // only the S-types (and LMS-types as per our grouping)
        }

        let bucket_idx = cast(input[j]).unwrap();
        let bucket_value = bucket_tails.get(bucket_idx);
        approx_sa[bucket_value] = j;
        bucket_tails.set(bucket_idx, bucket_value - 1);
    }
}

// Check whether the string between two LMS bytes have the same lengths and same contents
fn is_equal_lms<T>(input: &[T], type_map: &BitsVec<SuffixType>, j: usize, k: usize) -> bool
    where T: Num + NumCast + PartialOrd + Copy
{
    if j == input.len() || k == input.len() {
        return false    // null byte
    }

    for i in 0..(input.len() + 1) {
        let first_lms = type_map.get(i + j) == SuffixType::LeftMostSmall;
        let second_lms = type_map.get(i + k) == SuffixType::LeftMostSmall;
        if first_lms && second_lms && i > 0 {
            return true
        } else if (first_lms != second_lms) || (input[i + j] != input[i + k]) {
            return false
        }
    }

    false
}

// Increment the counter at an index
pub fn insert<T>(vec: &mut BitsVec<usize>, value: T) -> usize
    where T: Num + NumCast + PartialOrd + Copy
{
    let idx = cast(value).unwrap();
    if vec.len() <= idx {
        vec.extend_with_element(idx + 1, 0);
    }

    let old = vec.get(idx);
    vec.set(idx, old + 1);
    old + 1
}

// Generates a suffix array and sorts them using the "induced sorting" method
// (Thanks to the python implementation in http://zork.net/~st/jottings/sais.html)
pub fn suffix_array<T>(input: &[T]) -> Vec<usize>  where T: Num + NumCast + PartialOrd + Copy {
    let mut type_map = BitsVec::with_elements(2, input.len() + 1, SuffixType::Small);
    // We'll be adding the frequencies, so input.len() would be the worst case
    // (i.e., same character throughout the string)
    let input_marker = input.len().next_power_of_two() - 1;
    let input_bits = input_marker.count_ones() as usize;
    let mut bucket_sizes = BitsVec::new(input_bits);      // byte frequency (HashMap will be a killer in recursions)

    type_map.set(input.len(), SuffixType::LeftMostSmall);      // null byte
    type_map.set(input.len() - 1, SuffixType::Large);          // should be L-type
    insert(&mut bucket_sizes, input[input.len() - 1]);

    // 1. Group the bytes into S-type or L-type (also mark LMS types)
    for i in (0..input.len() - 1).rev() {
        let prev_type = type_map.get(i + 1);
        insert(&mut bucket_sizes, input[i]);

        if input[i] > input[i + 1] ||
           (input[i] == input[i + 1] && prev_type == SuffixType::Large) {
            if prev_type == SuffixType::Small {
                type_map.set(i + 1, SuffixType::LeftMostSmall);
            }

            type_map.set(i, SuffixType::Large);
        }
    }

    let mut idx = 1;
    let bytes = bucket_sizes.iter().enumerate().filter_map(|(i, c)| {
        if c == 0 { None } else { Some(i) }
    }).collect::<Vec<_>>();

    // BitsVec always requires the max number of bits it should hold. Using the size of `usize`
    // would probably render it useless (as it'd be no different from a vector). So, we get the
    // maximum value from our collection (say, MAX), get its size (MAX::bits) and pass it to BitsVec.
    // This way, we can reduce the memory consumed by more than half.
    let max_byte = bytes[bytes.len() - 1];
    let mut bucket_tails = BitsVec::with_elements(input_bits, max_byte + 1, 0);
    // (bits + 1) would be worst case, since we'll be incrementing the values again in `induced_sort_large`
    let mut bucket_heads = BitsVec::with_elements(input_bits + 1, max_byte + 1, 0);

    // 2. Fill the bucket heads and tails (heads for L-types and tails for S-types)
    let mut j = 0;
    for i in 0..(max_byte + 1) {
        bucket_heads.set(i, idx);
        if i == bytes[j] {
            idx += bucket_sizes.get(bytes[j]);
            j += 1;
        }

        bucket_tails.set(i, idx - 1);
    }

    drop(bytes);
    drop(bucket_sizes);

    // 3. Build the approximate SA for initial induced sorting
    let mut approx_sa = {
        let mut vec = vec![MARKER; input.len() + 1];
        let mut bucket_tails = bucket_tails.clone();
        for (i, byte) in input.iter().enumerate() {
            if type_map.get(i) != SuffixType::LeftMostSmall {
                continue        // ignore the L and S types (for now)
            }

            let bucket_idx = cast(*byte).unwrap();
            let bucket_value = bucket_tails.get(bucket_idx);
            vec[bucket_value] = i;
            bucket_tails.set(bucket_idx, bucket_value - 1);
        }

        vec[0] = input.len();       // null byte
        vec
    };

    // 4. Induced sort with respect to L & S types (using the buckets)
    induced_sort_large(&input, &mut approx_sa, bucket_heads.clone(), &type_map);
    induced_sort_small(&input, &mut approx_sa, bucket_tails.clone(), &type_map);

    // 5. Record the indices that share LMS substrings
    let mut label = 0;
    let lms_bytes = {
        // Approx SA is no longer needed (it'll be dropped when it goes out of scope)
        let mut approx_sa = approx_sa;
        let mut last_idx = approx_sa[0];
        let mut lms_vec = BitsVec::with_elements(input_bits, input.len() + 1, input.len());
        lms_vec.set(last_idx, 0);

        for count in approx_sa.drain(1..) {
            let idx = if count == MARKER { input.len() } else { count };
            if type_map.get(idx) != SuffixType::LeftMostSmall {
                continue
            }

            if !is_equal_lms(&input, &type_map, last_idx, idx) {
                label += 1;
            }

            last_idx = idx;
            lms_vec.set(idx, label);
        }

        lms_vec
    };

    // ... and filter the unnecessary bytes
    let lms_bits = (lms_bytes.len().next_power_of_two() - 1).count_ones() as usize;
    let mut summary_index = BitsVec::new(lms_bits);
    for (i, b) in lms_bytes.iter().enumerate() {
        if b != input.len() {
            summary_index.push(i);
        }
    }

    // 6. Build the final SA
    let mut final_sa = {
        let mut bucket_tails = bucket_tails.clone();
        let summary_sa = if label + 1 < summary_index.len() {
            // recursion (we don't have enough labels - multiple LMS substrings are same)
            let mapped = summary_index.iter().map(|i| lms_bytes.get(i)).collect::<Vec<_>>();
            drop(lms_bytes);
            suffix_array(&mapped)
        } else {
            let mut sum_sa = vec![0; summary_index.len() + 1];
            sum_sa[0] = summary_index.len();
            for (i, val) in summary_index.iter().enumerate() {
                let idx = lms_bytes.get(val);
                sum_sa[idx + 1] = i;
            }

            drop(lms_bytes);
            sum_sa      // recursion begins to unwind (peek of memory consumption)
        };

        let mut suffix_idx = vec![MARKER; input.len() + 1];
        for i in (2..summary_sa.len()).rev() {
            let idx = summary_index.get(summary_sa[i]);
            let bucket_idx = cast(input[idx]).unwrap();
            let bucket_value = bucket_tails.get(bucket_idx);
            suffix_idx[bucket_value] = idx;
            bucket_tails.set(bucket_idx, bucket_value - 1);
        }

        suffix_idx[0] = input.len();
        suffix_idx
    };

    // ... and sort it one last time
    induced_sort_large(&input, &mut final_sa, bucket_heads, &type_map);
    induced_sort_small(&input, &mut final_sa, bucket_tails, &type_map);

    final_sa
}

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

    #[test]
    fn test_suffix_array() {
        let text = b"ATCGAATCGAGAGATCATCGAATCGAGATCATCGAAATCATCGAATCGTC";
        let sa = suffix_array(text);

        let mut rotations = (0..text.len()).map(|i| &text[i..]).collect::<Vec<_>>();
        rotations.sort();

        assert_eq!(sa.into_iter().skip(1).map(|i| &text[i..]).collect::<Vec<_>>(),
                   rotations);
    }
}
<|endoftext|>


<commit_before>enum List<T> {
    Cons(T, ~List<T>),
    Nil
}

fn last<'a, T>(list: &'a List<T>) -> Option<&'a T> {
    match *list {
        Nil => None,
        Cons(ref elem, ~Nil) => Some(elem),
        Cons(_, ~ref rest) => last(rest)
    }
}

fn main() {
    let list: List<char> = Cons('a', ~Cons('b', ~Cons('c', ~Nil)));
    println!("{:?}", last(&list));

    let list: List<uint> = Cons(6, ~Cons(7, ~Cons(42, ~Nil)));
    println!("{:?}", last(&list));

    let list: List<~str> = Cons(~"six", ~Cons(~"seven", ~Cons(~"forty-two", ~Nil)));
    println!("{:?}", last(&list));
}
<commit_msg>Redo Problem 01 with vectors<commit_after>fn main() {
    let list: ~[char] = ~['a', 'b', 'c'];
    println!("{:?}", list.last());
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(all(unix, not(target_os = "ios")))]
mod imp {
    extern crate libc;

    use self::OsRngInner::*;

    use io::{IoResult, File};
    use path::Path;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use result::Result::{Ok, Err};
    use slice::SliceExt;
    use mem;
    use os::errno;

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm")))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        extern "C" {
            fn syscall(number: libc::c_long, ...) -> libc::c_long;
        }

        #[cfg(target_arch = "x86_64")]
        const NR_GETRANDOM: libc::c_long = 318;
        #[cfg(target_arch = "x86")]
        const NR_GETRANDOM: libc::c_long = 355;
        #[cfg(target_arch = "arm")]
        const NR_GETRANDOM: libc::c_long = 384;

        unsafe {
            syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0u)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm"))))]
    fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }

    fn getrandom_fill_bytes(v: &mut [u8]) {
        let mut read = 0;
        let len = v.len();
        while read < len {
            let result = getrandom(v.slice_from_mut(read));
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as uint;
            }
        }
    }

    fn getrandom_next_u32() -> u32 {
        let mut buf: [u8; 4] = [0u8; 4];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8; 4], u32>(buf) }
    }

    fn getrandom_next_u64() -> u64 {
        let mut buf: [u8; 8] = [0u8; 8];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8; 8], u64>(buf) }
    }

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm")))]
    fn is_getrandom_available() -> bool {
        use sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Relaxed};

        static GETRANDOM_CHECKED: AtomicBool = ATOMIC_BOOL_INIT;
        static GETRANDOM_AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT;

        if !GETRANDOM_CHECKED.load(Relaxed) {
            let mut buf: [u8; 0] = [];
            let result = getrandom(&mut buf);
            let available = if result == -1 {
                let err = errno() as libc::c_int;
                err != libc::ENOSYS
            } else {
                true
            };
            GETRANDOM_AVAILABLE.store(available, Relaxed);
            GETRANDOM_CHECKED.store(true, Relaxed);
            available
        } else {
            GETRANDOM_AVAILABLE.load(Relaxed)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm"))))]
    fn is_getrandom_available() -> bool { false }

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        inner: OsRngInner,
    }

    enum OsRngInner {
        OsGetrandomRng,
        OsReaderRng(ReaderRng<File>),
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            if is_getrandom_available() {
                return Ok(OsRng { inner: OsGetrandomRng });
            }

            let reader = try!(File::open(&Path::new("/dev/urandom")));
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: OsReaderRng(reader_rng) })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u32(),
                OsReaderRng(ref mut rng) => rng.next_u32(),
            }
        }
        fn next_u64(&mut self) -> u64 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u64(),
                OsReaderRng(ref mut rng) => rng.next_u64(),
            }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            match self.inner {
                OsGetrandomRng => getrandom_fill_bytes(v),
                OsReaderRng(ref mut rng) => rng.fill_bytes(v)
            }
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    extern crate libc;

    use io::{IoResult};
    use kinds::Sync;
    use mem;
    use os;
    use rand::Rng;
    use result::Result::{Ok};
    use self::libc::{c_int, size_t};
    use slice::SliceExt;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    #[allow(missing_copy_implementations)]
    pub struct OsRng {
        // dummy field to ensure that this struct cannot be constructed outside of this module
        _dummy: (),
    }

    #[repr(C)]
    struct SecRandom;

    unsafe impl Sync for *const SecRandom {}

    #[allow(non_upper_case_globals)]
    static kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;

    #[link(name = "Security", kind = "framework")]
    extern "C" {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t, bytes: *mut u8) -> c_int;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            Ok(OsRng { _dummy: () })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8; 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
            };
            if ret == -1 {
                panic!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    extern crate libc;

    use io::{IoResult, IoError};
    use mem;
    use ops::Drop;
    use os;
    use rand::Rng;
    use result::Result::{Ok, Err};
    use self::libc::{DWORD, BYTE, LPCSTR, BOOL};
    use self::libc::types::os::arch::extra::{LONG_PTR};
    use slice::SliceExt;

    type HCRYPTPROV = LONG_PTR;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    static PROV_RSA_FULL: DWORD = 1;
    static CRYPT_SILENT: DWORD = 64;
    static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;

    #[allow(non_snake_case)]
    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let mut hcp = 0;
            let ret = unsafe {
                CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };

            if ret == 0 {
                Err(IoError::last_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8; 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                panic!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                panic!("couldn't release context: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(test)]
mod test {
    use prelude::v1::*;

    use sync::mpsc::channel;
    use rand::Rng;
    use super::OsRng;
    use thread::Thread;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8; 1000];
        r.fill_bytes(&mut v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in range(0u, 20) {
            let (tx, rx) = channel();
            txs.push(tx);

            Thread::spawn(move|| {
                // wait until all the tasks are ready to go.
                rx.recv().unwrap();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                Thread::yield_now();
                let mut v = [0u8; 1000];

                for _ in range(0u, 100) {
                    r.next_u32();
                    Thread::yield_now();
                    r.next_u64();
                    Thread::yield_now();
                    r.fill_bytes(&mut v);
                    Thread::yield_now();
                }
            }).detach();
        }

        // start all the tasks
        for tx in txs.iter() {
            tx.send(()).unwrap();
        }
    }
}
<commit_msg>Initial version of AArch64 support.<commit_after>// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(all(unix, not(target_os = "ios")))]
mod imp {
    extern crate libc;

    use self::OsRngInner::*;

    use io::{IoResult, File};
    use path::Path;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use result::Result::{Ok, Err};
    use slice::SliceExt;
    use mem;
    use os::errno;

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64",
                  target_arch = "x86",
                  target_arch = "arm",
                  target_arch = "aarch64")))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        extern "C" {
            fn syscall(number: libc::c_long, ...) -> libc::c_long;
        }

        #[cfg(target_arch = "x86_64")]
        const NR_GETRANDOM: libc::c_long = 318;
        #[cfg(target_arch = "x86")]
        const NR_GETRANDOM: libc::c_long = 355;
        #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
        const NR_GETRANDOM: libc::c_long = 384;

        unsafe {
            syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0u)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64",
                      target_arch = "x86",
                      target_arch = "arm",
                      target_arch = "aarch64"))))]
    fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }

    fn getrandom_fill_bytes(v: &mut [u8]) {
        let mut read = 0;
        let len = v.len();
        while read < len {
            let result = getrandom(v.slice_from_mut(read));
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as uint;
            }
        }
    }

    fn getrandom_next_u32() -> u32 {
        let mut buf: [u8; 4] = [0u8; 4];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8; 4], u32>(buf) }
    }

    fn getrandom_next_u64() -> u64 {
        let mut buf: [u8; 8] = [0u8; 8];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8; 8], u64>(buf) }
    }

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64",
                  target_arch = "x86",
                  target_arch = "arm",
                  target_arch = "aarch64")))]
    fn is_getrandom_available() -> bool {
        use sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Relaxed};

        static GETRANDOM_CHECKED: AtomicBool = ATOMIC_BOOL_INIT;
        static GETRANDOM_AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT;

        if !GETRANDOM_CHECKED.load(Relaxed) {
            let mut buf: [u8; 0] = [];
            let result = getrandom(&mut buf);
            let available = if result == -1 {
                let err = errno() as libc::c_int;
                err != libc::ENOSYS
            } else {
                true
            };
            GETRANDOM_AVAILABLE.store(available, Relaxed);
            GETRANDOM_CHECKED.store(true, Relaxed);
            available
        } else {
            GETRANDOM_AVAILABLE.load(Relaxed)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64",
                      target_arch = "x86",
                      target_arch = "arm",
                      target_arch = "aarch64"))))]
    fn is_getrandom_available() -> bool { false }

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        inner: OsRngInner,
    }

    enum OsRngInner {
        OsGetrandomRng,
        OsReaderRng(ReaderRng<File>),
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            if is_getrandom_available() {
                return Ok(OsRng { inner: OsGetrandomRng });
            }

            let reader = try!(File::open(&Path::new("/dev/urandom")));
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: OsReaderRng(reader_rng) })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u32(),
                OsReaderRng(ref mut rng) => rng.next_u32(),
            }
        }
        fn next_u64(&mut self) -> u64 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u64(),
                OsReaderRng(ref mut rng) => rng.next_u64(),
            }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            match self.inner {
                OsGetrandomRng => getrandom_fill_bytes(v),
                OsReaderRng(ref mut rng) => rng.fill_bytes(v)
            }
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    extern crate libc;

    use io::{IoResult};
    use kinds::Sync;
    use mem;
    use os;
    use rand::Rng;
    use result::Result::{Ok};
    use self::libc::{c_int, size_t};
    use slice::SliceExt;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    #[allow(missing_copy_implementations)]
    pub struct OsRng {
        // dummy field to ensure that this struct cannot be constructed outside of this module
        _dummy: (),
    }

    #[repr(C)]
    struct SecRandom;

    unsafe impl Sync for *const SecRandom {}

    #[allow(non_upper_case_globals)]
    static kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;

    #[link(name = "Security", kind = "framework")]
    extern "C" {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t, bytes: *mut u8) -> c_int;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            Ok(OsRng { _dummy: () })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8; 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
            };
            if ret == -1 {
                panic!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    extern crate libc;

    use io::{IoResult, IoError};
    use mem;
    use ops::Drop;
    use os;
    use rand::Rng;
    use result::Result::{Ok, Err};
    use self::libc::{DWORD, BYTE, LPCSTR, BOOL};
    use self::libc::types::os::arch::extra::{LONG_PTR};
    use slice::SliceExt;

    type HCRYPTPROV = LONG_PTR;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    static PROV_RSA_FULL: DWORD = 1;
    static CRYPT_SILENT: DWORD = 64;
    static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;

    #[allow(non_snake_case)]
    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let mut hcp = 0;
            let ret = unsafe {
                CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };

            if ret == 0 {
                Err(IoError::last_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8; 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                panic!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                panic!("couldn't release context: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(test)]
mod test {
    use prelude::v1::*;

    use sync::mpsc::channel;
    use rand::Rng;
    use super::OsRng;
    use thread::Thread;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8; 1000];
        r.fill_bytes(&mut v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in range(0u, 20) {
            let (tx, rx) = channel();
            txs.push(tx);

            Thread::spawn(move|| {
                // wait until all the tasks are ready to go.
                rx.recv().unwrap();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                Thread::yield_now();
                let mut v = [0u8; 1000];

                for _ in range(0u, 100) {
                    r.next_u32();
                    Thread::yield_now();
                    r.next_u64();
                    Thread::yield_now();
                    r.fill_bytes(&mut v);
                    Thread::yield_now();
                }
            }).detach();
        }

        // start all the tasks
        for tx in txs.iter() {
            tx.send(()).unwrap();
        }
    }
}
<|endoftext|>


<commit_before>extern mod std;
extern mod cql_client;

fn main() {
    let res = cql_client::connect(~"127.0.0.1", 9042, None);
    if res.is_err() {
        io::println(fmt!("%?", res.get_err()));
        return;
    }

    let client = res.get();

    let res = client.query(~"create keyspace test with replication = {'CLASS': 'SimpleStrategy', 'replication_factor':1}", cql_client::ConsistencyOne);
    io::println(fmt!("%?", res));

    let res = client.query(~"select id, email from test.test", cql_client::ConsistencyOne);
    let msg = match copy res.body {
        cql_client::ResponseEmpty() => ~"empty",
        cql_client::ResultRows(rows) => ~"rows",
        _ => ~"etc",
    };

    io::println(fmt!("%?", msg));

    io::println(fmt!("%?", res));
}
<commit_msg>add create table query<commit_after>extern mod std;
extern mod cql_client;

fn main() {
    let res = cql_client::connect(~"127.0.0.1", 9042, None);
    if res.is_err() {
        io::println(fmt!("%?", res.get_err()));
        return;
    }

    let client = res.get();

    let res = client.query(~"create keyspace test with replication = {'CLASS': 'SimpleStrategy', 'replication_factor':1}", cql_client::ConsistencyOne);
    io::println(fmt!("%?", res));
    let res = client.query(~"create table test.test (id text primary key, pw text)", cql_client::ConsistencyOne);
    io::println(fmt!("%?", res));

    let res = client.query(~"select * from test.test", cql_client::ConsistencyOne);
    let msg = match copy res.body {
        cql_client::ResponseEmpty() => ~"empty",
        cql_client::ResultRows(rows) => ~"rows",
        _ => ~"etc",
    };

    io::println(fmt!("%?", msg));

    io::println(fmt!("%?", res));
}
<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[crate_id = "github.com/mozilla-servo/sharegl#0.1"];

extern crate std;
extern crate sync;
extern crate geom;

#[cfg(target_os="macos")]
extern crate core_foundation;
#[cfg(target_os="macos")]
extern crate io_surface;
#[cfg(target_os="macos")]
extern crate opengles;

pub mod base;
pub mod context;

#[cfg(target_os="macos")]
#[path="platform/macos.rs"]
pub mod platform;

#[cfg(target_os="linux")]
#[path="platform/linux.rs"]
pub mod platform;

#[cfg(target_os="windows")]
#[cfg(target_os="android")]
#[path="platform/dummy.rs"]
pub mod platform;
<commit_msg>Update to current rust: import the logging macros.<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[crate_id = "github.com/mozilla-servo/sharegl#0.1"];

#[feature(phase)];
#[phase(syntax, link)] extern crate log;

extern crate std;
extern crate sync;
extern crate geom;

#[cfg(target_os="macos")]
extern crate core_foundation;
#[cfg(target_os="macos")]
extern crate io_surface;
#[cfg(target_os="macos")]
extern crate opengles;

pub mod base;
pub mod context;

#[cfg(target_os="macos")]
#[path="platform/macos.rs"]
pub mod platform;

#[cfg(target_os="linux")]
#[path="platform/linux.rs"]
pub mod platform;

#[cfg(target_os="windows")]
#[cfg(target_os="android")]
#[path="platform/dummy.rs"]
pub mod platform;
<|endoftext|>