<commit_before>use operand::Operand;
use memory::Memory;
use super::{OpcodeInstance, Size};

fn encode_ea(op: &Operand) -> u16 {
    (match *op {
        Operand::DataRegisterDirect(reg_y) => 0b000000 | reg_y,
        Operand::AddressRegisterDirect(reg_y) => 0b001000 | reg_y,
        Operand::AddressRegisterIndirect(reg_y) => 0b010000 | reg_y,
        Operand::AddressRegisterIndirectWithPostincrement(reg_y) => 0b011000 | reg_y,
        Operand::AddressRegisterIndirectWithPredecrement(reg_y) => 0b100000 | reg_y,
        Operand::AddressRegisterIndirectWithDisplacement(reg_y, _) => 0b101000 | reg_y,
        Operand::AddressRegisterIndirectWithIndex(reg_y, _, _) => 0b110000 | reg_y,
        Operand::AbsoluteWord(_) => 0b111000,
        Operand::AbsoluteLong(_) => 0b111001,
        Operand::PcWithDisplacement(_) => 0b111010,
        Operand::PcWithIndex(_, _) => 0b111011,
        Operand::Immediate(_, _) => 0b111100,
    }) as u16
}

fn encode_dx(op: &Operand) -> u16 {
    match *op {
        Operand::DataRegisterDirect(reg_x) => (reg_x as u16) << 9,
        _ => panic!("not dx-encodable: {:?}", *op)
    }
}

fn encode_ax(op: &Operand) -> u16 {
    match *op {
        Operand::AddressRegisterDirect(reg_x) => (reg_x as u16) << 9,
        _ => panic!("not ax-encodable: {:?}", *op)
    }
}

fn assert_no_overlap(op: &OpcodeInstance, template: u16, ea: u16, xreg: u16) {
    assert!(template & ea | template & xreg | ea & xreg == 0, "template {:016b}, ea {:06b}, xreg {:012b} overlaps for {}", template, ea, xreg, op);
}

pub fn encode_ea_dx(op: &OpcodeInstance, template: u16, pc: u32, mem: &mut Memory) -> u32 {
    let ea = encode_ea(&op.operands[0]);
    let dx = encode_dx(&op.operands[1]);
    assert_no_overlap(&op, template, ea, dx);
    mem.write_word(pc, template | ea | dx);
    op.operands[0].add_extension_words(pc + 2, mem)
}

pub fn encode_ea_ax(op: &OpcodeInstance, template: u16, pc: u32, mem: &mut Memory) -> u32 {
    let ea = encode_ea(&op.operands[0]);
    let ax = encode_ax(&op.operands[1]);
    assert_no_overlap(&op, template, ea, ax);
    mem.write_word(pc, template | ea | ax);
    op.operands[0].add_extension_words(pc + 2, mem)
}

pub fn encode_dx_ea(op: &OpcodeInstance, template: u16, pc: u32, mem: &mut Memory) -> u32 {
    let ea = encode_ea(&op.operands[1]);
    let dx = encode_dx(&op.operands[0]);
    assert_no_overlap(&op, template, ea, dx);
    mem.write_word(pc, template | ea | dx);
    op.operands[1].add_extension_words(pc + 2, mem)
}

pub fn encode_imm_ea(op: &OpcodeInstance, template: u16, pc: u32, mem: &mut Memory) -> u32 {
    let ea = encode_ea(&op.operands[1]);
    assert_no_overlap(&op, template, ea, 0);
    let pc = mem.write_word(pc, template | ea);
    let pc = op.operands[0].add_extension_words(pc, mem);
    op.operands[1].add_extension_words(pc, mem)
}
#[allow(unused_variables)]
pub fn nop_encoder(op: &OpcodeInstance, template: u16, pc: u32, mem: &mut Memory) -> u32 {
    pc
}
#[allow(unused_variables)]
pub fn nop_selector(op: &OpcodeInstance) -> bool {
    false
}
pub fn is_ea_ax(op: &OpcodeInstance) -> bool {
    if op.operands.len() != 2 { return false };
    match op.operands[1] {
        Operand::AddressRegisterDirect(_) => true,
        _ => false,
    }
}
pub fn is_ea_dx(op: &OpcodeInstance) -> bool {
    if op.operands.len() != 2 { return false };
    match op.operands[1] {
        Operand::DataRegisterDirect(_) => true,
        _ => false,
    }
}
pub fn is_dx_ea(op: &OpcodeInstance) -> bool {
    if op.operands.len() != 2 { return false };
    match op.operands[1] {
        Operand::DataRegisterDirect(_) => false,
        _ => true,
    }
}
pub fn is_imm_ea(op: &OpcodeInstance) -> bool {
    if op.operands.len() != 2 { return false };
    match op.operands[0] {
        Operand::Immediate(_, _) => true,
        _ => false,
    }
}
pub fn encode_instruction(instruction: &str, op_inst: &OpcodeInstance, pc: u32, mem: &mut Memory) -> u32
{
    let optable = super::generate();
    for op in optable {
        if op_inst.mnemonic == op.mnemonic && op_inst.size == op.size && (op.selector)(op_inst) {
            let encoder = op.encoder;
            return encoder(op_inst, op.matching as u16, pc, mem);
        }
    }
    panic!("Could not assemble {} ({})", instruction, op_inst);
}

use regex::RegexSet;
use regex::Regex;
pub struct Assembler {
    instruction_re: Regex,
    drd: Regex,
    ard: Regex,
    ari: Regex,
    api: Regex,
    apd: Regex,
    adi: Regex,
    aix: Regex,
    hex: Regex,
    lng: Regex,
    pcd: Regex,
    pci: Regex,
    imm: Regex,
    modes: RegexSet,
}

impl Assembler {
    pub fn new() -> Assembler {
        let drd = Regex::new(r"^D([0-7])$").unwrap();
        let ard = Regex::new(r"^A([0-7])$").unwrap();
        let ari = Regex::new(r"^\(A([0-7])\)$").unwrap();
        let api = Regex::new(r"^\(A([0-7])\)\+$").unwrap();
        let apd = Regex::new(r"^-\(A([0-7])\)$").unwrap();
        let adi = Regex::new(r"^(-?\d+)\(A([0-7])\)$",).unwrap();
        let aix = Regex::new(r"^(-?\d+)\(A([0-7]),([DA])([0-7])\)$").unwrap();
        let hex = Regex::new(r"^\$([\dA-F]+)$").unwrap();
        let lng = Regex::new(r"^\$([\dA-F]+)\.L$").unwrap();
        let pcd = Regex::new(r"^(-?\d+)\(PC\)$").unwrap();
        let pci = Regex::new(r"^(-?\d+)\(PC,([DA])([0-7])\)$").unwrap();
        let imm = Regex::new(r"^#\$([\dA-F]+)$").unwrap();

        Assembler { instruction_re: Regex::new(r"^(\w+)(\.\w)?(\s+(\w\d|-?\$?[\dA-F]*\([\w,0-9]+\)\+?|#?\$?[\dA-F]+(?:\.\w)?)(,(\w\d|-?\$?[\dA-F]*\([\w,0-9]+\)\+?|#?-?\$?[\dA-F]+(?:\.\w)?))?)$").unwrap(),
            modes: RegexSet::new(&[
        drd.as_str(),
        ard.as_str(),
        ari.as_str(),
        api.as_str(),
        apd.as_str(),
        adi.as_str(),
        aix.as_str(),
        hex.as_str(),
        lng.as_str(),
        pcd.as_str(),
        pci.as_str(),
        imm.as_str(),
    ]).unwrap(),
            drd: drd,
            ard: ard,
            ari: ari,
            api: api,
            apd: apd,
            adi: adi,
            aix: aix,
            hex: hex,
            lng: lng,
            pcd: pcd,
            pci: pci,
            imm: imm,
        }
    }

    pub fn parse_assembler<'a>(&'a self, instruction: &'a str) -> OpcodeInstance {
        let im = self.instruction_re.captures(instruction);
        if im.is_none() {
            panic!("Syntax Error: {:?} does not match instruction pattern {:?}", instruction, self.instruction_re);
        }
        let imatch = im.unwrap();
        let (ins, size, op1, op2) = (imatch.at(1).unwrap_or(""), imatch.at(2).unwrap_or(""), imatch.at(4).unwrap_or(""), imatch.at(6).unwrap_or(""));
        let size = match size {
            ".B" => Size::Byte,
            ".W" => Size::Word,
            ".L" => Size::Long,
            _ => Size::Unsized,
        };

        let mode1 = self.modes.matches(op1).into_iter().nth(0);
        let mode2 = self.modes.matches(op2).into_iter().nth(0);
        let get_chr = |rx: &Regex, op: &str, at: usize| rx.captures(op).unwrap().at(at).unwrap().chars().next().unwrap();
        let get_num = |rx: &Regex, op: &str, at: usize|->i32 { rx.captures(op).unwrap().at(at).unwrap().parse().unwrap() };
        let get_hex = |rx: &Regex, op: &str, at: usize|->u32 { u32::from_str_radix(rx.captures(op).unwrap().at(at).unwrap(), 16).unwrap() };
        let to_op = |opinfo:(Option<usize>, &str)| {
            let (v, op) = opinfo;
            match v {
                None => if !op.is_empty() { panic!("operand {:?} couldn't be matched", op)} else { None },
                Some(0) => Some(Operand::DataRegisterDirect(get_num(&self.drd, op, 1) as u8)),
                Some(1) => Some(Operand::AddressRegisterDirect(get_num(&self.ard, op, 1) as u8)),
                Some(2) => Some(Operand::AddressRegisterIndirect(get_num(&self.ari, op, 1) as u8)),
                Some(3) => Some(Operand::AddressRegisterIndirectWithPostincrement(get_num(&self.api, op, 1) as u8)),
                Some(4) => Some(Operand::AddressRegisterIndirectWithPredecrement(get_num(&self.apd, op, 1) as u8)),
                Some(5) => Some(Operand::AddressRegisterIndirectWithDisplacement(get_num(&self.adi, op, 2) as u8, get_num(&self.adi, op, 1) as i16)),
                Some(6) => {
                    let offset = if get_chr(&self.aix, op, 3) == 'D' {
                        0
                    } else {
                        8
                    };
                    let i_reg = offset + get_num(&self.aix, op, 4) as u8;
                    Some(Operand::AddressRegisterIndirectWithIndex(get_num(&self.aix, op, 2) as u8, i_reg, get_num(&self.aix, op, 1) as i8))
                },
                Some(7) => {
                    let hex: u32 = get_hex(&self.hex, op, 1);
                    if hex > 0x7FFF {
                        Some(Operand::AbsoluteLong(hex))
                    } else {
                        Some(Operand::AbsoluteWord(hex as u16))
                    }
                },
                Some(8) => Some(Operand::AbsoluteLong(get_hex(&self.lng, op, 1))),
                Some(9) => Some(Operand::PcWithDisplacement(get_num(&self.pcd, op, 1) as i16)),
                Some(10) => {
                    let offset = if get_chr(&self.pci, op, 2) == 'D' {
                        0
                    } else {
                        8
                    };
                    let i_reg = offset + get_num(&self.pci, op, 3) as u8;
                    Some(Operand::PcWithIndex(i_reg, get_num(&self.pci, op, 1) as i8))
                },
                Some(11) => Some(Operand::Immediate(size, get_hex(&self.imm, op, 1) as u32)),
                // TODO: Handle the remaining addressing modes
                _ => panic!("Operand syntax error {:?} {:?}", v, op)
            }
        };
        OpcodeInstance {mnemonic: ins, size: size, operands: vec![(mode1, op1), (mode2, op2)].into_iter().filter_map(to_op).collect::<Vec<_>>()}
    }
}

#[cfg(test)]
mod tests {
    use operand::Operand;
    use memory::{MemoryVec, Memory};
    use super::{Assembler, encode_instruction};
    use super::super::Size;

    #[test]
    fn encodes_add_8_er() {
        let asm = "ADD.B\t(A1),D2";
        let a = Assembler::new();
        let inst = a.parse_assembler(asm);
        assert_eq!("ADD", inst.mnemonic);
        assert_eq!(Size::Byte, inst.size);
        assert_eq!(Operand::AddressRegisterIndirect(1), inst.operands[0]);
        assert_eq!(Operand::DataRegisterDirect(2), inst.operands[1]);
        let mut mem = &mut MemoryVec::new();
        let pc = 0;
        let new_pc = encode_instruction(asm, &inst, pc, mem);
        assert_eq!(2, new_pc);
        assert_eq!(0xd411, mem.read_word(pc));
    }
    #[test]
    fn encodes_add_8_re() {
        let asm = "ADD.B\tD2,(A1)";
        let a = Assembler::new();
        let inst = a.parse_assembler(asm);
        assert_eq!("ADD", inst.mnemonic);
        assert_eq!(Size::Byte, inst.size);
        assert_eq!(Operand::DataRegisterDirect(2), inst.operands[0]);
        assert_eq!(Operand::AddressRegisterIndirect(1), inst.operands[1]);
        let mut mem = &mut MemoryVec::new();
        let pc = 0;
        let new_pc = encode_instruction(asm, &inst, pc, mem);
        assert_eq!(2, new_pc);
        assert_eq!(0xd511, mem.read_word(pc));
    }

}<commit_msg>Add initial multiline assembler<commit_after>use operand::Operand;
use memory::{Memory, MemoryVec};
use super::{OpcodeInstance, Size};

fn encode_ea(op: &Operand) -> u16 {
    (match *op {
        Operand::DataRegisterDirect(reg_y) => 0b000000 | reg_y,
        Operand::AddressRegisterDirect(reg_y) => 0b001000 | reg_y,
        Operand::AddressRegisterIndirect(reg_y) => 0b010000 | reg_y,
        Operand::AddressRegisterIndirectWithPostincrement(reg_y) => 0b011000 | reg_y,
        Operand::AddressRegisterIndirectWithPredecrement(reg_y) => 0b100000 | reg_y,
        Operand::AddressRegisterIndirectWithDisplacement(reg_y, _) => 0b101000 | reg_y,
        Operand::AddressRegisterIndirectWithIndex(reg_y, _, _) => 0b110000 | reg_y,
        Operand::AbsoluteWord(_) => 0b111000,
        Operand::AbsoluteLong(_) => 0b111001,
        Operand::PcWithDisplacement(_) => 0b111010,
        Operand::PcWithIndex(_, _) => 0b111011,
        Operand::Immediate(_, _) => 0b111100,
    }) as u16
}

fn encode_dx(op: &Operand) -> u16 {
    match *op {
        Operand::DataRegisterDirect(reg_x) => (reg_x as u16) << 9,
        _ => panic!("not dx-encodable: {:?}", *op)
    }
}

fn encode_ax(op: &Operand) -> u16 {
    match *op {
        Operand::AddressRegisterDirect(reg_x) => (reg_x as u16) << 9,
        _ => panic!("not ax-encodable: {:?}", *op)
    }
}

fn assert_no_overlap(op: &OpcodeInstance, template: u16, ea: u16, xreg: u16) {
    assert!(template & ea | template & xreg | ea & xreg == 0, "template {:016b}, ea {:06b}, xreg {:012b} overlaps for {}", template, ea, xreg, op);
}

pub fn encode_ea_dx(op: &OpcodeInstance, template: u16, pc: u32, mem: &mut Memory) -> u32 {
    let ea = encode_ea(&op.operands[0]);
    let dx = encode_dx(&op.operands[1]);
    assert_no_overlap(&op, template, ea, dx);
    mem.write_word(pc, template | ea | dx);
    op.operands[0].add_extension_words(pc + 2, mem)
}

pub fn encode_ea_ax(op: &OpcodeInstance, template: u16, pc: u32, mem: &mut Memory) -> u32 {
    let ea = encode_ea(&op.operands[0]);
    let ax = encode_ax(&op.operands[1]);
    assert_no_overlap(&op, template, ea, ax);
    mem.write_word(pc, template | ea | ax);
    op.operands[0].add_extension_words(pc + 2, mem)
}

pub fn encode_dx_ea(op: &OpcodeInstance, template: u16, pc: u32, mem: &mut Memory) -> u32 {
    let ea = encode_ea(&op.operands[1]);
    let dx = encode_dx(&op.operands[0]);
    assert_no_overlap(&op, template, ea, dx);
    mem.write_word(pc, template | ea | dx);
    op.operands[1].add_extension_words(pc + 2, mem)
}

pub fn encode_imm_ea(op: &OpcodeInstance, template: u16, pc: u32, mem: &mut Memory) -> u32 {
    let ea = encode_ea(&op.operands[1]);
    assert_no_overlap(&op, template, ea, 0);
    let pc = mem.write_word(pc, template | ea);
    let pc = op.operands[0].add_extension_words(pc, mem);
    op.operands[1].add_extension_words(pc, mem)
}
#[allow(unused_variables)]
pub fn nop_encoder(op: &OpcodeInstance, template: u16, pc: u32, mem: &mut Memory) -> u32 {
    pc
}
#[allow(unused_variables)]
pub fn nop_selector(op: &OpcodeInstance) -> bool {
    false
}
pub fn is_ea_ax(op: &OpcodeInstance) -> bool {
    if op.operands.len() != 2 { return false };
    match op.operands[1] {
        Operand::AddressRegisterDirect(_) => true,
        _ => false,
    }
}
pub fn is_ea_dx(op: &OpcodeInstance) -> bool {
    if op.operands.len() != 2 { return false };
    match op.operands[1] {
        Operand::DataRegisterDirect(_) => true,
        _ => false,
    }
}
pub fn is_dx_ea(op: &OpcodeInstance) -> bool {
    if op.operands.len() != 2 { return false };
    match op.operands[1] {
        Operand::DataRegisterDirect(_) => false,
        _ => true,
    }
}
pub fn is_imm_ea(op: &OpcodeInstance) -> bool {
    if op.operands.len() != 2 { return false };
    match op.operands[0] {
        Operand::Immediate(_, _) => true,
        _ => false,
    }
}
pub fn encode_instruction(instruction: &str, op_inst: &OpcodeInstance, pc: u32, mem: &mut Memory) -> u32
{
    let optable = super::generate();
    for op in optable {
        if op_inst.mnemonic == op.mnemonic && op_inst.size == op.size && (op.selector)(op_inst) {
            let encoder = op.encoder;
            return encoder(op_inst, op.matching as u16, pc, mem);
        }
    }
    panic!("Could not assemble {} ({})", instruction, op_inst);
}

use regex::RegexSet;
use regex::Regex;
use std::io;
use std::io::BufRead;

pub struct Assembler {
    instruction_re: Regex,
    drd: Regex,
    ard: Regex,
    ari: Regex,
    api: Regex,
    apd: Regex,
    adi: Regex,
    aix: Regex,
    hex: Regex,
    lng: Regex,
    pcd: Regex,
    pci: Regex,
    imm: Regex,
    modes: RegexSet,
}

impl Assembler {
    pub fn new() -> Assembler {
        let drd = Regex::new(r"^D([0-7])$").unwrap();
        let ard = Regex::new(r"^A([0-7])$").unwrap();
        let ari = Regex::new(r"^\(A([0-7])\)$").unwrap();
        let api = Regex::new(r"^\(A([0-7])\)\+$").unwrap();
        let apd = Regex::new(r"^-\(A([0-7])\)$").unwrap();
        let adi = Regex::new(r"^(-?\d+)\(A([0-7])\)$",).unwrap();
        let aix = Regex::new(r"^(-?\d+)\(A([0-7]),([DA])([0-7])\)$").unwrap();
        let hex = Regex::new(r"^\$([\dA-F]+)$").unwrap();
        let lng = Regex::new(r"^\$([\dA-F]+)\.L$").unwrap();
        let pcd = Regex::new(r"^(-?\d+)\(PC\)$").unwrap();
        let pci = Regex::new(r"^(-?\d+)\(PC,([DA])([0-7])\)$").unwrap();
        let imm = Regex::new(r"^#\$([\dA-F]+)$").unwrap();

        Assembler { instruction_re: Regex::new(r"^(\w+)(\.\w)?(\s+(\w\d|-?\$?[\dA-F]*\([\w,0-9]+\)\+?|#?\$?[\dA-F]+(?:\.\w)?)(,(\w\d|-?\$?[\dA-F]*\([\w,0-9]+\)\+?|#?-?\$?[\dA-F]+(?:\.\w)?))?)$").unwrap(),
            modes: RegexSet::new(&[
        drd.as_str(),
        ard.as_str(),
        ari.as_str(),
        api.as_str(),
        apd.as_str(),
        adi.as_str(),
        aix.as_str(),
        hex.as_str(),
        lng.as_str(),
        pcd.as_str(),
        pci.as_str(),
        imm.as_str(),
    ]).unwrap(),
            drd: drd,
            ard: ard,
            ari: ari,
            api: api,
            apd: apd,
            adi: adi,
            aix: aix,
            hex: hex,
            lng: lng,
            pcd: pcd,
            pci: pci,
            imm: imm,
        }
    }

    pub fn assemble(&self, reader: &mut BufRead) ->  io::Result<(u32, MemoryVec)> {
        let mut mem = MemoryVec::new();
        let mut pc = 0;
        for line in reader.lines() {
            let asm = line.unwrap();
            let asm_text = asm.as_str();
            let op = self.parse_assembler(asm_text);
            pc = encode_instruction(asm_text, &op, pc, &mut mem);
        }
        Ok((pc, mem))
    }
    pub fn parse_assembler<'a>(&'a self, instruction: &'a str) -> OpcodeInstance {
        let im = self.instruction_re.captures(instruction);
        if im.is_none() {
            panic!("Syntax Error: {:?} does not match instruction pattern {:?}", instruction, self.instruction_re);
        }
        let imatch = im.unwrap();
        let (ins, size, op1, op2) = (imatch.at(1).unwrap_or(""), imatch.at(2).unwrap_or(""), imatch.at(4).unwrap_or(""), imatch.at(6).unwrap_or(""));
        let size = match size {
            ".B" => Size::Byte,
            ".W" => Size::Word,
            ".L" => Size::Long,
            _ => Size::Unsized,
        };

        let mode1 = self.modes.matches(op1).into_iter().nth(0);
        let mode2 = self.modes.matches(op2).into_iter().nth(0);
        let get_chr = |rx: &Regex, op: &str, at: usize| rx.captures(op).unwrap().at(at).unwrap().chars().next().unwrap();
        let get_num = |rx: &Regex, op: &str, at: usize|->i32 { rx.captures(op).unwrap().at(at).unwrap().parse().unwrap() };
        let get_hex = |rx: &Regex, op: &str, at: usize|->u32 { u32::from_str_radix(rx.captures(op).unwrap().at(at).unwrap(), 16).unwrap() };
        let to_op = |opinfo:(Option<usize>, &str)| {
            let (v, op) = opinfo;
            match v {
                None => if !op.is_empty() { panic!("operand {:?} couldn't be matched", op)} else { None },
                Some(0) => Some(Operand::DataRegisterDirect(get_num(&self.drd, op, 1) as u8)),
                Some(1) => Some(Operand::AddressRegisterDirect(get_num(&self.ard, op, 1) as u8)),
                Some(2) => Some(Operand::AddressRegisterIndirect(get_num(&self.ari, op, 1) as u8)),
                Some(3) => Some(Operand::AddressRegisterIndirectWithPostincrement(get_num(&self.api, op, 1) as u8)),
                Some(4) => Some(Operand::AddressRegisterIndirectWithPredecrement(get_num(&self.apd, op, 1) as u8)),
                Some(5) => Some(Operand::AddressRegisterIndirectWithDisplacement(get_num(&self.adi, op, 2) as u8, get_num(&self.adi, op, 1) as i16)),
                Some(6) => {
                    let offset = if get_chr(&self.aix, op, 3) == 'D' {
                        0
                    } else {
                        8
                    };
                    let i_reg = offset + get_num(&self.aix, op, 4) as u8;
                    Some(Operand::AddressRegisterIndirectWithIndex(get_num(&self.aix, op, 2) as u8, i_reg, get_num(&self.aix, op, 1) as i8))
                },
                Some(7) => {
                    let hex: u32 = get_hex(&self.hex, op, 1);
                    if hex > 0x7FFF {
                        Some(Operand::AbsoluteLong(hex))
                    } else {
                        Some(Operand::AbsoluteWord(hex as u16))
                    }
                },
                Some(8) => Some(Operand::AbsoluteLong(get_hex(&self.lng, op, 1))),
                Some(9) => Some(Operand::PcWithDisplacement(get_num(&self.pcd, op, 1) as i16)),
                Some(10) => {
                    let offset = if get_chr(&self.pci, op, 2) == 'D' {
                        0
                    } else {
                        8
                    };
                    let i_reg = offset + get_num(&self.pci, op, 3) as u8;
                    Some(Operand::PcWithIndex(i_reg, get_num(&self.pci, op, 1) as i8))
                },
                Some(11) => Some(Operand::Immediate(size, get_hex(&self.imm, op, 1) as u32)),
                // TODO: Handle the remaining addressing modes
                _ => panic!("Operand syntax error {:?} {:?}", v, op)
            }
        };
        OpcodeInstance {mnemonic: ins, size: size, operands: vec![(mode1, op1), (mode2, op2)].into_iter().filter_map(to_op).collect::<Vec<_>>()}
    }
}

#[cfg(test)]
mod tests {
    use operand::Operand;
    use memory::{MemoryVec, Memory};
    use super::{Assembler, encode_instruction};
    use super::super::Size;
    use std::io::BufReader;

    #[test]
    fn encodes_add_8_er() {
        let asm = "ADD.B\t(A1),D2";
        let a = Assembler::new();
        let inst = a.parse_assembler(asm);
        assert_eq!("ADD", inst.mnemonic);
        assert_eq!(Size::Byte, inst.size);
        assert_eq!(Operand::AddressRegisterIndirect(1), inst.operands[0]);
        assert_eq!(Operand::DataRegisterDirect(2), inst.operands[1]);
        let mut mem = &mut MemoryVec::new();
        let pc = 0;
        let new_pc = encode_instruction(asm, &inst, pc, mem);
        assert_eq!(2, new_pc);
        assert_eq!(0xd411, mem.read_word(pc));
    }
    #[test]
    fn encodes_add_8_re() {
        let asm = "ADD.B\tD2,(A1)";
        let a = Assembler::new();
        let inst = a.parse_assembler(asm);
        assert_eq!("ADD", inst.mnemonic);
        assert_eq!(Size::Byte, inst.size);
        assert_eq!(Operand::DataRegisterDirect(2), inst.operands[0]);
        assert_eq!(Operand::AddressRegisterIndirect(1), inst.operands[1]);
        let mut mem = &mut MemoryVec::new();
        let pc = 0;
        let new_pc = encode_instruction(asm, &inst, pc, mem);
        assert_eq!(2, new_pc);
        assert_eq!(0xd511, mem.read_word(pc));
    }

    #[test]
    fn can_assemble() {
        let r68k = Assembler::new();

        let asm = r#"ADD.B   #$3,D0
ADD.B   D0,D1"#;

        println!("{}", asm);
        let mut reader = BufReader::new(asm.as_bytes());
        let (pc, mem) = r68k.assemble(&mut reader).unwrap();
    }
}<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::path::Path;

#[derive(Debug)]
pub struct LanguageSpec {
    pub reserved_words: HashMap<String, String>,
    pub hash_comment: bool,
    pub c_style_comments: bool,
    pub backtick_strings: bool,
    pub regexp_literals: bool,
    pub triple_quote_literals: bool,
    pub c_preprocessor: bool,
}

fn make_reserved(v: &Vec<&str>) -> HashMap<String, String> {
    let mut reserved_words = HashMap::new();
    for word in v {
        reserved_words.insert(word.to_string(), "style=\"color: blue;\" ".to_string());
    }
    reserved_words
}

lazy_static! {
    static ref RESERVED_WORDS_JS : Vec<&'static str> = vec![
        "abstract", "else", "instanceof", "super",
        "boolean", "enum", "int", "switch",
        "break", "export", "interface", "synchronized",
        "byte", "extends", "let", "this",
        "case", "false", "long", "throw",
        "catch", "final", "native", "throws",
        "char", "finally", "new", "transient",
        "class", "float", "null", "true",
        "const", "for", "package", "try",
        "continue", "function", "private", "typeof",
        "debugger", "goto", "protected", "var",
        "default", "if", "public", "void",
        "delete", "implements", "return", "volatile",
        "do", "import", "short", "while",
        "double", "in", "static", "with",
        "get", "set",
    ];

    static ref RESERVED_WORDS_CPP : Vec<&'static str> = vec![
        "alignas", "alignof", "and", "and_eq", "asm", "atomic_cancel",
        "atomic_commit", "atomic_noexcept", "auto", "bitand", "bitor", "bool", "break",
        "case", "catch", "char", "char16_t", "char32_t", "class", "compl", "concept",
        "const", "constexpr", "const_cast", "continue", "decltype", "default", "delete",
        "do", "double", "dynamic_cast", "else", "enum", "explicit", "export", "extern", "false",
        "float", "for", "friend", "goto", "if", "inline", "int", "import", "long", "module",
        "mutable", "namespace", "new", "noexcept", "not", "not_eq", "nullptr",
        // Don't mark "operator" as a keyword so that people can click
        // on it.
        //"operator",
        "or", "or_eq", "private", "protected", "public", "register", "reinterpret_cast",
        "requires", "return", "short", "signed", "sizeof", "static", "static_assert",
        "static_cast", "struct", "switch", "synchronized", "template", "this", "thread_local",
        "throw", "true", "try", "typedef", "typeid", "typename", "union", "unsigned",
        "using", "virtual", "void", "volatile", "wchar_t", "while", "xor", "xor_eq",
        "#if", "#ifdef", "#ifndef", "#else", "#elif", "#endif", "#define", "#undef",
        "#include", "#error", "defined",
    ];

    static ref RESERVED_WORDS_IPDL : Vec<&'static str> = vec![
        "answer", "as", "async", "both", "bridges", "call", "child", "class",
        "compress", "compressall", "__delete__", "delete", "from", "goto", "high",
        "include", "intr", "manager", "manages", "namespace", "normal", "nullable",
        "opens", "or", "parent", "prio", "protocol", "recv", "returns", "send",
        "spawns", "start", "state", "struct", "sync", "union", "upto", "urgent",
        "using",
    ];

    static ref RESERVED_WORDS_IDL : Vec<&'static str> = vec![
        "const", "interface", "in", "inout", "out", "attribute", "raises",
        "readonly", "native", "typedef",
        "array", "shared", "iid_is", "size_is", "retval",
        "boolean", "void", "octet", "short", "long", "long",
        "unsigned", "float", "double", "char", "string", "wchar", "wstring",
        "nsid", "domstring", "utf8string", "cstring", "astring", "jsval",
        "uuid", "scriptable", "builtinclass", "function", "noscript", "deprecated",
        "object", "main_process_scriptable_only",
    ];

    static ref RESERVED_WORDS_WEBIDL : Vec<&'static str> = vec![
        "module", "interface", "partial", "dictionary", "exception", "enum", "callback",
        "typedef", "implements", "const", "null", "true", "false", "serializer",
        "stringifier", "jsonifier", "unrestricted", "attribute", "readonly", "inherit",
        "static", "getter", "setter", "creator", "deleter", "legacycaller", "optional",
        "Date", "DOMString", "ByteString", "USVString", "any", "boolean", "byte",
        "double", "float", "long", "object", "octet", "Promise", "required", "sequence",
        "MozMap", "short", "unsigned", "void", "ArrayBuffer", "SharedArrayBuffer", "or",
        "maplike", "setlike", "iterable",
        "Exposed", "ChromeOnly", "ChromeConstructor", "Pref", "Func", "AvailableIn",
        "CheckAnyPermissions", "CheckAllPermissions", "JSImplementation", "HeaderFile",
        "NavigatorProperty", "AvailableIn", "Func", "CheckAnyPermissions", "CheckAllPermissions",
        "Deprecated", "NeedResolve", "OverrideBuiltins", "ChromeOnly", "Unforgeable",
        "UnsafeInPrerendering", "LegacyEventInit", "ProbablyShortLivingObject", "ArrayClass",
        "Clamp", "Constructor", "EnforceRange", "ExceptionClass", "Exposed", "ImplicitThis",
        "Global", "PrimaryGlobal", "LegacyArrayClass", "LegacyUnenumerableNamedProperties",
        "LenientSetter", "LenientThis", "NamedConstructor", "NewObject", "NoInterfaceObject",
        "OverrideBuiltins", "PutForwards", "Replaceable", "SameObject", "SecureContext",
        "Throws", "TreatNonObjectAsNull", "TreatNullAs", "Unforgeable", "Unscopable",
    ];

    static ref RESERVED_WORDS_PYTHON : Vec<&'static str> = vec![
        "and", "del", "from", "not", "while",
        "as", "elif", "global", "or", "with",
        "assert", "else", "if", "pass", "yield",
        "break", "except", "import", "print",
        "class", "exec", "in", "raise", "continue",
        "finally", "is", "return",
        "def", "for", "lambda", "try",
    ];

    static ref JS_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_JS),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: true,
        regexp_literals: true,
        triple_quote_literals: false,
        c_preprocessor: false,
    };

    static ref CPP_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_CPP),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: false,
        c_preprocessor: true,
    };

    static ref IPDL_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_IPDL),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: false,
        c_preprocessor: false,
    };

    static ref IDL_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_IDL),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: false,
        c_preprocessor: false,
    };

    static ref WEBIDL_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_WEBIDL),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: false,
        c_preprocessor: false,
    };

    static ref PYTHON_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_PYTHON),
        hash_comment: true,
        c_style_comments: false,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: true,
        c_preprocessor: false,
    };
}

#[derive(Debug)]
pub enum FormatAs {
    FormatCLike(&'static LanguageSpec),
    FormatTagLike(&'static LanguageSpec),
    Plain,
    Binary,
}

pub fn select_formatting(filename: &str) -> FormatAs {
    let ext = match Path::new(filename).extension() {
        Some(ext) => ext.to_str().unwrap(),
        None => "",
    };
    match ext {
        "c" | "cc" | "cpp" | "h" | "hh" | "mm" => FormatAs::FormatCLike(&*CPP_SPEC),
        "ipdl" | "ipdlh" => FormatAs::FormatCLike(&*IPDL_SPEC),
        "idl" => FormatAs::FormatCLike(&*IDL_SPEC),
        "webidl" => FormatAs::FormatCLike(&*WEBIDL_SPEC),
        "js" | "jsm" | "json" => FormatAs::FormatCLike(&*JS_SPEC),
        "py" | "build" | "configure" => FormatAs::FormatCLike(&*PYTHON_SPEC),

        "html" | "htm" | "xhtml" | "xml" | "xul" => FormatAs::FormatTagLike(&*JS_SPEC),

        "ogg" | "ttf" | "xpi" | "png" | "bcmap" |
        "gif" | "ogv" | "jpg" | "bmp" | "icns" | "ico" |
        "mp4" | "sqlite" | "jar" | "webm" | "woff" |
        "class" | "m4s" | "mgif" | "wav" | "opus" |
        "mp3" | "otf" => FormatAs::Binary,

        _ => FormatAs::Plain,
    }
}
<commit_msg>Register *.sjs as JavaScript<commit_after>use std::collections::HashMap;
use std::path::Path;

#[derive(Debug)]
pub struct LanguageSpec {
    pub reserved_words: HashMap<String, String>,
    pub hash_comment: bool,
    pub c_style_comments: bool,
    pub backtick_strings: bool,
    pub regexp_literals: bool,
    pub triple_quote_literals: bool,
    pub c_preprocessor: bool,
}

fn make_reserved(v: &Vec<&str>) -> HashMap<String, String> {
    let mut reserved_words = HashMap::new();
    for word in v {
        reserved_words.insert(word.to_string(), "style=\"color: blue;\" ".to_string());
    }
    reserved_words
}

lazy_static! {
    static ref RESERVED_WORDS_JS : Vec<&'static str> = vec![
        "abstract", "else", "instanceof", "super",
        "boolean", "enum", "int", "switch",
        "break", "export", "interface", "synchronized",
        "byte", "extends", "let", "this",
        "case", "false", "long", "throw",
        "catch", "final", "native", "throws",
        "char", "finally", "new", "transient",
        "class", "float", "null", "true",
        "const", "for", "package", "try",
        "continue", "function", "private", "typeof",
        "debugger", "goto", "protected", "var",
        "default", "if", "public", "void",
        "delete", "implements", "return", "volatile",
        "do", "import", "short", "while",
        "double", "in", "static", "with",
        "get", "set",
    ];

    static ref RESERVED_WORDS_CPP : Vec<&'static str> = vec![
        "alignas", "alignof", "and", "and_eq", "asm", "atomic_cancel",
        "atomic_commit", "atomic_noexcept", "auto", "bitand", "bitor", "bool", "break",
        "case", "catch", "char", "char16_t", "char32_t", "class", "compl", "concept",
        "const", "constexpr", "const_cast", "continue", "decltype", "default", "delete",
        "do", "double", "dynamic_cast", "else", "enum", "explicit", "export", "extern", "false",
        "float", "for", "friend", "goto", "if", "inline", "int", "import", "long", "module",
        "mutable", "namespace", "new", "noexcept", "not", "not_eq", "nullptr",
        // Don't mark "operator" as a keyword so that people can click
        // on it.
        //"operator",
        "or", "or_eq", "private", "protected", "public", "register", "reinterpret_cast",
        "requires", "return", "short", "signed", "sizeof", "static", "static_assert",
        "static_cast", "struct", "switch", "synchronized", "template", "this", "thread_local",
        "throw", "true", "try", "typedef", "typeid", "typename", "union", "unsigned",
        "using", "virtual", "void", "volatile", "wchar_t", "while", "xor", "xor_eq",
        "#if", "#ifdef", "#ifndef", "#else", "#elif", "#endif", "#define", "#undef",
        "#include", "#error", "defined",
    ];

    static ref RESERVED_WORDS_IPDL : Vec<&'static str> = vec![
        "answer", "as", "async", "both", "bridges", "call", "child", "class",
        "compress", "compressall", "__delete__", "delete", "from", "goto", "high",
        "include", "intr", "manager", "manages", "namespace", "normal", "nullable",
        "opens", "or", "parent", "prio", "protocol", "recv", "returns", "send",
        "spawns", "start", "state", "struct", "sync", "union", "upto", "urgent",
        "using",
    ];

    static ref RESERVED_WORDS_IDL : Vec<&'static str> = vec![
        "const", "interface", "in", "inout", "out", "attribute", "raises",
        "readonly", "native", "typedef",
        "array", "shared", "iid_is", "size_is", "retval",
        "boolean", "void", "octet", "short", "long", "long",
        "unsigned", "float", "double", "char", "string", "wchar", "wstring",
        "nsid", "domstring", "utf8string", "cstring", "astring", "jsval",
        "uuid", "scriptable", "builtinclass", "function", "noscript", "deprecated",
        "object", "main_process_scriptable_only",
    ];

    static ref RESERVED_WORDS_WEBIDL : Vec<&'static str> = vec![
        "module", "interface", "partial", "dictionary", "exception", "enum", "callback",
        "typedef", "implements", "const", "null", "true", "false", "serializer",
        "stringifier", "jsonifier", "unrestricted", "attribute", "readonly", "inherit",
        "static", "getter", "setter", "creator", "deleter", "legacycaller", "optional",
        "Date", "DOMString", "ByteString", "USVString", "any", "boolean", "byte",
        "double", "float", "long", "object", "octet", "Promise", "required", "sequence",
        "MozMap", "short", "unsigned", "void", "ArrayBuffer", "SharedArrayBuffer", "or",
        "maplike", "setlike", "iterable",
        "Exposed", "ChromeOnly", "ChromeConstructor", "Pref", "Func", "AvailableIn",
        "CheckAnyPermissions", "CheckAllPermissions", "JSImplementation", "HeaderFile",
        "NavigatorProperty", "AvailableIn", "Func", "CheckAnyPermissions", "CheckAllPermissions",
        "Deprecated", "NeedResolve", "OverrideBuiltins", "ChromeOnly", "Unforgeable",
        "UnsafeInPrerendering", "LegacyEventInit", "ProbablyShortLivingObject", "ArrayClass",
        "Clamp", "Constructor", "EnforceRange", "ExceptionClass", "Exposed", "ImplicitThis",
        "Global", "PrimaryGlobal", "LegacyArrayClass", "LegacyUnenumerableNamedProperties",
        "LenientSetter", "LenientThis", "NamedConstructor", "NewObject", "NoInterfaceObject",
        "OverrideBuiltins", "PutForwards", "Replaceable", "SameObject", "SecureContext",
        "Throws", "TreatNonObjectAsNull", "TreatNullAs", "Unforgeable", "Unscopable",
    ];

    static ref RESERVED_WORDS_PYTHON : Vec<&'static str> = vec![
        "and", "del", "from", "not", "while",
        "as", "elif", "global", "or", "with",
        "assert", "else", "if", "pass", "yield",
        "break", "except", "import", "print",
        "class", "exec", "in", "raise", "continue",
        "finally", "is", "return",
        "def", "for", "lambda", "try",
    ];

    static ref JS_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_JS),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: true,
        regexp_literals: true,
        triple_quote_literals: false,
        c_preprocessor: false,
    };

    static ref CPP_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_CPP),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: false,
        c_preprocessor: true,
    };

    static ref IPDL_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_IPDL),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: false,
        c_preprocessor: false,
    };

    static ref IDL_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_IDL),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: false,
        c_preprocessor: false,
    };

    static ref WEBIDL_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_WEBIDL),
        hash_comment: false,
        c_style_comments: true,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: false,
        c_preprocessor: false,
    };

    static ref PYTHON_SPEC : LanguageSpec = LanguageSpec {
        reserved_words: make_reserved(&*RESERVED_WORDS_PYTHON),
        hash_comment: true,
        c_style_comments: false,
        backtick_strings: false,
        regexp_literals: false,
        triple_quote_literals: true,
        c_preprocessor: false,
    };
}

#[derive(Debug)]
pub enum FormatAs {
    FormatCLike(&'static LanguageSpec),
    FormatTagLike(&'static LanguageSpec),
    Plain,
    Binary,
}

pub fn select_formatting(filename: &str) -> FormatAs {
    let ext = match Path::new(filename).extension() {
        Some(ext) => ext.to_str().unwrap(),
        None => "",
    };
    match ext {
        "c" | "cc" | "cpp" | "h" | "hh" | "mm" => FormatAs::FormatCLike(&*CPP_SPEC),
        "ipdl" | "ipdlh" => FormatAs::FormatCLike(&*IPDL_SPEC),
        "idl" => FormatAs::FormatCLike(&*IDL_SPEC),
        "webidl" => FormatAs::FormatCLike(&*WEBIDL_SPEC),
        "js" | "jsm" | "json" | "sjs" => FormatAs::FormatCLike(&*JS_SPEC),
        "py" | "build" | "configure" => FormatAs::FormatCLike(&*PYTHON_SPEC),

        "html" | "htm" | "xhtml" | "xml" | "xul" => FormatAs::FormatTagLike(&*JS_SPEC),

        "ogg" | "ttf" | "xpi" | "png" | "bcmap" |
        "gif" | "ogv" | "jpg" | "bmp" | "icns" | "ico" |
        "mp4" | "sqlite" | "jar" | "webm" | "woff" |
        "class" | "m4s" | "mgif" | "wav" | "opus" |
        "mp3" | "otf" => FormatAs::Binary,

        _ => FormatAs::Plain,
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 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.

//! Tidy check to ensure that there are no stray `.stderr` files in UI test directories.

use std::path::Path;

pub fn check(path: &Path, bad: &mut bool) {
    super::walk_many(&[&path.join("test/ui"), &path.join("test/ui-fulldeps")],
                     &mut |_| false,
                     &mut |file_path| {
        if let Some(ext) = file_path.extension() {
            if ext == "stderr" || ext == "stdout" {
                // Test output filenames have the format:
                // $testname.stderr
                // $testname.$mode.stderr
                // $testname.$revision.stderr
                // $testname.$revision.$mode.stderr
                //
                // For now, just make sure that there is a corresponding
                // $testname.rs file.
                let testname = file_path.file_name().unwrap()
                                        .to_str().unwrap()
                                        .splitn(2, '.').next().unwrap();
                if !file_path.with_file_name(testname)
                             .with_extension("rs")
                             .exists() {
                    println!("Stray file with UI testing output: {:?}", file_path);
                    *bad = true;
                }
            }
        }
    });
}
<commit_msg>tidy: Add a check for empty UI test files<commit_after>// Copyright 2018 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.

//! Tidy check to ensure that there are no stray `.stderr` files in UI test directories.

use std::fs;
use std::path::Path;

pub fn check(path: &Path, bad: &mut bool) {
    super::walk_many(
        &[&path.join("test/ui"), &path.join("test/ui-fulldeps")],
        &mut |_| false,
        &mut |file_path| {
            if let Some(ext) = file_path.extension() {
                if ext == "stderr" || ext == "stdout" {
                    // Test output filenames have the format:
                    // $testname.stderr
                    // $testname.$mode.stderr
                    // $testname.$revision.stderr
                    // $testname.$revision.$mode.stderr
                    //
                    // For now, just make sure that there is a corresponding
                    // $testname.rs file.
                    let testname = file_path
                        .file_name()
                        .unwrap()
                        .to_str()
                        .unwrap()
                        .splitn(2, '.')
                        .next()
                        .unwrap();
                    if !file_path
                        .with_file_name(testname)
                        .with_extension("rs")
                        .exists()
                    {
                        println!("Stray file with UI testing output: {:?}", file_path);
                        *bad = true;
                    }

                    if let Ok(metadata) = fs::metadata(file_path) {
                        if metadata.len() == 0 {
                            println!("Empty file with UI testing output: {:?}", file_path);
                            *bad = true;
                        }
                    }
                }
            }
        },
    );
}
<|endoftext|>


<commit_before>// Copyright 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.

#![feature(rustc_private)]

extern crate rustc;
extern crate rustc_driver;
extern crate rustc_lint;
extern crate rustc_metadata;
extern crate rustc_errors;
extern crate rustc_trans;
extern crate syntax;

use rustc::session::{build_session, Session};
use rustc::session::config::{basic_options, Input,
                             OutputType, OutputTypes};
use rustc_driver::driver::{compile_input, CompileController};
use rustc_metadata::cstore::CStore;
use rustc_errors::registry::Registry;
use syntax::codemap::FileName;

use std::path::PathBuf;
use std::rc::Rc;

fn main() {
    let src = r#"
    fn main() {}
    "#;

    let args: Vec<String> = std::env::args().collect();

    if args.len() < 4 {
        panic!("expected rustc path");
    }

    let tmpdir = PathBuf::from(&args[1]);

    let mut sysroot = PathBuf::from(&args[3]);
    sysroot.pop();
    sysroot.pop();

    compile(src.to_string(), tmpdir.join("out"), sysroot.clone());

    compile(src.to_string(), tmpdir.join("out"), sysroot.clone());
}

fn basic_sess(sysroot: PathBuf) -> (Session, Rc<CStore>) {
    let mut opts = basic_options();
    opts.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
    opts.maybe_sysroot = Some(sysroot);
    if let Ok(linker) = std::env::var("RUSTC_LINKER") {
        opts.cg.linker = Some(linker.into());
    }

    let descriptions = Registry::new(&rustc::DIAGNOSTICS);
    let cstore = Rc::new(CStore::new(Box::new(rustc_trans::LlvmMetadataLoader)));
    let sess = build_session(opts, None, descriptions);
    rustc_trans::init(&sess);
    rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
    (sess, cstore)
}

fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
    let (sess, cstore) = basic_sess(sysroot);
    let control = CompileController::basic();
    let input = Input::Str { name: FileName::Anon, input: code };
    let _ = compile_input(&sess, &cstore, &input, &None, &Some(output), None, &control);
}
<commit_msg>Fix a `compile_input` test<commit_after>// Copyright 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.

#![feature(rustc_private)]

extern crate rustc;
extern crate rustc_driver;
extern crate rustc_lint;
extern crate rustc_metadata;
extern crate rustc_errors;
extern crate rustc_trans;
extern crate syntax;

use rustc::session::{build_session, Session};
use rustc::session::config::{basic_options, Input,
                             OutputType, OutputTypes};
use rustc_driver::driver::{compile_input, CompileController};
use rustc_metadata::cstore::CStore;
use rustc_errors::registry::Registry;
use syntax::codemap::FileName;

use std::path::PathBuf;
use std::rc::Rc;

fn main() {
    let src = r#"
    fn main() {}
    "#;

    let args: Vec<String> = std::env::args().collect();

    if args.len() < 4 {
        panic!("expected rustc path");
    }

    let tmpdir = PathBuf::from(&args[1]);

    let mut sysroot = PathBuf::from(&args[3]);
    sysroot.pop();
    sysroot.pop();

    compile(src.to_string(), tmpdir.join("out"), sysroot.clone());

    compile(src.to_string(), tmpdir.join("out"), sysroot.clone());
}

fn basic_sess(sysroot: PathBuf) -> (Session, Rc<CStore>) {
    let mut opts = basic_options();
    opts.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
    opts.maybe_sysroot = Some(sysroot);
    if let Ok(linker) = std::env::var("RUSTC_LINKER") {
        opts.cg.linker = Some(linker.into());
    }

    let descriptions = Registry::new(&rustc::DIAGNOSTICS);
    let cstore = Rc::new(CStore::new(Box::new(rustc_trans::LlvmMetadataLoader)));
    let sess = build_session(opts, None, descriptions);
    rustc_trans::init(&sess);
    rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
    (sess, cstore)
}

fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
    let (sess, cstore) = basic_sess(sysroot);
    let control = CompileController::basic();
    let input = Input::Str { name: FileName::Anon, input: code };
    let _ = compile_input(&sess, &cstore, &None, &input, &None, &Some(output), None, &control);
}
<|endoftext|>


<commit_before>use read_token;
use range::Range;
use std::rc::Rc;

use {
    MetaData,
    MetaReader,
    ParseError,
};

/// Stores information about reading until whitespace or any of some character.
pub struct UntilAnyOrWhitespace {
    /// The characters to stop at.
    pub any_characters: Rc<String>,
    /// Whether empty data is accepted or not.
    pub optional: bool,
    /// The property to store read text.
    pub property: Option<Rc<String>>,
}

impl UntilAnyOrWhitespace {
    /// Parses until whitespace or any specified characters.
    pub fn parse<M>(
        &self,
        meta_reader: &mut M,
        state: &M::State,
        chars: &[char],
        offset: usize
    ) -> Result<(Range, M::State), (Range, ParseError)>
        where M: MetaReader
    {
        let (range, _) = read_token::until_any_or_whitespace(
            &self.any_characters, chars, offset);
        if range.length == 0 && !self.optional {
            Err((range, ParseError::ExpectedSomething))
        } else {
            if let Some(ref property) = self.property {
                let mut text = String::with_capacity(range.length);
                for c in chars.iter().take(range.length) {
                    text.push(*c);
                }
                match meta_reader.data(
                    MetaData::String(property.clone(), text),
                    state,
                    range
                ) {
                    Err(err) => Err((range, err)),
                    Ok(state) => Ok((range, state)),
                }
            } else {
                Ok((range, state.clone()))
            }
        }
    }
}
<commit_msg>Added unit tests for `UntilAnyOrWhitespace`<commit_after>use read_token;
use range::Range;
use std::rc::Rc;

use {
    MetaData,
    MetaReader,
    ParseError,
};

/// Stores information about reading until whitespace or any of some character.
pub struct UntilAnyOrWhitespace {
    /// The characters to stop at.
    pub any_characters: Rc<String>,
    /// Whether empty data is accepted or not.
    pub optional: bool,
    /// The property to store read text.
    pub property: Option<Rc<String>>,
}

impl UntilAnyOrWhitespace {
    /// Parses until whitespace or any specified characters.
    pub fn parse<M>(
        &self,
        meta_reader: &mut M,
        state: &M::State,
        chars: &[char],
        offset: usize
    ) -> Result<(Range, M::State), (Range, ParseError)>
        where M: MetaReader
    {
        let (range, _) = read_token::until_any_or_whitespace(
            &self.any_characters, chars, offset);
        if range.length == 0 && !self.optional {
            Err((range, ParseError::ExpectedSomething))
        } else {
            if let Some(ref property) = self.property {
                let mut text = String::with_capacity(range.length);
                for c in chars.iter().take(range.length) {
                    text.push(*c);
                }
                match meta_reader.data(
                    MetaData::String(property.clone(), text),
                    state,
                    range
                ) {
                    Err(err) => Err((range, err)),
                    Ok(state) => Ok((range, state)),
                }
            } else {
                Ok((range, state.clone()))
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::super::*;
    use range::Range;
    use std::rc::Rc;

    #[test]
    fn required() {
        let text = "fn ()";
        let chars: Vec<char> = text.chars().collect();
        let mut tokenizer = Tokenizer::new();
        let s = TokenizerState::new();
        let name = UntilAnyOrWhitespace {
            any_characters: Rc::new("(".into()),
            optional: false,
            property: None
        };
        let res = name.parse(&mut tokenizer, &s, &chars[3..], 3);
        assert_eq!(res, Err((Range::new(3, 0), ParseError::ExpectedSomething)));
    }

    #[test]
    fn successful() {
        let text = "fn foo()";
        let chars: Vec<char> = text.chars().collect();
        let mut tokenizer = Tokenizer::new();
        let s = TokenizerState::new();
        let function_name: Rc<String> = Rc::new("function_name".into());
        let name = UntilAnyOrWhitespace {
            any_characters: Rc::new("(".into()),
            optional: false,
            property: Some(function_name.clone())
        };
        let res = name.parse(&mut tokenizer, &s, &chars[3..], 3);
        assert_eq!(res, Ok((Range::new(3, 3), TokenizerState(1))));
        assert_eq!(tokenizer.tokens.len(), 1);
        assert_eq!(&tokenizer.tokens[0].0,
            &MetaData::String(function_name.clone(), "foo".into()));
    }
}
<|endoftext|>


<commit_before>use std::process;
use std::process::Command;
use std::{env, fs};

fn main() {
    let usage = r#"tutorial-maker <username> <program-name> <language> <program-type>

    <language> can only be the following:

    - rust

    <program-type> can only be the following:

    - library
"#;
    let args: Vec<String> = env::args().collect();

    if args.len() < 5 {
        println!("{usage}");

        process::exit(1);
    }

    println!("{:?}", args);

    let username = args[1].to_lowercase();
    let program_name = args[2].to_lowercase();
    let args3 = args[3].to_lowercase();
    let language = if args3 == "rust" {
        "rust"
    } else {
        println!("{usage}");

        process::exit(1);
    };

    let args4 = args[4].to_lowercase();
    let program_type = if args4 == "library" {
        "library"
    } else {
        println!("{usage}");

        process::exit(1);
    };

    let path_name = format!("repos/github/{username}");

    println!("mkdir -p path_name: {path_name}");

    fs::create_dir_all(&path_name).expect("unable to create path name");

    println!("cd {path_name}");

    env::set_current_dir(&path_name).expect("changing directory failed");

    let app_name = format!("{program_name}-{program_type}");
    let folder_name = format!("{program_name}-{language}-{program_type}");
    let repo_name = format!("{username}/{folder_name}");

    println!("rm -rf {folder_name}");

    let removing_folder_output = Command::new("rm")
        .arg("-rf")
        .arg(&folder_name)
        .output()
        .expect("removing folder failed");

    if removing_folder_output.status.success() {
        println!(
            "cloning stdout: {}",
            String::from_utf8_lossy(&removing_folder_output.stdout)
        );
    } else {
        println!(
            "cloning stderr: {}",
            String::from_utf8_lossy(&removing_folder_output.stderr)
        );

        process::exit(1);
    }

    println!("gh repo clone {repo_name}");

    let cloning_output = Command::new("gh")
        .arg("repo")
        .arg("clone")
        .arg(&repo_name)
        .output()
        .expect("cloning failed");

    if cloning_output.status.success() {
        println!(
            "cloning stdout: {}",
            String::from_utf8_lossy(&cloning_output.stdout)
        );
    } else {
        println!(
            "cloning stderr: {}",
            String::from_utf8_lossy(&cloning_output.stderr)
        );

        process::exit(1);
    }

    println!("cd {folder_name}");

    env::set_current_dir(&folder_name).expect("changing directory failed");

    println!("git rev-list --all --reverse");

    let rev_list_output = Command::new("git")
        .arg("rev-list")
        .arg("--all")
        .arg("--reverse")
        .output()
        .expect("rev-list failed");

    if rev_list_output.status.success() {
        let rev_list_output_cow = String::from_utf8_lossy(&rev_list_output.stdout).to_string();

        for (_, commit_hash) in rev_list_output_cow.split("\n").enumerate() {
            if !commit_hash.is_empty() {
                println!("git checkout {commit_hash}");

                let checkout_output = Command::new("git")
                    .arg("checkout")
                    .arg(commit_hash)
                    .output()
                    .expect("checkout failed");

                if checkout_output.status.success() {
                    println!(
                        "checkout stdout: {}",
                        String::from_utf8_lossy(&checkout_output.stdout)
                    );
                } else {
                    println!(
                        "checkout stderr: {}",
                        String::from_utf8_lossy(&checkout_output.stderr)
                    );

                    process::exit(1);
                }

                println!("git show --no-patch --format='%s'");

                let show_output = Command::new("git")
                    .arg("show")
                    .arg("--no-patch")
                    .arg("--format='%s'")
                    .output()
                    .expect("show failed");

                if show_output.status.success() {
                    println!(
                        "show stdout: {}",
                        String::from_utf8_lossy(&show_output.stdout)
                    );
                } else {
                    println!(
                        "show stderr: {}",
                        String::from_utf8_lossy(&show_output.stderr)
                    );

                    process::exit(1);
                }

                let mut path = env::current_dir().expect("getting current directory failed");
                path.push(&app_name);
                let metadata = fs::metadata(path);
                match metadata {
                  Ok(_) => {},
                  Err(_) => {
                      continue;
                  }
                };

                println!("cd {app_name}");

                env::set_current_dir(&app_name).expect("changing directory failed");

                println!("cargo test");

                let test_output = Command::new("cargo")
                    .arg("test")
                    .output()
                    .expect("test failed");

                if test_output.status.success() {
                    println!(
                        "test stdout: {}",
                        String::from_utf8_lossy(&test_output.stdout)
                    );
                } else {
                    println!(
                        "test stderr: {}",
                        String::from_utf8_lossy(&test_output.stderr)
                    );

                    process::exit(1);
                }
            }
        }

        println!(
            "rev-list stdout: {}",
            String::from_utf8_lossy(&rev_list_output.stdout)
        );
    } else {
        println!(
            "rev-list stderr: {}",
            String::from_utf8_lossy(&rev_list_output.stderr)
        );

        process::exit(1);
    }
}
<commit_msg>displaying commit body<commit_after>use std::process;
use std::process::Command;
use std::{env, fs};

fn main() {
    let usage = r#"tutorial-maker <username> <program-name> <language> <program-type>

    <language> can only be the following:

    - rust

    <program-type> can only be the following:

    - library
"#;
    let args: Vec<String> = env::args().collect();

    if args.len() < 5 {
        println!("{usage}");

        process::exit(1);
    }

    println!("{:?}", args);

    let username = args[1].to_lowercase();
    let program_name = args[2].to_lowercase();
    let args3 = args[3].to_lowercase();
    let language = if args3 == "rust" {
        "rust"
    } else {
        println!("{usage}");

        process::exit(1);
    };

    let args4 = args[4].to_lowercase();
    let program_type = if args4 == "library" {
        "library"
    } else {
        println!("{usage}");

        process::exit(1);
    };

    let path_name = format!("repos/github/{username}");

    println!("mkdir -p path_name: {path_name}");

    fs::create_dir_all(&path_name).expect("unable to create path name");

    println!("cd {path_name}");

    env::set_current_dir(&path_name).expect("changing directory failed");

    let app_name = format!("{program_name}-{program_type}");
    let folder_name = format!("{program_name}-{language}-{program_type}");
    let repo_name = format!("{username}/{folder_name}");

    println!("rm -rf {folder_name}");

    let removing_folder_output = Command::new("rm")
        .arg("-rf")
        .arg(&folder_name)
        .output()
        .expect("removing folder failed");

    if removing_folder_output.status.success() {
        println!(
            "cloning stdout: {}",
            String::from_utf8_lossy(&removing_folder_output.stdout)
        );
    } else {
        println!(
            "cloning stderr: {}",
            String::from_utf8_lossy(&removing_folder_output.stderr)
        );

        process::exit(1);
    }

    println!("gh repo clone {repo_name}");

    let cloning_output = Command::new("gh")
        .arg("repo")
        .arg("clone")
        .arg(&repo_name)
        .output()
        .expect("cloning failed");

    if cloning_output.status.success() {
        println!(
            "cloning stdout: {}",
            String::from_utf8_lossy(&cloning_output.stdout)
        );
    } else {
        println!(
            "cloning stderr: {}",
            String::from_utf8_lossy(&cloning_output.stderr)
        );

        process::exit(1);
    }

    println!("cd {folder_name}");

    env::set_current_dir(&folder_name).expect("changing directory failed");

    println!("git rev-list --all --reverse");

    let rev_list_output = Command::new("git")
        .arg("rev-list")
        .arg("--all")
        .arg("--reverse")
        .output()
        .expect("rev-list failed");

    if rev_list_output.status.success() {
        let rev_list_output_cow = String::from_utf8_lossy(&rev_list_output.stdout).to_string();

        for (_, commit_hash) in rev_list_output_cow.split("\n").enumerate() {
            if !commit_hash.is_empty() {
                println!("git checkout {commit_hash}");

                let checkout_output = Command::new("git")
                    .arg("checkout")
                    .arg(commit_hash)
                    .output()
                    .expect("checkout failed");

                if checkout_output.status.success() {
                    println!(
                        "checkout stdout: {}",
                        String::from_utf8_lossy(&checkout_output.stdout)
                    );
                } else {
                    println!(
                        "checkout stderr: {}",
                        String::from_utf8_lossy(&checkout_output.stderr)
                    );

                    process::exit(1);
                }

                println!("git show --no-patch --format='%s'");

                let show_s_output = Command::new("git")
                    .arg("show")
                    .arg("--no-patch")
                    .arg("--format='%s'")
                    .output()
                    .expect("show failed");

                if show_s_output.status.success() {
                    println!(
                        "show stdout: {}",
                        String::from_utf8_lossy(&show_s_output.stdout)
                    );
                } else {
                    println!(
                        "show stderr: {}",
                        String::from_utf8_lossy(&show_s_output.stderr)
                    );

                    process::exit(1);
                }

                println!("git show --no-patch --format='%b'");

                let show_b_output = Command::new("git")
                    .arg("show")
                    .arg("--no-patch")
                    .arg("--format='%b'")
                    .output()
                    .expect("show failed");

                if show_b_output.status.success() {
                    println!(
                        "show stdout: {}",
                        String::from_utf8_lossy(&show_b_output.stdout)
                    );
                } else {
                    println!(
                        "show stderr: {}",
                        String::from_utf8_lossy(&show_b_output.stderr)
                    );

                    process::exit(1);
                }

                let mut path = env::current_dir().expect("getting current directory failed");
                path.push(&app_name);
                let metadata = fs::metadata(path);
                match metadata {
                  Ok(_) => {},
                  Err(_) => {
                      continue;
                  }
                };

                println!("cd {app_name}");

                env::set_current_dir(&app_name).expect("changing directory failed");

                println!("cargo test");

                let test_output = Command::new("cargo")
                    .arg("test")
                    .output()
                    .expect("test failed");

                if test_output.status.success() {
                    println!(
                        "test stdout: {}",
                        String::from_utf8_lossy(&test_output.stdout)
                    );
                } else {
                    println!(
                        "test stderr: {}",
                        String::from_utf8_lossy(&test_output.stderr)
                    );

                    process::exit(1);
                }
            }
        }

        println!(
            "rev-list stdout: {}",
            String::from_utf8_lossy(&rev_list_output.stdout)
        );
    } else {
        println!(
            "rev-list stderr: {}",
            String::from_utf8_lossy(&rev_list_output.stderr)
        );

        process::exit(1);
    }
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>clones repo<commit_after>use std::env;
use std::process;
use std::process::Command;

fn main() {
    let usage = r#"tutorial-maker <username> <program-name> <language> <program-type>

    <language> can only be the following:

    - rust

    <program-type> can only be the following:

    - library
"#;
    let args: Vec<String> = env::args().collect();

    if args.len() < 5 {
        println!("{usage}");

        process::exit(1);
    }

    println!("{:?}", args);

    let username = args[1].to_lowercase();

    let program_name = args[2].to_lowercase();

    let args3 = args[3].to_lowercase();
    let language = if args3 == "rust" {
        "rust"
    } else {
        println!("{usage}");

        process::exit(1);
    };

    let args4 = args[4].to_lowercase();
    let program_type = if args4 == "library" {
        "library"
    } else {
        println!("{usage}");

        process::exit(1);
    };

    let folder_name = format!("{program_name}-{language}-{program_type}");

    let repo_name = format!("{username}/{folder_name}");

    println!("rm -rf {folder_name}");

    let removing_folder_output = Command::new("rm")
        .arg("-rf")
        .arg(&folder_name)
        .output()
        .expect("removing folder failed");

    if removing_folder_output.status.success() {
        println!(
            "cloning stdout: {}",
            String::from_utf8_lossy(&removing_folder_output.stdout)
        );
    } else {
        println!(
            "cloning stderr: {}",
            String::from_utf8_lossy(&removing_folder_output.stderr)
        );

        process::exit(1);
    }

    println!("gh repo clone {repo_name}");

    let cloning_output = Command::new("gh")
        .arg("repo")
        .arg("clone")
        .arg(&repo_name)
        .output()
        .expect("cloning failed");

    if cloning_output.status.success() {
        println!(
            "cloning stdout: {}",
            String::from_utf8_lossy(&cloning_output.stdout)
        );
    } else {
        println!(
            "cloning stderr: {}",
            String::from_utf8_lossy(&cloning_output.stderr)
        );

        process::exit(1);
    }

    env::set_current_dir(&folder_name).expect("changing directory failed");
}
<|endoftext|>


<commit_before>use memory::{MemoryBlock, Size, CellPosition};

pub type Operations = Vec<Operation>;

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Operation {
    /// Denotes a "block" of operations
    /// Any allocations in this block will be freed at the end of the block
    Block {
        body: Vec<Operation>,
    },

    /// Allocates the given size in bytes on the tape so that it is not used by any other code
    /// accidentally. The addr is generated automatically and represents the position which will
    /// eventually be determined when the memory layout is generated. Nothing is guaranteed about
    /// the position other than that `size` consecutive cells including the position will be
    /// available for use without conflicts. This is also used to ensure memory is automatically
    /// dropped at the end of its scope (stack frame).
    Allocate(MemoryBlock),

    /// While most allocations can be dropped at the end of their scope, temporary cells
    /// should be dropped as soon as possible so that they are available in the memory
    /// layout again as soon as possible
    /// This way we can avoid a lot of unnecessary move operations over cells
    /// that aren't being used anymore
    /// While this could be an optimization as well, temporary cells in particular are
    /// *known* to have this property since we generate temporary cells in the compiler itself
    /// The temporary cells are guaranteed to last for the duration of the given body
    /// They are then freed immediately afterwards
    TempAllocate {
        // The memory block used as temporary memory in the provided operations
        temp: MemoryBlock,
        body: Vec<Operation>,
    },

    /// Frees the given memory id and all cells associated with it
    /// Typically not used unless an explicit free is necessary before the end of the scope
    /// Freeing means both marking those cells available and zeroing their values
    /// This memory block should not be used after this
    Free(MemoryBlock),

    /// Increment the value of the given cell by a certain amount (relative to whatever the
    /// current amount in the cell is)
    Increment {
        target: CellPosition,
        amount: usize,
    },

    /// Decrement the value of the given cell by a certain amount (relative to whatever the
    /// current amount in the cell is)
    Decrement {
        target: CellPosition,
        amount: usize,
    },

    /// Read bytes into the given memory block
    /// Note: this generates both read instructions and move right instructions
    Read {
        target: MemoryBlock,
    },

    /// Write bytes into the given memory block
    /// Note: this generates both write instructions and move right instructions
    Write {
        target: MemoryBlock,
    },

    /// Set the value of every cell inside the given memory block to zero
    /// Note: this generates instructions to zero the value and move to the right towards each
    /// consecutive cell
    Zero {
        target: MemoryBlock,
    },

    /// Loop with the given operations as the loop body
    /// cond is the cell position that represents the loop condition
    /// This will be moved to before the loop and at the end of the loop body
    /// It is up to the surrounding operations to determine when to evaluate the condition
    Loop {
        cond: CellPosition,
        body: Vec<Operation>,
    },

    /// Copy `size` cells from the source cell to the target cell using a single temporary cell
    /// WARNING: If size is greater than the allocated size of either memory block, this can result
    /// in buffer overrun.
    Copy {
        source: CellPosition,
        target: CellPosition,
        size: Size,
    },

    /// Relocate the value at the source memory block to the target memory block
    /// leaving only zeros at the source memory block
    /// Both memory blocks must be the same size
    Relocate {
        source: MemoryBlock,
        target: MemoryBlock,
    },
}
<commit_msg>Documenting why the cond field in Loop is important<commit_after>use memory::{MemoryBlock, Size, CellPosition};

pub type Operations = Vec<Operation>;

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Operation {
    /// Denotes a "block" of operations
    /// Any allocations in this block will be freed at the end of the block
    Block {
        body: Vec<Operation>,
    },

    /// Allocates the given size in bytes on the tape so that it is not used by any other code
    /// accidentally. The addr is generated automatically and represents the position which will
    /// eventually be determined when the memory layout is generated. Nothing is guaranteed about
    /// the position other than that `size` consecutive cells including the position will be
    /// available for use without conflicts. This is also used to ensure memory is automatically
    /// dropped at the end of its scope (stack frame).
    Allocate(MemoryBlock),

    /// While most allocations can be dropped at the end of their scope, temporary cells
    /// should be dropped as soon as possible so that they are available in the memory
    /// layout again as soon as possible
    /// This way we can avoid a lot of unnecessary move operations over cells
    /// that aren't being used anymore
    /// While this could be an optimization as well, temporary cells in particular are
    /// *known* to have this property since we generate temporary cells in the compiler itself
    /// The temporary cells are guaranteed to last for the duration of the given body
    /// They are then freed immediately afterwards
    TempAllocate {
        // The memory block used as temporary memory in the provided operations
        temp: MemoryBlock,
        body: Vec<Operation>,
    },

    /// Frees the given memory id and all cells associated with it
    /// Typically not used unless an explicit free is necessary before the end of the scope
    /// Freeing means both marking those cells available and zeroing their values
    /// This memory block should not be used after this
    Free(MemoryBlock),

    /// Increment the value of the given cell by a certain amount (relative to whatever the
    /// current amount in the cell is)
    Increment {
        target: CellPosition,
        amount: usize,
    },

    /// Decrement the value of the given cell by a certain amount (relative to whatever the
    /// current amount in the cell is)
    Decrement {
        target: CellPosition,
        amount: usize,
    },

    /// Read bytes into the given memory block
    /// Note: this generates both read instructions and move right instructions
    Read {
        target: MemoryBlock,
    },

    /// Write bytes into the given memory block
    /// Note: this generates both write instructions and move right instructions
    Write {
        target: MemoryBlock,
    },

    /// Set the value of every cell inside the given memory block to zero
    /// Note: this generates instructions to zero the value and move to the right towards each
    /// consecutive cell
    Zero {
        target: MemoryBlock,
    },

    /// Loop with the given operations as the loop body
    /// cond is the cell position that represents the loop condition
    /// This will be moved to before the loop and at the end of the loop body
    /// It is up to the surrounding operations to determine when to evaluate the condition
    Loop {
        /// This field in particular is VERY important because it creates a guarantee about the
        /// position of the cell pointer both before and after a loop
        /// Without this, solving for the current position in order to generate
        /// movement instructions would be nearly impossible
        cond: CellPosition,
        body: Vec<Operation>,
    },

    /// Copy `size` cells from the source cell to the target cell using a single temporary cell
    /// WARNING: If size is greater than the allocated size of either memory block, this can result
    /// in buffer overrun.
    Copy {
        source: CellPosition,
        target: CellPosition,
        size: Size,
    },

    /// Relocate the value at the source memory block to the target memory block
    /// leaving only zeros at the source memory block
    /// Both memory blocks must be the same size
    Relocate {
        source: MemoryBlock,
        target: MemoryBlock,
    },
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate vcpkg;

use clap::{App, AppSettings, Arg, SubCommand};
use std::env;

fn main() {
    let app = App::new("vcpkg library finder")
        .about("Allows examining what vcpkg will find in a build script")
        .setting(AppSettings::SubcommandRequired)
        .arg(
            Arg::with_name("target")
                .short("t")
                .long("target")
                .value_name("TARGET TRIPLE")
                .help("the rust toolchain triple to find libraries for")
                .takes_value(true)
                .default_value("x86_64-pc-windows-msvc"),
        )
        .subcommand(
            SubCommand::with_name("probe")
                .about("try to find a library")
                .arg(
                    Arg::with_name("library")
                        .index(1)
                        .required(true)
                        .help("probe for a library and display paths and cargo metadata"),
                )
                .arg(
                    Arg::with_name("linkage")
                        .short("l")
                        .long("linkage")
                        .takes_value(true)
                        .possible_values(&["dll", "static"]),
                ),
        );

    let matches = app.get_matches();

    // set TARGET as if we are running under cargo
    env::set_var("TARGET", matches.value_of("target").unwrap());

    if let Some(matches) = matches.subcommand_matches("probe") {
        let lib_name = matches.value_of("library").unwrap();

        let mut cfg = vcpkg::Config::new();
        cfg.cargo_metadata(false);
        cfg.copy_dlls(false);
        if let Some(linkage) = matches.value_of("linkage") {
            match &linkage {
                &"dll" => {
                    // do nothing
                }
                &"static" => {
                    env::set_var("CARGO_CFG_TARGET_FEATURE", "crt-static");
                }
                _ => unreachable!(),
            }
        }

        match cfg.probe(lib_name) {
            Ok(lib) => {
                println!("Found library {}", lib_name);

                if !lib.include_paths.is_empty() {
                    println!("Include paths:");
                    for line in &lib.include_paths {
                        println!("\t{}", line.as_os_str().to_str().unwrap());
                    }
                }

                if !lib.link_paths.is_empty() {
                    println!("Library paths:");
                    for line in &lib.link_paths {
                        println!("\t{}", line.as_os_str().to_str().unwrap());
                    }
                }

                if !lib.link_paths.is_empty() {
                    println!("Runtime Library paths:");
                    for line in &lib.dll_paths {
                        println!("\t{}", line.as_os_str().to_str().unwrap());
                    }
                }

                if !lib.cargo_metadata.is_empty() {
                    println!("Cargo metadata:");
                    for line in &lib.cargo_metadata {
                        println!("\t{}", line);
                    }
                }
                if !lib.found_dlls.is_empty() {
                    println!("Found DLLs:");
                    for line in &lib.found_dlls {
                        println!("\t{}", line.display());
                    }
                }
                if !lib.found_libs.is_empty() {
                    println!("Found libs:");
                    for line in &lib.found_libs {
                        println!("\t{}", line.display());
                    }
                }
            }
            Err(err) => {
                println!("Failed:  {}", err);
            }
        }
    }
}
<commit_msg>use find_library and say "package" instead of "library"<commit_after>extern crate clap;
extern crate vcpkg;

use clap::{App, AppSettings, Arg, SubCommand};
use std::env;

fn main() {
    let app = App::new("vcpkg library finder")
        .about("Allows examining what vcpkg will find in a build script")
        .setting(AppSettings::SubcommandRequired)
        .arg(
            Arg::with_name("target")
                .short("t")
                .long("target")
                .value_name("TARGET TRIPLE")
                .help("the rust toolchain triple to find libraries for")
                .takes_value(true)
                .default_value("x86_64-pc-windows-msvc"),
        )
        .subcommand(
            SubCommand::with_name("probe")
                .about("try to find a package")
                .arg(
                    Arg::with_name("package")
                        .index(1)
                        .required(true)
                        .help("probe for a library and display paths and cargo metadata"),
                )
                .arg(
                    Arg::with_name("linkage")
                        .short("l")
                        .long("linkage")
                        .takes_value(true)
                        .possible_values(&["dll", "static"]),
                ),
        );

    let matches = app.get_matches();

    // set TARGET as if we are running under cargo
    env::set_var("TARGET", matches.value_of("target").unwrap());

    if let Some(matches) = matches.subcommand_matches("probe") {
        let lib_name = matches.value_of("package").unwrap();

        let mut cfg = vcpkg::Config::new();
        cfg.cargo_metadata(false);
        cfg.copy_dlls(false);
        if let Some(linkage) = matches.value_of("linkage") {
            match &linkage {
                &"dll" => {
                    // do nothing
                }
                &"static" => {
                    env::set_var("CARGO_CFG_TARGET_FEATURE", "crt-static");
                }
                _ => unreachable!(),
            }
        }

        match cfg.find_package(lib_name) {
            Ok(lib) => {
                println!("Found library {}", lib_name);

                if !lib.include_paths.is_empty() {
                    println!("Include paths:");
                    for line in &lib.include_paths {
                        println!("  {}", line.as_os_str().to_str().unwrap());
                    }
                }

                if !lib.link_paths.is_empty() {
                    println!("Library paths:");
                    for line in &lib.link_paths {
                        println!("  {}", line.as_os_str().to_str().unwrap());
                    }
                }

                if !lib.link_paths.is_empty() {
                    println!("Runtime Library paths:");
                    for line in &lib.dll_paths {
                        println!("  {}", line.as_os_str().to_str().unwrap());
                    }
                }

                if !lib.cargo_metadata.is_empty() {
                    println!("Cargo metadata:");
                    for line in &lib.cargo_metadata {
                        println!("  {}", line);
                    }
                }
                if !lib.found_dlls.is_empty() {
                    println!("Found DLLs:");
                    for line in &lib.found_dlls {
                        println!("  {}", line.display());
                    }
                }
                if !lib.found_libs.is_empty() {
                    println!("Found libs:");
                    for line in &lib.found_libs {
                        println!("  {}", line.display());
                    }
                }
            }
            Err(err) => {
                println!("Failed:  {}", err);
            }
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Add back accidentally removed comment<commit_after><|endoftext|>