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, needs_cleanup
=None):
19 if needs_cleanup
is None:
20 self
.needs_cleanup
= type.is_pyobject
22 self
.needs_cleanup
= needs_cleanup
25 return TempRefNode(pos
, handle
=self
, type=self
.type)
27 def cleanup_ref(self
, pos
):
28 return CleanupTempRefNode(pos
, handle
=self
, type=self
.type)
30 class TempRefNode(AtomicExprNode
):
31 # THIS IS DEPRECATED, USE LetRefNode instead
34 def analyse_types(self
, env
):
35 assert self
.type == self
.handle
.type
38 def analyse_target_types(self
, env
):
39 assert self
.type == self
.handle
.type
42 def analyse_target_declaration(self
, env
):
45 def calculate_result_code(self
):
46 result
= self
.handle
.temp
47 if result
is None: result
= "<error>" # might be called and overwritten
50 def generate_result_code(self
, code
):
53 def generate_assignment_code(self
, rhs
, code
):
54 if self
.type.is_pyobject
:
55 rhs
.make_owned_reference(code
)
56 # TODO: analyse control flow to see if this is necessary
57 code
.put_xdecref(self
.result(), self
.ctype())
58 code
.putln('%s = %s;' % (self
.result(), rhs
.result_as(self
.ctype())))
59 rhs
.generate_post_assignment_code(code
)
62 class CleanupTempRefNode(TempRefNode
):
63 # THIS IS DEPRECATED, USE LetRefNode instead
66 def generate_assignment_code(self
, rhs
, code
):
69 def generate_execution_code(self
, code
):
70 if self
.type.is_pyobject
:
71 code
.put_decref_clear(self
.result(), self
.type)
72 self
.handle
.needs_cleanup
= False
74 class TempsBlockNode(Node
):
75 # THIS IS DEPRECATED, USE LetNode instead
78 Creates a block which allocates temporary variables.
79 This is used by transforms to output constructs that need
80 to make use of a temporary variable. Simply pass the types
81 of the needed temporaries to the constructor.
83 The variables can be referred to using a TempRefNode
84 (which can be constructed by calling get_ref_node).
90 child_attrs
= ["body"]
92 def generate_execution_code(self
, code
):
93 for handle
in self
.temps
:
94 handle
.temp
= code
.funcstate
.allocate_temp(
95 handle
.type, manage_ref
=handle
.needs_cleanup
)
96 self
.body
.generate_execution_code(code
)
97 for handle
in self
.temps
:
98 if handle
.needs_cleanup
:
99 if handle
.needs_xdecref
:
100 code
.put_xdecref_clear(handle
.temp
, handle
.type)
102 code
.put_decref_clear(handle
.temp
, handle
.type)
103 code
.funcstate
.release_temp(handle
.temp
)
105 def analyse_declarations(self
, env
):
106 self
.body
.analyse_declarations(env
)
108 def analyse_expressions(self
, env
):
109 self
.body
= self
.body
.analyse_expressions(env
)
112 def generate_function_definitions(self
, env
, code
):
113 self
.body
.generate_function_definitions(env
, code
)
115 def annotate(self
, code
):
116 self
.body
.annotate(code
)
119 class ResultRefNode(AtomicExprNode
):
120 # A reference to the result of an expression. The result_code
121 # must be set externally (usually a temp name).
124 lhs_of_first_assignment
= False
126 def __init__(self
, expression
=None, pos
=None, type=None, may_hold_none
=True, is_temp
=False):
127 self
.expression
= expression
129 self
.may_hold_none
= may_hold_none
130 if expression
is not None:
131 self
.pos
= expression
.pos
132 if hasattr(expression
, "type"):
133 self
.type = expression
.type
140 assert self
.pos
is not None
142 def clone_node(self
):
146 def type_dependencies(self
, env
):
148 return self
.expression
.type_dependencies(env
)
152 def analyse_types(self
, env
):
153 if self
.expression
is not None:
154 self
.type = self
.expression
.type
157 def infer_type(self
, env
):
158 if self
.type is not None:
160 if self
.expression
is not None:
161 if self
.expression
.type is not None:
162 return self
.expression
.type
163 return self
.expression
.infer_type(env
)
164 assert False, "cannot infer type of ResultRefNode"
166 def may_be_none(self
):
167 if not self
.type.is_pyobject
:
169 return self
.may_hold_none
171 def _DISABLED_may_be_none(self
):
172 # not sure if this is safe - the expression may not be the
173 # only value that gets assigned
174 if self
.expression
is not None:
175 return self
.expression
.may_be_none()
176 if self
.type is not None:
177 return self
.type.is_pyobject
178 return True # play safe
185 return self
.result_code
186 except AttributeError:
187 if self
.expression
is not None:
188 self
.result_code
= self
.expression
.result()
189 return self
.result_code
191 def generate_evaluation_code(self
, code
):
194 def generate_result_code(self
, code
):
197 def generate_disposal_code(self
, code
):
200 def generate_assignment_code(self
, rhs
, code
):
201 if self
.type.is_pyobject
:
202 rhs
.make_owned_reference(code
)
203 if not self
.lhs_of_first_assignment
:
204 code
.put_decref(self
.result(), self
.ctype())
205 code
.putln('%s = %s;' % (self
.result(), rhs
.result_as(self
.ctype())))
206 rhs
.generate_post_assignment_code(code
)
209 def allocate_temps(self
, env
):
212 def release_temp(self
, env
):
215 def free_temps(self
, code
):
220 def set_temp_expr(self
, lazy_temp
):
221 self
.lazy_temp
= lazy_temp
222 self
.temp_expression
= lazy_temp
.expression
224 def setup_temp_expr(self
, code
):
225 self
.temp_expression
.generate_evaluation_code(code
)
226 self
.temp_type
= self
.temp_expression
.type
227 if self
.temp_type
.is_array
:
228 self
.temp_type
= c_ptr_type(self
.temp_type
.base_type
)
229 self
._result
_in
_temp
= self
.temp_expression
.result_in_temp()
230 if self
._result
_in
_temp
:
231 self
.temp
= self
.temp_expression
.result()
233 self
.temp_expression
.make_owned_reference(code
)
234 self
.temp
= code
.funcstate
.allocate_temp(
235 self
.temp_type
, manage_ref
=True)
236 code
.putln("%s = %s;" % (self
.temp
, self
.temp_expression
.result()))
237 self
.temp_expression
.generate_disposal_code(code
)
238 self
.temp_expression
.free_temps(code
)
239 self
.lazy_temp
.result_code
= self
.temp
241 def teardown_temp_expr(self
, code
):
242 if self
._result
_in
_temp
:
243 self
.temp_expression
.generate_disposal_code(code
)
244 self
.temp_expression
.free_temps(code
)
246 if self
.temp_type
.is_pyobject
:
247 code
.put_decref_clear(self
.temp
, self
.temp_type
)
248 code
.funcstate
.release_temp(self
.temp
)
250 class EvalWithTempExprNode(ExprNodes
.ExprNode
, LetNodeMixin
):
251 # A wrapper around a subexpression that moves an expression into a
252 # temp variable and provides it to the subexpression.
254 subexprs
= ['temp_expression', 'subexpression']
256 def __init__(self
, lazy_temp
, subexpression
):
257 self
.set_temp_expr(lazy_temp
)
258 self
.pos
= subexpression
.pos
259 self
.subexpression
= subexpression
260 # if called after type analysis, we already know the type here
261 self
.type = self
.subexpression
.type
263 def infer_type(self
, env
):
264 return self
.subexpression
.infer_type(env
)
267 return self
.subexpression
.result()
269 def analyse_types(self
, env
):
270 self
.temp_expression
= self
.temp_expression
.analyse_types(env
)
271 self
.subexpression
= self
.subexpression
.analyse_types(env
)
272 self
.type = self
.subexpression
.type
275 def free_subexpr_temps(self
, code
):
276 self
.subexpression
.free_temps(code
)
278 def generate_subexpr_disposal_code(self
, code
):
279 self
.subexpression
.generate_disposal_code(code
)
281 def generate_evaluation_code(self
, code
):
282 self
.setup_temp_expr(code
)
283 self
.subexpression
.generate_evaluation_code(code
)
284 self
.teardown_temp_expr(code
)
286 LetRefNode
= ResultRefNode
288 class LetNode(Nodes
.StatNode
, LetNodeMixin
):
289 # Implements a local temporary variable scope. Imagine this
290 # syntax being present:
292 # BLOCK (can modify temp)
293 # if temp is an object, decref
295 # Usually used after analysis phase, but forwards analysis methods
298 child_attrs
= ['temp_expression', 'body']
300 def __init__(self
, lazy_temp
, body
):
301 self
.set_temp_expr(lazy_temp
)
305 def analyse_declarations(self
, env
):
306 self
.temp_expression
.analyse_declarations(env
)
307 self
.body
.analyse_declarations(env
)
309 def analyse_expressions(self
, env
):
310 self
.temp_expression
= self
.temp_expression
.analyse_expressions(env
)
311 self
.body
= self
.body
.analyse_expressions(env
)
314 def generate_execution_code(self
, code
):
315 self
.setup_temp_expr(code
)
316 self
.body
.generate_execution_code(code
)
317 self
.teardown_temp_expr(code
)
319 def generate_function_definitions(self
, env
, code
):
320 self
.temp_expression
.generate_function_definitions(env
, code
)
321 self
.body
.generate_function_definitions(env
, code
)
324 class TempResultFromStatNode(ExprNodes
.ExprNode
):
325 # An ExprNode wrapper around a StatNode that executes the StatNode
326 # body. Requires a ResultRefNode that it sets up to refer to its
327 # own temp result. The StatNode must assign a value to the result
328 # node, which then becomes the result of this node.
331 child_attrs
= ['body']
333 def __init__(self
, result_ref
, body
):
334 self
.result_ref
= result_ref
337 self
.type = result_ref
.type
340 def analyse_declarations(self
, env
):
341 self
.body
.analyse_declarations(env
)
343 def analyse_types(self
, env
):
344 self
.body
= self
.body
.analyse_expressions(env
)
347 def generate_result_code(self
, code
):
348 self
.result_ref
.result_code
= self
.result()
349 self
.body
.generate_execution_code(code
)