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 seperate module.
10 from ExprNodes import AtomicExprNode
11 from PyrexTypes import c_ptr_type
13 class TempHandle(object):
14 # THIS IS DEPRECATED, USE LetRefNode instead
17 def __init__(self, type):
19 self.needs_cleanup = type.is_pyobject
22 return TempRefNode(pos, handle=self, type=self.type)
24 def cleanup_ref(self, pos):
25 return CleanupTempRefNode(pos, handle=self, type=self.type)
27 class TempRefNode(AtomicExprNode):
28 # THIS IS DEPRECATED, USE LetRefNode instead
31 def analyse_types(self, env):
32 assert self.type == self.handle.type
34 def analyse_target_types(self, env):
35 assert self.type == self.handle.type
37 def analyse_target_declaration(self, env):
40 def calculate_result_code(self):
41 result = self.handle.temp
42 if result is None: result = "<error>" # might be called and overwritten
45 def generate_result_code(self, code):
48 def generate_assignment_code(self, rhs, code):
49 if self.type.is_pyobject:
50 rhs.make_owned_reference(code)
51 # TODO: analyse control flow to see if this is necessary
52 code.put_xdecref(self.result(), self.ctype())
53 code.putln('%s = %s;' % (self.result(), rhs.result_as(self.ctype())))
54 rhs.generate_post_assignment_code(code)
57 class CleanupTempRefNode(TempRefNode):
58 # THIS IS DEPRECATED, USE LetRefNode instead
61 def generate_assignment_code(self, rhs, code):
64 def generate_execution_code(self, code):
65 if self.type.is_pyobject:
66 code.put_decref_clear(self.result(), self.type)
67 self.handle.needs_cleanup = False
69 class TempsBlockNode(Node):
70 # THIS IS DEPRECATED, USE LetNode instead
73 Creates a block which allocates temporary variables.
74 This is used by transforms to output constructs that need
75 to make use of a temporary variable. Simply pass the types
76 of the needed temporaries to the constructor.
78 The variables can be referred to using a TempRefNode
79 (which can be constructed by calling get_ref_node).
85 child_attrs = ["body"]
87 def generate_execution_code(self, code):
88 for handle in self.temps:
89 handle.temp = code.funcstate.allocate_temp(
90 handle.type, manage_ref=handle.needs_cleanup)
91 self.body.generate_execution_code(code)
92 for handle in self.temps:
93 if handle.needs_cleanup:
94 if handle.needs_xdecref:
95 code.put_xdecref_clear(handle.temp, handle.type)
97 code.put_decref_clear(handle.temp, handle.type)
98 code.funcstate.release_temp(handle.temp)
100 def analyse_control_flow(self, env):
101 self.body.analyse_control_flow(env)
103 def analyse_declarations(self, env):
104 self.body.analyse_declarations(env)
106 def analyse_expressions(self, env):
107 self.body.analyse_expressions(env)
109 def generate_function_definitions(self, env, code):
110 self.body.generate_function_definitions(env, code)
112 def annotate(self, code):
113 self.body.annotate(code)
116 class ResultRefNode(AtomicExprNode):
117 # A reference to the result of an expression. The result_code
118 # must be set externally (usually a temp name).
121 lhs_of_first_assignment = False
123 def __init__(self, expression=None, pos=None, type=None, may_hold_none=True):
124 self.expression = expression
126 self.may_hold_none = may_hold_none
127 if expression is not None:
128 self.pos = expression.pos
129 if hasattr(expression, "type"):
130 self.type = expression.type
135 assert self.pos is not None
137 def clone_node(self):
141 def analyse_types(self, env):
142 if self.expression is not None:
143 self.type = self.expression.type
145 def infer_type(self, env):
146 if self.expression is not None:
147 return self.expression.infer_type(env)
148 if self.type is not None:
150 assert False, "cannot infer type of ResultRefNode"
152 def may_be_none(self):
153 if not self.type.is_pyobject:
155 return self.may_hold_none
157 def _DISABLED_may_be_none(self):
158 # not sure if this is safe - the expression may not be the
159 # only value that gets assigned
160 if self.expression is not None:
161 return self.expression.may_be_none()
162 if self.type is not None:
163 return self.type.is_pyobject
164 return True # play safe
171 return self.result_code
172 except AttributeError:
173 if self.expression is not None:
174 self.result_code = self.expression.result()
175 return self.result_code
177 def generate_evaluation_code(self, code):
180 def generate_result_code(self, code):
183 def generate_disposal_code(self, code):
186 def generate_assignment_code(self, rhs, code):
187 if self.type.is_pyobject:
188 rhs.make_owned_reference(code)
189 if not self.lhs_of_first_assignment:
190 code.put_decref(self.result(), self.ctype())
191 code.putln('%s = %s;' % (self.result(), rhs.result_as(self.ctype())))
192 rhs.generate_post_assignment_code(code)
195 def allocate_temps(self, env):
198 def release_temp(self, env):
201 def free_temps(self, code):
206 def set_temp_expr(self, lazy_temp):
207 self.lazy_temp = lazy_temp
208 self.temp_expression = lazy_temp.expression
210 def setup_temp_expr(self, code):
211 self.temp_expression.generate_evaluation_code(code)
212 self.temp_type = self.temp_expression.type
213 if self.temp_type.is_array:
214 self.temp_type = c_ptr_type(self.temp_type.base_type)
215 self._result_in_temp = self.temp_expression.result_in_temp()
216 if self._result_in_temp:
217 self.temp = self.temp_expression.result()
219 self.temp_expression.make_owned_reference(code)
220 self.temp = code.funcstate.allocate_temp(
221 self.temp_type, manage_ref=True)
222 code.putln("%s = %s;" % (self.temp, self.temp_expression.result()))
223 self.temp_expression.generate_disposal_code(code)
224 self.temp_expression.free_temps(code)
225 self.lazy_temp.result_code = self.temp
227 def teardown_temp_expr(self, code):
228 if self._result_in_temp:
229 self.temp_expression.generate_disposal_code(code)
230 self.temp_expression.free_temps(code)
232 if self.temp_type.is_pyobject:
233 code.put_decref_clear(self.temp, self.temp_type)
234 code.funcstate.release_temp(self.temp)
236 class EvalWithTempExprNode(ExprNodes.ExprNode, LetNodeMixin):
237 # A wrapper around a subexpression that moves an expression into a
238 # temp variable and provides it to the subexpression.
240 subexprs = ['temp_expression', 'subexpression']
242 def __init__(self, lazy_temp, subexpression):
243 self.set_temp_expr(lazy_temp)
244 self.pos = subexpression.pos
245 self.subexpression = subexpression
246 # if called after type analysis, we already know the type here
247 self.type = self.subexpression.type
249 def infer_type(self, env):
250 return self.subexpression.infer_type(env)
253 return self.subexpression.result()
255 def analyse_types(self, env):
256 self.temp_expression.analyse_types(env)
257 self.subexpression.analyse_types(env)
258 self.type = self.subexpression.type
260 def free_subexpr_temps(self, code):
261 self.subexpression.free_temps(code)
263 def generate_subexpr_disposal_code(self, code):
264 self.subexpression.generate_disposal_code(code)
266 def generate_evaluation_code(self, code):
267 self.setup_temp_expr(code)
268 self.subexpression.generate_evaluation_code(code)
269 self.teardown_temp_expr(code)
271 LetRefNode = ResultRefNode
273 class LetNode(Nodes.StatNode, LetNodeMixin):
274 # Implements a local temporary variable scope. Imagine this
275 # syntax being present:
277 # BLOCK (can modify temp)
278 # if temp is an object, decref
280 # Usually used after analysis phase, but forwards analysis methods
283 child_attrs = ['temp_expression', 'body']
285 def __init__(self, lazy_temp, body):
286 self.set_temp_expr(lazy_temp)
290 def analyse_control_flow(self, env):
291 self.body.analyse_control_flow(env)
293 def analyse_declarations(self, env):
294 self.temp_expression.analyse_declarations(env)
295 self.body.analyse_declarations(env)
297 def analyse_expressions(self, env):
298 self.temp_expression.analyse_expressions(env)
299 self.body.analyse_expressions(env)
301 def generate_execution_code(self, code):
302 self.setup_temp_expr(code)
303 self.body.generate_execution_code(code)
304 self.teardown_temp_expr(code)
306 class TempResultFromStatNode(ExprNodes.ExprNode):
307 # An ExprNode wrapper around a StatNode that executes the StatNode
308 # body. Requires a ResultRefNode that it sets up to refer to its
309 # own temp result. The StatNode must assign a value to the result
310 # node, which then becomes the result of this node.
313 child_attrs = ['body']
315 def __init__(self, result_ref, body):
316 self.result_ref = result_ref
319 self.type = result_ref.type
322 def analyse_declarations(self, env):
323 self.body.analyse_declarations(env)
325 def analyse_types(self, env):
326 self.body.analyse_expressions(env)
328 def generate_result_code(self, code):
329 self.result_ref.result_code = self.result()
330 self.body.generate_execution_code(code)