UtilNodes.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. #
  2. # Nodes used as utilities and support for transforms etc.
  3. # These often make up sets including both Nodes and ExprNodes
  4. # so it is convenient to have them in a separate module.
  5. #
  6. from __future__ import absolute_import
  7. from . import Nodes
  8. from . import ExprNodes
  9. from .Nodes import Node
  10. from .ExprNodes import AtomicExprNode
  11. from .PyrexTypes import c_ptr_type
  12. class TempHandle(object):
  13. # THIS IS DEPRECATED, USE LetRefNode instead
  14. temp = None
  15. needs_xdecref = False
  16. def __init__(self, type, needs_cleanup=None):
  17. self.type = type
  18. if needs_cleanup is None:
  19. self.needs_cleanup = type.is_pyobject
  20. else:
  21. self.needs_cleanup = needs_cleanup
  22. def ref(self, pos):
  23. return TempRefNode(pos, handle=self, type=self.type)
  24. class TempRefNode(AtomicExprNode):
  25. # THIS IS DEPRECATED, USE LetRefNode instead
  26. # handle TempHandle
  27. def analyse_types(self, env):
  28. assert self.type == self.handle.type
  29. return self
  30. def analyse_target_types(self, env):
  31. assert self.type == self.handle.type
  32. return self
  33. def analyse_target_declaration(self, env):
  34. pass
  35. def calculate_result_code(self):
  36. result = self.handle.temp
  37. if result is None: result = "<error>" # might be called and overwritten
  38. return result
  39. def generate_result_code(self, code):
  40. pass
  41. def generate_assignment_code(self, rhs, code, overloaded_assignment=False):
  42. if self.type.is_pyobject:
  43. rhs.make_owned_reference(code)
  44. # TODO: analyse control flow to see if this is necessary
  45. code.put_xdecref(self.result(), self.ctype())
  46. code.putln('%s = %s;' % (
  47. self.result(),
  48. rhs.result() if overloaded_assignment else rhs.result_as(self.ctype()),
  49. ))
  50. rhs.generate_post_assignment_code(code)
  51. rhs.free_temps(code)
  52. class TempsBlockNode(Node):
  53. # THIS IS DEPRECATED, USE LetNode instead
  54. """
  55. Creates a block which allocates temporary variables.
  56. This is used by transforms to output constructs that need
  57. to make use of a temporary variable. Simply pass the types
  58. of the needed temporaries to the constructor.
  59. The variables can be referred to using a TempRefNode
  60. (which can be constructed by calling get_ref_node).
  61. """
  62. # temps [TempHandle]
  63. # body StatNode
  64. child_attrs = ["body"]
  65. def generate_execution_code(self, code):
  66. for handle in self.temps:
  67. handle.temp = code.funcstate.allocate_temp(
  68. handle.type, manage_ref=handle.needs_cleanup)
  69. self.body.generate_execution_code(code)
  70. for handle in self.temps:
  71. if handle.needs_cleanup:
  72. if handle.needs_xdecref:
  73. code.put_xdecref_clear(handle.temp, handle.type)
  74. else:
  75. code.put_decref_clear(handle.temp, handle.type)
  76. code.funcstate.release_temp(handle.temp)
  77. def analyse_declarations(self, env):
  78. self.body.analyse_declarations(env)
  79. def analyse_expressions(self, env):
  80. self.body = self.body.analyse_expressions(env)
  81. return self
  82. def generate_function_definitions(self, env, code):
  83. self.body.generate_function_definitions(env, code)
  84. def annotate(self, code):
  85. self.body.annotate(code)
  86. class ResultRefNode(AtomicExprNode):
  87. # A reference to the result of an expression. The result_code
  88. # must be set externally (usually a temp name).
  89. subexprs = []
  90. lhs_of_first_assignment = False
  91. def __init__(self, expression=None, pos=None, type=None, may_hold_none=True, is_temp=False):
  92. self.expression = expression
  93. self.pos = None
  94. self.may_hold_none = may_hold_none
  95. if expression is not None:
  96. self.pos = expression.pos
  97. if hasattr(expression, "type"):
  98. self.type = expression.type
  99. if pos is not None:
  100. self.pos = pos
  101. if type is not None:
  102. self.type = type
  103. if is_temp:
  104. self.is_temp = True
  105. assert self.pos is not None
  106. def clone_node(self):
  107. # nothing to do here
  108. return self
  109. def type_dependencies(self, env):
  110. if self.expression:
  111. return self.expression.type_dependencies(env)
  112. else:
  113. return ()
  114. def update_expression(self, expression):
  115. self.expression = expression
  116. if hasattr(expression, "type"):
  117. self.type = expression.type
  118. def analyse_types(self, env):
  119. if self.expression is not None:
  120. if not self.expression.type:
  121. self.expression = self.expression.analyse_types(env)
  122. self.type = self.expression.type
  123. return self
  124. def infer_type(self, env):
  125. if self.type is not None:
  126. return self.type
  127. if self.expression is not None:
  128. if self.expression.type is not None:
  129. return self.expression.type
  130. return self.expression.infer_type(env)
  131. assert False, "cannot infer type of ResultRefNode"
  132. def may_be_none(self):
  133. if not self.type.is_pyobject:
  134. return False
  135. return self.may_hold_none
  136. def _DISABLED_may_be_none(self):
  137. # not sure if this is safe - the expression may not be the
  138. # only value that gets assigned
  139. if self.expression is not None:
  140. return self.expression.may_be_none()
  141. if self.type is not None:
  142. return self.type.is_pyobject
  143. return True # play safe
  144. def is_simple(self):
  145. return True
  146. def result(self):
  147. try:
  148. return self.result_code
  149. except AttributeError:
  150. if self.expression is not None:
  151. self.result_code = self.expression.result()
  152. return self.result_code
  153. def generate_evaluation_code(self, code):
  154. pass
  155. def generate_result_code(self, code):
  156. pass
  157. def generate_disposal_code(self, code):
  158. pass
  159. def generate_assignment_code(self, rhs, code, overloaded_assignment=False):
  160. if self.type.is_pyobject:
  161. rhs.make_owned_reference(code)
  162. if not self.lhs_of_first_assignment:
  163. code.put_decref(self.result(), self.ctype())
  164. code.putln('%s = %s;' % (
  165. self.result(),
  166. rhs.result() if overloaded_assignment else rhs.result_as(self.ctype()),
  167. ))
  168. rhs.generate_post_assignment_code(code)
  169. rhs.free_temps(code)
  170. def allocate_temps(self, env):
  171. pass
  172. def release_temp(self, env):
  173. pass
  174. def free_temps(self, code):
  175. pass
  176. class LetNodeMixin:
  177. def set_temp_expr(self, lazy_temp):
  178. self.lazy_temp = lazy_temp
  179. self.temp_expression = lazy_temp.expression
  180. def setup_temp_expr(self, code):
  181. self.temp_expression.generate_evaluation_code(code)
  182. self.temp_type = self.temp_expression.type
  183. if self.temp_type.is_array:
  184. self.temp_type = c_ptr_type(self.temp_type.base_type)
  185. self._result_in_temp = self.temp_expression.result_in_temp()
  186. if self._result_in_temp:
  187. self.temp = self.temp_expression.result()
  188. else:
  189. self.temp_expression.make_owned_reference(code)
  190. self.temp = code.funcstate.allocate_temp(
  191. self.temp_type, manage_ref=True)
  192. code.putln("%s = %s;" % (self.temp, self.temp_expression.result()))
  193. self.temp_expression.generate_disposal_code(code)
  194. self.temp_expression.free_temps(code)
  195. self.lazy_temp.result_code = self.temp
  196. def teardown_temp_expr(self, code):
  197. if self._result_in_temp:
  198. self.temp_expression.generate_disposal_code(code)
  199. self.temp_expression.free_temps(code)
  200. else:
  201. if self.temp_type.is_pyobject:
  202. code.put_decref_clear(self.temp, self.temp_type)
  203. code.funcstate.release_temp(self.temp)
  204. class EvalWithTempExprNode(ExprNodes.ExprNode, LetNodeMixin):
  205. # A wrapper around a subexpression that moves an expression into a
  206. # temp variable and provides it to the subexpression.
  207. subexprs = ['temp_expression', 'subexpression']
  208. def __init__(self, lazy_temp, subexpression):
  209. self.set_temp_expr(lazy_temp)
  210. self.pos = subexpression.pos
  211. self.subexpression = subexpression
  212. # if called after type analysis, we already know the type here
  213. self.type = self.subexpression.type
  214. def infer_type(self, env):
  215. return self.subexpression.infer_type(env)
  216. def may_be_none(self):
  217. return self.subexpression.may_be_none()
  218. def result(self):
  219. return self.subexpression.result()
  220. def analyse_types(self, env):
  221. self.temp_expression = self.temp_expression.analyse_types(env)
  222. self.lazy_temp.update_expression(self.temp_expression) # overwrite in case it changed
  223. self.subexpression = self.subexpression.analyse_types(env)
  224. self.type = self.subexpression.type
  225. return self
  226. def free_subexpr_temps(self, code):
  227. self.subexpression.free_temps(code)
  228. def generate_subexpr_disposal_code(self, code):
  229. self.subexpression.generate_disposal_code(code)
  230. def generate_evaluation_code(self, code):
  231. self.setup_temp_expr(code)
  232. self.subexpression.generate_evaluation_code(code)
  233. self.teardown_temp_expr(code)
  234. LetRefNode = ResultRefNode
  235. class LetNode(Nodes.StatNode, LetNodeMixin):
  236. # Implements a local temporary variable scope. Imagine this
  237. # syntax being present:
  238. # let temp = VALUE:
  239. # BLOCK (can modify temp)
  240. # if temp is an object, decref
  241. #
  242. # Usually used after analysis phase, but forwards analysis methods
  243. # to its children
  244. child_attrs = ['temp_expression', 'body']
  245. def __init__(self, lazy_temp, body):
  246. self.set_temp_expr(lazy_temp)
  247. self.pos = body.pos
  248. self.body = body
  249. def analyse_declarations(self, env):
  250. self.temp_expression.analyse_declarations(env)
  251. self.body.analyse_declarations(env)
  252. def analyse_expressions(self, env):
  253. self.temp_expression = self.temp_expression.analyse_expressions(env)
  254. self.body = self.body.analyse_expressions(env)
  255. return self
  256. def generate_execution_code(self, code):
  257. self.setup_temp_expr(code)
  258. self.body.generate_execution_code(code)
  259. self.teardown_temp_expr(code)
  260. def generate_function_definitions(self, env, code):
  261. self.temp_expression.generate_function_definitions(env, code)
  262. self.body.generate_function_definitions(env, code)
  263. class TempResultFromStatNode(ExprNodes.ExprNode):
  264. # An ExprNode wrapper around a StatNode that executes the StatNode
  265. # body. Requires a ResultRefNode that it sets up to refer to its
  266. # own temp result. The StatNode must assign a value to the result
  267. # node, which then becomes the result of this node.
  268. subexprs = []
  269. child_attrs = ['body']
  270. def __init__(self, result_ref, body):
  271. self.result_ref = result_ref
  272. self.pos = body.pos
  273. self.body = body
  274. self.type = result_ref.type
  275. self.is_temp = 1
  276. def analyse_declarations(self, env):
  277. self.body.analyse_declarations(env)
  278. def analyse_types(self, env):
  279. self.body = self.body.analyse_expressions(env)
  280. return self
  281. def generate_result_code(self, code):
  282. self.result_ref.result_code = self.result()
  283. self.body.generate_execution_code(code)