def test_demo_input(): assembler_code = """Mov [2] 0 Mov [3] 0 Jeq 6 [3] [1] Add [3] 1 Add [2] [0] Jmp 2 Mov [0] [2] Halt""" expected_output = "0x08 0x02 0x00 0x08 0x03 0x00 0x15 0x06 0x03 0x01 " \ "0x0B 0x03 0x01 0x0A 0x02 0x00 0x0F 0x02 0x07 0x00 " \ "0x02 0xFF" asm = assembler.assembler_to_hex(assembler_code) print(expected_output) print(asm) assert asm == expected_output
def test_invalid_argument(): with pytest.raises(InvalidArgumentError): assembler.assembler_to_hex('JMP a')
def test_unknown_instruction(): with pytest.raises(UnknownMnemonicError): assembler.assembler_to_hex('HEY')
def test_trivial(): assert assembler.assembler_to_hex('') == ''
def test_no_memory_left(): with pytest.raises(AssemblerException): s = ['${} = [_]'.format(i) for i in range(config.MEMORY_SIZE + 1)] assembler.assembler_to_hex('\n'.join(s))
def test_no_such_label(): with pytest.raises(NoSuchLabelError): assembler.assembler_to_hex('JMP :lbl')
def test_no_such_const(): with pytest.raises(NoSuchConstantError): assembler.assembler_to_hex('MOV $a 1')
def test_redefinition_const(): with pytest.raises(RedefinitionWarning): assembler.assembler_to_hex('$a = 1\n$a = 1\nHALT') with pytest.raises(RedefinitionWarning): assembler.assembler_to_hex('$a = [_]\n$a = [_]\nHALT')
def test_redefinition_label(): with pytest.raises(RedefinitionError): assembler.assembler_to_hex('lbl:\nlbl:\nHALT')
def test_invalid_args(): with pytest.raises(AssemblerSyntaxError): assembler.assembler_to_hex('MOV 0 0')
def run(self, asm, filename=None, preprocess=True): start = timer() # Tokenize code if preprocess: self.tokens = assembler.assembler_to_hex(asm, filename) self.tokens = self.tokens.split() # Main loop while self.running: self.jumping = False # Check bounds of instr_pointer if self.instr_pointer >= len(self.tokens): fatal_error('Reached end of code without seeing HALT', MissingHaltError, exit_func=self.halt) # Get current opcode opcode = self.tokens[self.instr_pointer] mnem = opcodes[opcode].upper() if self.debug: print('Instruction: {} ({})'.format(mnem, opcode)) # Look up instruction instruction_class = self.instructions[mnem] instruction = instruction_class(self) instruction_spec = instructions[mnem] annotations = get_annotations(instruction) # Look up number of arguments num_args = len(list(instruction_spec.values())[0]) if self.debug: print('Number of args:', num_args) print('Argument spec:', instruction_spec[opcode]) # Collect arguments if num_args: try: args = [self.process_arg(i, annotations, opcode) for i in range(num_args)] except IndexError: msg = 'Unexpectedly reached EOF. Maybe an argument is ' \ 'missing or a messed up jump occured' fatal_error(msg, VirtualRuntimeError, exit_func=self.halt) else: args = [] if self.debug: print('Arguments:', args) # Run instruction return_value = instruction(*args) # Process return value try: return_type = annotations['return'] except KeyError: return_type = None self.process_return_value(return_type, return_value) # Increase counters self.ticks += 1 if not self.jumping: self.prev_instr_pointer = self.instr_pointer self.instr_pointer += 1 # Skip current opcode self.instr_pointer += num_args # Skip arguments if self.debug: print('Memory:', self.memory) print() print() if self.debug: print() print('Exited after {} ticks in {:.5}s'.format(self.ticks, timer() - start)) return self.output.getvalue()