Maroc-OS/decompiler

View on GitHub
src/statements.py

Summary

Maintainability
F
5 days
Test Coverage

from expressions import *

class statement_t(object):
  """ defines a statement containing an expression. """

  def __init__(self, ea, expr):
    self.ea = ea
    self.expr = expr
    self.container = None
    return

  def copy(self):
    return self.__class__(self.ea, self.expr.copy() if self.expr else None)

  def index(self):
    """ return the statement index inside its parent
        container, or None if container is None """
    if self.container is None:
        return
    return self.container.index(self)

  def remove(self):
    """ removes the statement from its container. return True if
        container is not None and the removal succeeded. """
    if self.container is None:
        return
    return self.container.remove(self)

  @property
  def expr(self):
    return self.__expr

  @expr.setter
  def expr(self, value):
    if value is not None:
      assert isinstance(value, replaceable_t), 'expr is not replaceable'
      value.parent = (self, 'expr')
    self.__expr = value
    return

  def __getitem__(self, key):
    assert key in ('expr', ), "%s is not a valid key" % (key, )
    if key == 'expr':
      return self.expr
    else:
      raise IndexError('key not supported')
    return

  def __setitem__(self, key, value):
    assert key in ('expr', )
    if key == 'expr':
      self.expr = value
    else:
      raise IndexError('key not supported')
    return

  def __hash__(self):
    return hash((self.__class__, self.expr))

  def __repr__(self):
    return '<%s statement %s>' % (hex(self.ea) if self.ea else '~',
      repr(self.expr), )

  @property
  def expressions(self):
    """ by default, statements contain only one expression. some statements may contain
        no expressions (break, continue) and others may contain many (for loops, ...). """
    yield self.expr
    return

  @property
  def statements(self):
    """ by default, no statements are present in this one. """
    return []

  @property
  def containers(self):
    """ by default, no containers are present in this one. """
    return []

class container_t(object):
  """ a container contains statements. """

  def __init__(self, block, __list=None):
    assert type(block).__name__ == 'function_block_t', 'block must be function_block_t, not %s' % (type(block), )
    self.__block = block
    self.__list = __list or []
    for item in self.__list:
      item.container = self
    return

  def __repr__(self):
    return repr(self.__list)

  def __len__(self):
    return len(self.__list)

  def __getitem__(self, key):
    return self.__list[key]

  def __setitem__(self, key, value):
    if type(key) == slice:
      for item in value:
        assert isinstance(item, statement_t), 'cannot set non-statement to container'
        item.container = self
    else:
      assert isinstance(value, statement_t), 'cannot set non-statement to container'
      value.container = self
    self.__list.__setitem__(key, value)
    return

  def __hash__(self):
    return hash(tuple(self.statements))

  def copy(self):
    copy = container_t(self.block, [stmt.copy() for stmt in self])
    return copy

  def iteritems(self):
    for i in range(len(self.__list)):
      yield i, self.__list[i]
    return

  @property
  def block(self):
    return self.__block

  @property
  def statements(self):
    for item in self.__list:
      yield item
    return

  def add(self, stmt):
    assert isinstance(stmt, statement_t), 'cannot add non-statement: %s' % (repr(stmt), )
    self.__list.append(stmt)
    stmt.container = self
    return

  def extend(self, _new):
    for stmt in _new:
      assert isinstance(stmt, statement_t), 'cannot add non-statement to container'
      stmt.container = self
      self.__list.append(stmt)
    return

  def insert(self, key, _new):
    assert isinstance(_new, statement_t), 'cannot add non-statement: %s' % (repr(_new), )
    self.__list.insert(key, _new)
    _new.container = self
    return

  def pop(self, key=-1):
    stmt = self.__list.pop(key)
    if stmt:
      stmt.container = None
    return stmt

  def index(self, stmt):
    return self.__list.index(stmt)

  def __iter__(self):
    for item in self.__list:
      yield item
    return

  def remove(self, stmt):
    if stmt in self.__list:
      stmt.container = None
    return self.__list.remove(stmt)

class if_t(statement_t):
  """ if_t is a statement containing an expression and a then-side,
      and optionally an else-side. """

  def __init__(self, ea, expr, then, _else=None):
    statement_t.__init__(self, ea, expr)
    assert isinstance(then, container_t), 'then-side must be container_t'
    assert _else is None or isinstance(_else, container_t), 'else-side must be container_t'
    self.then_expr = then
    self.else_expr = _else
    return

  def __repr__(self):
    return '<%s if %s then %s else %s>' % (hex(self.ea) if self.ea else '~',
      repr(self.expr), repr(self.then_expr), repr(self.else_expr))

  def __hash__(self):
    return hash((self.__class__, self.expr, self.then_expr, self.else_expr))

  def copy(self):
    return self.__class__(self.ea, self.expr.copy(), self.then_expr.copy(), self.else_expr.copy() if self.else_expr else None)

  @property
  def statements(self):
    for stmt in self.then_expr.statements:
      yield stmt
    if self.else_expr:
      for stmt in self.else_expr.statements:
        yield stmt
    return

  @property
  def containers(self):
    yield self.then_expr
    if self.else_expr:
      yield self.else_expr
    return

class while_t(statement_t):
  """ a while_t statement of the type 'while(expr) { ... }'. """

  def __init__(self, ea, expr, loop_container):
    statement_t.__init__(self, ea, expr)
    assert isinstance(loop_container, container_t), '2nd argument to while_t must be container_t'
    self.loop_container = loop_container
    return

  def __repr__(self):
    return '<%s while %s do %s>' % (hex(self.ea) if self.ea else '~',
      repr(self.expr), repr(self.loop_container))

  def __hash__(self):
    return hash((self.__class__, self.expr, self.loop_container))

  def copy(self):
    return self.__class__(self.ea, self.expr.copy(), self.loop_container.copy())

  @property
  def statements(self):
    for stmt in self.loop_container:
      yield stmt
    return

  @property
  def containers(self):
    yield self.loop_container
    return

class do_while_t(statement_t):
  """ a do_while_t statement of the type 'do { ... } while(expr)'. """

  def __init__(self, ea, expr, loop_container):
    statement_t.__init__(self, ea, expr)
    assert isinstance(loop_container, container_t), '2nd argument to while_t must be container_t'
    self.loop_container = loop_container
    return

  def __repr__(self):
    return '<%s do %s while %s>' % (hex(self.ea) if self.ea else '~',
      repr(self.loop_container), repr(self.expr), )

  def __hash__(self):
    return hash((self.__class__, self.expr, self.loop_container))

  def copy(self):
    return self.__class__(self.ea, self.expr.copy(), self.loop_container.copy())

  @property
  def statements(self):
    for stmt in self.loop_container:
      yield stmt
    return

  @property
  def containers(self):
    yield self.loop_container
    return

class goto_t(statement_t):

  def __init__(self, ea, dst):
    statement_t.__init__(self, ea, dst)
    return

  def __eq__(self, other):
    return isinstance(other, self.__class__) and self.expr == other.expr

  def __repr__(self):
    s = hex(self.expr.value) if type(self.expr) == value_t else str(self.expr)
    return '<%s goto %s>' % (hex(self.ea) if self.ea else '~', s, )

  def is_known(self):
    return type(self.expr) == value_t

class branch_t(statement_t):

  def __init__(self, ea, expr, true, false):
    statement_t.__init__(self, ea, expr)
    self.true = true
    self.false = false
    return

  def __eq__(self, other):
    return type(other) == branch_t and self.expr == other.expr and \
            self.true == other.true and self.false == other.false

  def __repr__(self):
    return '<%s branch %s true:%s false:%s>' % (hex(self.ea) if self.ea else '~',
      repr(self.expr), repr(self.true), repr(self.false))

  def __hash__(self):
    return hash((self.__class__, self.expr, self.true, self.false))

  def copy(self):
    return self.__class__(self.ea, self.expr.copy(), self.true.copy(), self.false.copy())

  @property
  def expressions(self):
    """ by default, statements contain only one expression. some statements may contain
        no expressions (break, continue) and others may contain many (for loops, ...). """
    yield self.expr
    yield self.true
    yield self.false
    return

class return_t(statement_t):
  def __init__(self, ea, expr=None):
    statement_t.__init__(self, ea, expr)
    return

  def __repr__(self):
    return '<%s return %s>' % (hex(self.ea) if self.ea else '~',
      repr(self.expr) if self.expr else 'void', )

  @property
  def expressions(self):
    if self.expr:
      yield self.expr

class break_t(statement_t):
  def __init__(self, ea):
    statement_t.__init__(self, ea, None)
    return

  def __repr__(self):
    return '<%s break>' % (hex(self.ea) if self.ea else '~', )

  @property
  def expressions(self):
    """ no expressions """
    return

class continue_t(statement_t):
  def __init__(self, ea):
    statement_t.__init__(self, ea, None)
    return

  def __repr__(self):
    return '<%s continue>' % (hex(self.ea) if self.ea else '~', )

  @property
  def expressions(self):
    """ no expressions """
    return