ir.py 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. class Instruction(object):
  2. """A base class for instructions. An instruction is essentially a syntax
  3. node that must first be defined, and can only then be used."""
  4. def __init__(self):
  5. pass
  6. def has_result(self):
  7. """Tells if this instruction computes a result."""
  8. return True
  9. def generate_python_def(self, code_generator):
  10. """Generates a Python statement that executes this instruction.
  11. The statement is appended immediately to the code generator."""
  12. raise NotImplementedError
  13. def generate_python_use(self, code_generator):
  14. """Generates a Python expression that retrieves this instruction's
  15. result. The expression is returned as a string."""
  16. if self.has_result():
  17. return code_generator.get_result_name(self)
  18. else:
  19. return 'None'
  20. def simplify(self):
  21. """Applies basic simplification to this instruction and its children."""
  22. return self
  23. def __str__(self):
  24. cg = PythonGenerator()
  25. self.generate_python_def(cg)
  26. return cg.code
  27. class PythonGenerator(object):
  28. """Generates Python code from instructions."""
  29. def __init__(self):
  30. self.code = ''
  31. self.indentation_string = ' ' * 4
  32. self.indentation = 0
  33. self.result_value_dict = {}
  34. def append(self, text):
  35. """Appends the given string to this code generator."""
  36. self.code += text
  37. def append_indentation(self):
  38. """Appends indentation to the code generator."""
  39. self.append(self.indentation_string * self.indentation)
  40. def append_line(self, line = None):
  41. """Appends the indentation string followed by the given string (if any)
  42. and a newline to the code generator."""
  43. self.append_indentation()
  44. if line is not None:
  45. self.append(line)
  46. self.append('\n')
  47. def increase_indentation(self):
  48. """Increases the code generator's indentation by one indent."""
  49. self.indentation += 1
  50. def decrease_indentation(self):
  51. """Decreases the code generator's indentation by one indent."""
  52. self.indentation -= 1
  53. def get_result_name(self, instruction):
  54. """Gets the name of the given instruction's result variable."""
  55. if instruction not in self.result_value_dict:
  56. self.result_value_dict[instruction] = \
  57. 'tmp' + str(len(self.result_value_dict))
  58. return self.result_value_dict[instruction]
  59. def append_definition(self, lhs, rhs):
  60. """Defines the first instruction's result variable as the second
  61. instruction's result."""
  62. self.append_line(
  63. self.get_result_name(lhs) + ' = ' + rhs.generate_python_use(self))
  64. class VoidInstruction(Instruction):
  65. """A base class for instructions that do not return a value."""
  66. def has_result(self):
  67. """Tells if this instruction computes a result."""
  68. return False
  69. class EmptyInstruction(VoidInstruction):
  70. """Represents the empty instruction, which does nothing."""
  71. def generate_python_def(self, code_generator):
  72. code_generator.append_line('pass')
  73. class SelectInstruction(Instruction):
  74. """Represents a select-instruction: an instruction that defines one of two
  75. child instructions, and sets its result to the defined child's result."""
  76. def __init__(self, condition, if_clause, else_clause):
  77. Instruction.__init__(self)
  78. self.condition = condition
  79. self.if_clause = if_clause
  80. self.else_clause = else_clause
  81. def has_result(self):
  82. """Tells if this instruction computes a result."""
  83. return self.if_clause.has_result() or self.else_clause.has_result()
  84. def simplify(self):
  85. """Applies basic simplification to this instruction and its children."""
  86. simple_cond = self.condition.simplify()
  87. simple_if = self.if_clause.simplify()
  88. simple_else = self.else_clause.simplify()
  89. return SelectInstruction(simple_cond, simple_if, simple_else)
  90. def generate_python_def(self, code_generator):
  91. """Generates Python code for this instruction."""
  92. if_has_result = self.has_result()
  93. if not isinstance(self.condition, EmptyInstruction):
  94. self.condition.generate_python_def(code_generator)
  95. code_generator.append_line(
  96. 'if ' + self.condition.generate_python_use(code_generator) + ':')
  97. code_generator.increase_indentation()
  98. self.if_clause.generate_python_def(code_generator)
  99. if if_has_result:
  100. code_generator.append_definition(self, self.if_clause)
  101. code_generator.decrease_indentation()
  102. if not isinstance(self.else_clause, EmptyInstruction) or if_has_result:
  103. code_generator.append_line('else:')
  104. code_generator.increase_indentation()
  105. self.else_clause.generate_python_def(code_generator)
  106. if if_has_result:
  107. code_generator.append_definition(self, self.else_clause)
  108. code_generator.decrease_indentation()
  109. class ReturnInstruction(VoidInstruction):
  110. """Represents a return-instruction."""
  111. def __init__(self, value):
  112. Instruction.__init__(self)
  113. self.value = value
  114. def simplify(self):
  115. """Applies basic simplification to this instruction and its children."""
  116. return LoopInstruction(self.value.simplify())
  117. def generate_python_def(self, code_generator):
  118. """Generates Python code for this instruction."""
  119. code_generator.append_line(
  120. 'raise PrimitiveFinished(' +
  121. self.value.generate_python_use(code_generator) +
  122. ')')
  123. class LoopInstruction(VoidInstruction):
  124. """Represents a loop-instruction, which loops until broken."""
  125. def __init__(self, body):
  126. Instruction.__init__(self)
  127. self.body = body
  128. def simplify(self):
  129. """Applies basic simplification to this instruction and its children."""
  130. return LoopInstruction(self.body.simplify())
  131. def generate_python_def(self, code_generator):
  132. """Generates Python code for this instruction."""
  133. code_generator.append_line('while True:')
  134. code_generator.increase_indentation()
  135. self.body.generate_python_def(code_generator)
  136. code_generator.decrease_indentation()
  137. class BreakInstruction(VoidInstruction):
  138. """Represents a break-instruction."""
  139. def generate_python_def(self, code_generator):
  140. """Generates Python code for this instruction."""
  141. code_generator.append_line('break')
  142. class ContinueInstruction(VoidInstruction):
  143. """Represents a continue-instruction."""
  144. def generate_python_def(self, code_generator):
  145. """Generates Python code for this instruction."""
  146. code_generator.append_line('continue')
  147. class CompoundInstruction(VoidInstruction):
  148. """Represents an instruction that evaluates two other instructions
  149. in order."""
  150. def __init__(self, first, second):
  151. Instruction.__init__(self)
  152. self.first = first
  153. self.second = second
  154. def simplify(self):
  155. """Applies basic simplification to this instruction and its children."""
  156. simple_fst, simple_snd = self.first.simplify(), self.second.simplify()
  157. if isinstance(simple_snd, EmptyInstruction):
  158. return simple_fst
  159. elif isinstance(simple_snd, EmptyInstruction):
  160. return simple_snd
  161. else:
  162. return CompoundInstruction(simple_fst, simple_snd)
  163. def generate_python_def(self, code_generator):
  164. """Generates Python code for this instruction."""
  165. if isinstance(self.second, EmptyInstruction):
  166. self.first.generate_python_def(code_generator)
  167. elif isinstance(self.first, EmptyInstruction):
  168. self.second.generate_python_def(code_generator)
  169. else:
  170. self.first.generate_python_def(code_generator)
  171. self.second.generate_python_def(code_generator)
  172. if __name__ == "__main__":
  173. exampleTree = SelectInstruction(
  174. EmptyInstruction(),
  175. LoopInstruction(
  176. CompoundInstruction(
  177. BreakInstruction(),
  178. ContinueInstruction()
  179. )
  180. ),
  181. ReturnInstruction(
  182. EmptyInstruction()))
  183. print(exampleTree)