tree_ir.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  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. def append_state_definition(self, lhs, opcode, args):
  71. """Appends a definition that queries the modelverse state."""
  72. self.append_line(
  73. "%s, = yield [('%s', [%s])]" % (
  74. self.get_result_name(lhs),
  75. opcode,
  76. ', '.join([arg_i.generate_python_use(self) for arg_i in args])))
  77. class VoidInstruction(Instruction):
  78. """A base class for instructions that do not return a value."""
  79. def has_result(self):
  80. """Tells if this instruction computes a result."""
  81. return False
  82. class EmptyInstruction(VoidInstruction):
  83. """Represents the empty instruction, which does nothing."""
  84. def has_definition(self):
  85. """Tells if this instruction requires a definition."""
  86. return False
  87. class SelectInstruction(Instruction):
  88. """Represents a select-instruction: an instruction that defines one of two
  89. child instructions, and sets its result to the defined child's result."""
  90. def __init__(self, condition, if_clause, else_clause):
  91. Instruction.__init__(self)
  92. self.condition = condition
  93. self.if_clause = if_clause
  94. self.else_clause = else_clause
  95. def has_result(self):
  96. """Tells if this instruction computes a result."""
  97. return self.if_clause.has_result() or self.else_clause.has_result()
  98. def simplify(self):
  99. """Applies basic simplification to this instruction and its children."""
  100. simple_cond = self.condition.simplify()
  101. simple_if = self.if_clause.simplify()
  102. simple_else = self.else_clause.simplify()
  103. if isinstance(simple_cond, LiteralInstruction):
  104. return simple_if if simple_cond.literal else simple_else
  105. else:
  106. return SelectInstruction(simple_cond, simple_if, simple_else)
  107. def generate_python_def(self, code_generator):
  108. """Generates Python code for this instruction."""
  109. if_has_result = self.has_result()
  110. if self.condition.has_definition():
  111. self.condition.generate_python_def(code_generator)
  112. code_generator.append_line(
  113. 'if ' + self.condition.generate_python_use(code_generator) + ':')
  114. code_generator.increase_indentation()
  115. self.if_clause.generate_python_def(code_generator)
  116. if if_has_result:
  117. code_generator.append_definition(self, self.if_clause)
  118. code_generator.decrease_indentation()
  119. if self.else_clause.has_definition() or if_has_result:
  120. code_generator.append_line('else:')
  121. code_generator.increase_indentation()
  122. self.else_clause.generate_python_def(code_generator)
  123. if if_has_result:
  124. code_generator.append_definition(self, self.else_clause)
  125. code_generator.decrease_indentation()
  126. class ReturnInstruction(VoidInstruction):
  127. """Represents a return-instruction."""
  128. def __init__(self, value):
  129. VoidInstruction.__init__(self)
  130. self.value = value
  131. def simplify(self):
  132. """Applies basic simplification to this instruction and its children."""
  133. return LoopInstruction(self.value.simplify())
  134. def generate_python_def(self, code_generator):
  135. """Generates Python code for this instruction."""
  136. code_generator.append_line(
  137. 'raise PrimitiveFinished(' +
  138. self.value.generate_python_use(code_generator) +
  139. ')')
  140. class LoopInstruction(VoidInstruction):
  141. """Represents a loop-instruction, which loops until broken."""
  142. def __init__(self, body):
  143. VoidInstruction.__init__(self)
  144. self.body = body
  145. def simplify(self):
  146. """Applies basic simplification to this instruction and its children."""
  147. return LoopInstruction(self.body.simplify())
  148. def generate_python_def(self, code_generator):
  149. """Generates Python code for this instruction."""
  150. code_generator.append_line('while True:')
  151. code_generator.increase_indentation()
  152. self.body.generate_python_def(code_generator)
  153. code_generator.decrease_indentation()
  154. class BreakInstruction(VoidInstruction):
  155. """Represents a break-instruction."""
  156. def generate_python_def(self, code_generator):
  157. """Generates Python code for this instruction."""
  158. code_generator.append_line('break')
  159. class ContinueInstruction(VoidInstruction):
  160. """Represents a continue-instruction."""
  161. def generate_python_def(self, code_generator):
  162. """Generates Python code for this instruction."""
  163. code_generator.append_line('continue')
  164. class CompoundInstruction(Instruction):
  165. """Represents an instruction that evaluates two other instructions
  166. in order, and returns the second instruction's result."""
  167. def __init__(self, first, second):
  168. Instruction.__init__(self)
  169. self.first = first
  170. self.second = second
  171. def has_result(self):
  172. """Tells if this instruction has a result."""
  173. return self.second.has_result()
  174. def simplify(self):
  175. """Applies basic simplification to this instruction and its children."""
  176. simple_fst, simple_snd = self.first.simplify(), self.second.simplify()
  177. if not simple_fst.has_definition():
  178. return simple_snd
  179. elif (not simple_snd.has_definition()) and (not simple_snd.has_result()):
  180. return simple_fst
  181. else:
  182. return CompoundInstruction(simple_fst, simple_snd)
  183. def generate_python_def(self, code_generator):
  184. """Generates Python code for this instruction."""
  185. self.first.generate_python_def(code_generator)
  186. self.second.generate_python_def(code_generator)
  187. if self.has_result():
  188. code_generator.append_definition(self, self.second)
  189. class LiteralInstruction(Instruction):
  190. """Represents an integer, floating-point, string or Boolean literal."""
  191. def __init__(self, literal):
  192. Instruction.__init__(self)
  193. self.literal = literal
  194. def has_definition(self):
  195. """Tells if this instruction requires a definition."""
  196. return False
  197. def generate_python_use(self, code_generator):
  198. """Generates a Python expression that retrieves this instruction's
  199. result. The expression is returned as a string."""
  200. return repr(self.literal)
  201. class StateInstruction(Instruction):
  202. """An instruction that accesses the modelverse state."""
  203. def get_opcode(self):
  204. """Gets the opcode for this state instruction."""
  205. raise NotImplementedError()
  206. def get_arguments(self):
  207. """Gets this state instruction's argument list."""
  208. raise NotImplementedError()
  209. def generate_python_def(self, code_generator):
  210. """Generates a Python statement that executes this instruction.
  211. The statement is appended immediately to the code generator."""
  212. args = self.get_arguments()
  213. for arg_i in args:
  214. if arg_i.has_definition():
  215. arg_i.generate_python_def(code_generator)
  216. code_generator.append_state_definition(self, self.get_opcode(), args)
  217. class ReadValueInstruction(StateInstruction):
  218. """An instruction that reads a value from a node."""
  219. def __init__(self, node_id):
  220. StateInstruction.__init__(self)
  221. self.node_id = node_id
  222. def simplify(self):
  223. """Applies basic simplification to this instruction and its children."""
  224. return ReadValueInstruction(self.node_id.simplify())
  225. def get_opcode(self):
  226. """Gets the opcode for this state instruction."""
  227. return "RV"
  228. def get_arguments(self):
  229. """Gets this state instruction's argument list."""
  230. return [self.node_id]
  231. if __name__ == "__main__":
  232. example_tree = SelectInstruction(
  233. LiteralInstruction(True),
  234. LoopInstruction(
  235. CompoundInstruction(
  236. BreakInstruction(),
  237. CompoundInstruction(
  238. EmptyInstruction(),
  239. ContinueInstruction()
  240. )
  241. )
  242. ),
  243. ReturnInstruction(
  244. EmptyInstruction()))
  245. print(example_tree.simplify())