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.
10
from .Nodes import Node
11
from .ExprNodes import AtomicExprNode
12
from .PyrexTypes import c_ptr_type, c_bint_type
16
# THIS IS DEPRECATED, USE LetRefNode instead
19
def __init__(self, type, needs_cleanup=None):
21
if needs_cleanup is None:
22
self.needs_cleanup = type.is_pyobject
24
self.needs_cleanup = needs_cleanup
27
return TempRefNode(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, overloaded_assignment=False):
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;' % (
60
rhs.result() if overloaded_assignment else rhs.result_as(self.ctype()),
62
rhs.generate_post_assignment_code(code)
66
class TempsBlockNode(Node):
67
# THIS IS DEPRECATED, USE LetNode instead
70
Creates a block which allocates temporary variables.
71
This is used by transforms to output constructs that need
72
to make use of a temporary variable. Simply pass the types
73
of the needed temporaries to the constructor.
75
The variables can be referred to using a TempRefNode
76
(which can be constructed by calling get_ref_node).
82
child_attrs = ["body"]
84
def generate_execution_code(self, code):
85
for handle in self.temps:
86
handle.temp = code.funcstate.allocate_temp(
87
handle.type, manage_ref=handle.needs_cleanup)
88
self.body.generate_execution_code(code)
89
for handle in self.temps:
90
if handle.needs_cleanup:
91
if handle.needs_xdecref:
92
code.put_xdecref_clear(handle.temp, handle.type)
94
code.put_decref_clear(handle.temp, handle.type)
95
code.funcstate.release_temp(handle.temp)
97
def analyse_declarations(self, env):
98
self.body.analyse_declarations(env)
100
def analyse_expressions(self, env):
101
self.body = self.body.analyse_expressions(env)
104
def generate_function_definitions(self, env, code):
105
self.body.generate_function_definitions(env, code)
107
def annotate(self, code):
108
self.body.annotate(code)
111
class ResultRefNode(AtomicExprNode):
112
# A reference to the result of an expression. The result_code
113
# must be set externally (usually a temp name).
116
lhs_of_first_assignment = False
118
def __init__(self, expression=None, pos=None, type=None, may_hold_none=True, is_temp=False):
119
self.expression = expression
121
self.may_hold_none = may_hold_none
122
if expression is not None:
123
self.pos = expression.pos
124
self.type = getattr(expression, "type", None)
131
assert self.pos is not None
133
def clone_node(self):
137
def type_dependencies(self, env):
139
return self.expression.type_dependencies(env)
143
def update_expression(self, expression):
144
self.expression = expression
145
type = getattr(expression, "type", None)
149
def analyse_target_declaration(self, env):
150
pass # OK - we can assign to this
152
def analyse_types(self, env):
153
if self.expression is not None:
154
if not self.expression.type:
155
self.expression = self.expression.analyse_types(env)
156
self.type = self.expression.type
159
def infer_type(self, env):
160
if self.type is not None:
162
if self.expression is not None:
163
if self.expression.type is not None:
164
return self.expression.type
165
return self.expression.infer_type(env)
166
assert False, "cannot infer type of ResultRefNode"
168
def may_be_none(self):
169
if not self.type.is_pyobject:
171
return self.may_hold_none
173
def _DISABLED_may_be_none(self):
174
# not sure if this is safe - the expression may not be the
175
# only value that gets assigned
176
if self.expression is not None:
177
return self.expression.may_be_none()
178
if self.type is not None:
179
return self.type.is_pyobject
180
return True # play it safe
187
return self.result_code
188
except AttributeError:
189
if self.expression is not None:
190
self.result_code = self.expression.result()
191
return self.result_code
193
def generate_evaluation_code(self, code):
196
def generate_result_code(self, code):
199
def generate_disposal_code(self, code):
202
def generate_assignment_code(self, rhs, code, overloaded_assignment=False):
203
if self.type.is_pyobject:
204
rhs.make_owned_reference(code)
205
if not self.lhs_of_first_assignment:
206
code.put_decref(self.result(), self.ctype())
207
code.putln('%s = %s;' % (
209
rhs.result() if overloaded_assignment else rhs.result_as(self.ctype()),
211
rhs.generate_post_assignment_code(code)
214
def allocate_temps(self, env):
217
def release_temp(self, env):
220
def free_temps(self, code):
225
def set_temp_expr(self, lazy_temp):
226
self.lazy_temp = lazy_temp
227
self.temp_expression = lazy_temp.expression
229
def setup_temp_expr(self, code):
230
self.temp_expression.generate_evaluation_code(code)
231
self.temp_type = self.temp_expression.type
232
if self.temp_type.is_array:
233
self.temp_type = c_ptr_type(self.temp_type.base_type)
234
self._result_in_temp = self.temp_expression.result_in_temp()
235
if self._result_in_temp:
236
self.temp = self.temp_expression.result()
238
if self.temp_type.is_memoryviewslice:
239
self.temp_expression.make_owned_memoryviewslice(code)
241
self.temp_expression.make_owned_reference(code)
242
self.temp = code.funcstate.allocate_temp(
243
self.temp_type, manage_ref=True)
244
code.putln("%s = %s;" % (self.temp, self.temp_expression.result()))
245
self.temp_expression.generate_disposal_code(code)
246
self.temp_expression.free_temps(code)
247
self.lazy_temp.result_code = self.temp
249
def teardown_temp_expr(self, code):
250
if self._result_in_temp:
251
self.temp_expression.generate_disposal_code(code)
252
self.temp_expression.free_temps(code)
254
if self.temp_type.needs_refcounting:
255
code.put_decref_clear(self.temp, self.temp_type)
256
code.funcstate.release_temp(self.temp)
259
class EvalWithTempExprNode(ExprNodes.ExprNode, LetNodeMixin):
260
# A wrapper around a subexpression that moves an expression into a
261
# temp variable and provides it to the subexpression.
263
subexprs = ['temp_expression', 'subexpression']
265
def __init__(self, lazy_temp, subexpression):
266
self.set_temp_expr(lazy_temp)
267
self.pos = subexpression.pos
268
self.subexpression = subexpression
269
# if called after type analysis, we already know the type here
270
self.type = self.subexpression.type
272
def infer_type(self, env):
273
return self.subexpression.infer_type(env)
275
def may_be_none(self):
276
return self.subexpression.may_be_none()
279
return self.subexpression.result()
281
def analyse_types(self, env):
282
self.temp_expression = self.temp_expression.analyse_types(env)
283
self.lazy_temp.update_expression(self.temp_expression) # overwrite in case it changed
284
self.subexpression = self.subexpression.analyse_types(env)
285
self.type = self.subexpression.type
288
def free_subexpr_temps(self, code):
289
self.subexpression.free_temps(code)
291
def generate_subexpr_disposal_code(self, code):
292
self.subexpression.generate_disposal_code(code)
294
def generate_evaluation_code(self, code):
295
self.setup_temp_expr(code)
296
self.subexpression.generate_evaluation_code(code)
297
self.teardown_temp_expr(code)
300
LetRefNode = ResultRefNode
303
class LetNode(Nodes.StatNode, LetNodeMixin):
304
# Implements a local temporary variable scope. Imagine this
305
# syntax being present:
307
# BLOCK (can modify temp)
308
# if temp is an object, decref
310
# Usually used after analysis phase, but forwards analysis methods
313
child_attrs = ['temp_expression', 'body']
315
def __init__(self, lazy_temp, body):
316
self.set_temp_expr(lazy_temp)
320
def analyse_declarations(self, env):
321
self.temp_expression.analyse_declarations(env)
322
self.body.analyse_declarations(env)
324
def analyse_expressions(self, env):
325
self.temp_expression = self.temp_expression.analyse_expressions(env)
326
self.body = self.body.analyse_expressions(env)
329
def generate_execution_code(self, code):
330
self.setup_temp_expr(code)
331
self.body.generate_execution_code(code)
332
self.teardown_temp_expr(code)
334
def generate_function_definitions(self, env, code):
335
self.temp_expression.generate_function_definitions(env, code)
336
self.body.generate_function_definitions(env, code)
339
class TempResultFromStatNode(ExprNodes.ExprNode):
340
# An ExprNode wrapper around a StatNode that executes the StatNode
341
# body. Requires a ResultRefNode that it sets up to refer to its
342
# own temp result. The StatNode must assign a value to the result
343
# node, which then becomes the result of this node.
346
child_attrs = ['body']
348
def __init__(self, result_ref, body):
349
self.result_ref = result_ref
352
self.type = result_ref.type
355
def analyse_declarations(self, env):
356
self.body.analyse_declarations(env)
358
def analyse_types(self, env):
359
self.body = self.body.analyse_expressions(env)
362
def may_be_none(self):
363
return self.result_ref.may_be_none()
365
def generate_result_code(self, code):
366
self.result_ref.result_code = self.result()
367
self.body.generate_execution_code(code)
369
def generate_function_definitions(self, env, code):
370
self.body.generate_function_definitions(env, code)
373
class HasGilNode(AtomicExprNode):
375
Simple node that evaluates to 0 or 1 depending on whether we're
380
def analyse_types(self, env):
383
def generate_result_code(self, code):
384
self.has_gil = code.funcstate.gil_owned
386
def calculate_result_code(self):
387
return "1" if self.has_gil else "0"