def test_vm_jmpb(): code = [*create_instr("jmpb", 0), *create_instr("nop")] vm = Arkhe(code) vm.registers[0] = 3 vm.exc_instr() # counter at 3 assert vm.counter == 0
def test_vm_mem_dealloc(): code = create_instr("dealloc", 0, 0) vm = Arkhe(code) vm.registers[0] = 16 vm.memory.alloc(36) vm.exc_instr() assert len(vm.memory) == 20
def test_vm_jne(): code = [*create_instr("jne", 0)] vm = Arkhe(code) vm.registers[0] = 0 vm._eqflag = False vm.exc_instr() assert vm.counter == 0 vm._eqflag = True vm.exc_instr() assert vm.counter == 3
def test_vm_comp_ne(): code = [*create_instr("ne", 0, 1), *create_instr("ne", 1, 2)] vm = Arkhe(code) vm.registers[0] = 5 vm.registers[1] = 5 vm.exc_instr() assert not vm._eqflag vm.registers[2] = 10 vm.exc_instr() assert vm._eqflag
def test_vm_mem_read(): code = create_instr("read", 0, 1) vm = Arkhe(code) vm.registers[0] = 16 with pytest.raises(MemoryFault): vm.exc_instr() vm.memory.alloc(100) vm.memory[16] = "hello" vm.counter = 0 vm.exc_instr() assert vm.registers[1] == "hello"
def test_vm_math(): code = [ *create_instr("load", 0, 3, 232), *create_instr("load", 1, 1, 244), *create_instr("add", 0, 1, 2), *create_instr("sub", 2, 1, 3), *create_instr("mul", 1, 2, 4), *create_instr("truediv", 2, 3, 5), ] vm = Arkhe(code) vm.eval() assert (vm.registers[0] == 1000 and vm.registers[1] == 500 and vm.registers[2] == 1500 and vm.registers[3] == 1000 and vm.registers[4] == 750_000 and vm.registers[5] == 1.5)
def test_vm_mem_alloc(): code = create_instr("alloc", 0) vm = Arkhe(code) vm.registers[0] = 16 vm.exc_instr() assert len(vm.memory) == 16 vm.counter = 0 vm.exc_instr() assert len(vm.memory) == 32
def test_vm_sym_read(): code = create_instr("symread", 0, 1) vm = Arkhe(code) vm.symtable["age"] = 15 vm.registers[0] = "age" vm.exc_instr() assert vm.registers[1] == 15
def test_vm_jfn(): code = [*create_instr("jfn", 0)] vm = Arkhe(code) vm.registers[0] = 20 vm._eqflag = False vm.exc_instr() assert vm.counter == 23
def test_vm_jmp(): code = create_instr("jmp", 0) vm = Arkhe(code) vm.registers[0] = 0 vm.exc_instr() assert vm.counter == 0
def test_vm_load_multiple(): code = [*create_instr("load", 0, 3, 232), *create_instr("load", 1, 1, 244)] vm = Arkhe(code) vm.eval() assert vm.registers[0] == 1000 and vm.registers[1] == 500
def test_vm_load(): code = create_instr("load", 0, 0, 100) vm = Arkhe(code) vm.eval() assert vm.registers[0] == 100
def test_ext_libc(): code = create_instr("ccall", 0, 1) vm = Arkhe(code) vm.registers[0] = "getpid" vm.exc_instr() assert vm.registers[1] == os.getpid()
def test_vm_comp_lt(): code = [ *create_instr("lt", 0, 1), *create_instr("lt", 1, 2), *create_instr("lt", 1, 3), ] vm = Arkhe(code) vm.registers[0] = 5 vm.registers[1] = 5 vm.exc_instr() assert not vm._eqflag vm.registers[2] = 10 vm.exc_instr() assert vm._eqflag vm.registers[3] = 4 vm.exc_instr() assert not vm._eqflag
def test_type_string(): code = create_instr("load", 0, 104, 101, 108, 108, 111, TypeTable.STR) vm = Arkhe(code) vm.exc_instr() assert vm.registers[0] == "hello" vm.code.extend( create_instr("load", 1, 32, 119, 111, 114, 108, 100, 33, 32, TypeTable.STR)) vm.exc_instr() assert vm.registers[1] == " world! " vm.code.extend(create_instr("add", 0, 1, 2)) vm.exc_instr() assert vm.registers[2] == "hello world! " vm.registers[5] = 5 vm.code.extend(create_instr("mul", 2, 5, 3)) vm.exc_instr() assert vm.registers[ 3] == "hello world! hello world! hello world! hello world! hello world! "
def __init__(self, stdout=sys.stdout): self.vm = Arkhe() self.parse = Parser() self.stdout = stdout
def run_cmd(self, command, stdout=None): with redirect_stdout(stdout or self.stdout): if command == "code": code = copy(self.vm.code) code.insert(self.vm.counter, 'SIGN') codesets = divide_sequence(code, INSTR_TERM) try: current, = filter(lambda sequence: 'SIGN' in sequence, codesets) evaled = codesets.index(current) codesets[evaled].remove('SIGN') unknown = False except ValueError: unknown = True for n, codeset in enumerate(codesets, 1): codeset = Instr(codeset.pop(0), codeset) if unknown: print(f"{n}th instr (state unknown) -> {codeset}") continue if n < evaled: Text["green"]( f"{n}th instr (executed) -> {codeset}") elif n == evaled: Text["green"]( f"{n}th instr (last executed) -> {codeset}") else: Text["blue"]( f"{n}th instr (pending) -> {codeset}") elif command == "regs": allrs = set(self.vm.registers.items()) useds = set(filter(lambda i: i[1], allrs)) frees = allrs - useds print("Register states:") Text["blue"](f"\tTotal: {len(allrs)}") Text["warn"]( f"\tUseds: {str(len(useds)).zfill(len(f'{len(allrs)}'))}") Text["green"](f"\tFrees: {len(frees)}") for reg, val in useds: print(f"r{reg} = {val}") elif command.startswith("r") and command[1:].isnumeric(): reg = command[1:] print(f"r{reg} = {self.vm.registers[int(reg)]}") elif command == "mem": total = len(self.vm.memory) nonzero = len([0 for chunk in self.vm.memory if chunk]) zero = total - nonzero Text["blue"](f"Allocated memory: {total}") Text["warn"](f"Non-zero memory: {nonzero}") Text["green"](f"Free memory: {zero}") elif command == "eq": if self.vm._eqflag: Text["green"]("Equality Flag: True") else: Text["warn"]("Equality Flag: False") elif command == "counter": Text["green"](f"Counter: {self.vm.counter}") elif command == "symtable": for key, value in self.vm.symtable.items(): print(f"{Text['green_p'](key)}: {Text['blue_p'](value)}") elif "=" in command and command.startswith("sym"): target, value = [ item.strip() for item in command.replace("sym ", "").split("=") ] value = ast.literal_eval(value) self.vm.symtable[target] = value elif "=" in command and command.startswith("r"): target, value = [ item.strip() for item in command.replace("r", "").split("=") ] value = ast.literal_eval(value) self.vm.registers[target] = value elif command == "reset": self.vm = Arkhe( ) # or reset counter, code, eqflag, memory, registers elif command.startswith("eval ") and command[5:].isnumeric(): for _ in range(int(command[5:])): self.vm.exc_instr() else: try: if ";" in command: self.vm.code.extend( chain.from_iterable( self.parse(command) for command in command.split("; "))) else: commands = self.parse(command) self.vm.code.extend(commands) except ParseError as exc: Text["fail"]("Last instruction couldn't parsed!")
def test_type_bytes(): code = create_instr("load", 0, 104, 101, 108, 108, 111, TypeTable.BYT) vm = Arkhe(code) vm.exc_instr() assert vm.registers[0] == b"hello"