tree_ir.py 9.2 KB

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