class Operand(ABC): def __init__(self, instruction, value=None): self.type = OperandType.UNKNOWN self.operand_string = "" self.instruction = instruction self.requires_resolution = False self.value = value if value else NoneValue(None) self.left = NoneValue(None) self.right = NoneValue(None) self.operation = "" @classmethod def create_from_str(cls, operand_string, instruction): try: return PseudoOperand(operand_string, instruction) except ValueError: pass try: return SpecialOperand(operand_string, instruction) except ValueError: pass try: return RelativeOperand(operand_string, instruction) except ValueError: pass try: return InherentOperand(operand_string, instruction) except ValueError: pass try: return ImmediateOperand(operand_string, instruction) except ValueError: pass try: return DirectOperand(operand_string, instruction) except ValueError: pass try: return ExtendedOperand(operand_string, instruction) except ValueError: pass try: return ExtendedIndexedOperand(operand_string, instruction) except ValueError: pass try: return IndexedOperand(operand_string, instruction) except ValueError: pass try: return ExpressionOperand(operand_string, instruction) except ValueError: pass try: return UnknownOperand(operand_string, instruction) except ValueError: pass raise ValueError("[{}] unknown operand type".format(operand_string)) def is_type(self, operand_type): """ Returns True if the type of this operand class is the type being compared. :param operand_type: the OperandType to check :return: True if the OperandType values match, False otherwise """ return self.type == operand_type def resolve_symbols(self, symbol_table): """ Given a symbol table, searches the operands for any symbols, and resolves them with values from the symbol table. Returns a (possibly) new Operand class type as a result of symbol resolution. :param symbol_table: the symbol table to search :return: self, or a new Operand class type with a resolved value """ if self.is_type(OperandType.EXPRESSION): return self.resolve_expression(symbol_table) if not self.value.is_type(ValueType.SYMBOL): return self symbol = self.get_symbol(self.value.ascii(), symbol_table) if symbol.is_type(ValueType.ADDRESS): self.value = AddressValue(symbol.int) if self.type == OperandType.UNKNOWN: return ExtendedOperand(self.operand_string, self.instruction, value=self.value) return self if symbol.is_type(ValueType.NUMERIC): self.value = copy(symbol) if self.value.hex_len() == 2: return DirectOperand(self.operand_string, self.instruction, value=self.value) return ExtendedOperand(self.operand_string, self.instruction, value=self.value) def resolve_expression(self, symbol_table): """ Attempts to resolve the expression contained in the operand using the symbol table supplied. Returns a (possibly) new Operand class type as a result of symbol resolution. :param symbol_table: the symbol table to use for resolution :return: self, or a new Operand class type with a resolved value """ if self.left.is_type(ValueType.SYMBOL): self.left = self.get_symbol(self.left.ascii(), symbol_table) if self.right.is_type(ValueType.SYMBOL): self.right = self.get_symbol(self.right.ascii(), symbol_table) if self.right.is_type(ValueType.NUMERIC) and self.left.is_type( ValueType.NUMERIC): left = self.left.int right = self.right.int if self.operation == "+": self.value = NumericValue("{}".format(left + right)) if self.operation == "-": self.value = NumericValue("{}".format(left - right)) if self.operation == "*": self.value = NumericValue("{}".format(int(left * right))) if self.operation == "/": self.value = NumericValue("{}".format(int(left / right))) if self.value.hex_len() == 2: return DirectOperand(self.operand_string, self.instruction, value=self.value) return ExtendedOperand(self.operand_string, self.instruction, value=self.value) raise ValueError("[{}] unresolved expression".format( self.operand_string)) @staticmethod def get_symbol(symbol_label, symbol_table): if symbol_label not in symbol_table: raise ValueError("[{}] not in symbol table".format(symbol_label)) return symbol_table[symbol_label] @abstractmethod def translate(self): """
def test_none_ascii_works_correctly(self): result = NoneValue('"test string"') self.assertEqual("", result.ascii())