cython

Форк
0
/
UtilNodes.py 
387 строк · 12.1 Кб
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

7

8
from . import Nodes
9
from . import ExprNodes
10
from .Nodes import Node
11
from .ExprNodes import AtomicExprNode
12
from .PyrexTypes import c_ptr_type, c_bint_type
13

14

15
class TempHandle:
16
    # THIS IS DEPRECATED, USE LetRefNode instead
17
    temp = None
18
    needs_xdecref = False
19
    def __init__(self, type, needs_cleanup=None):
20
        self.type = type
21
        if needs_cleanup is None:
22
            self.needs_cleanup = type.is_pyobject
23
        else:
24
            self.needs_cleanup = needs_cleanup
25

26
    def ref(self, pos):
27
        return TempRefNode(pos, handle=self, type=self.type)
28

29

30
class TempRefNode(AtomicExprNode):
31
    # THIS IS DEPRECATED, USE LetRefNode instead
32
    # handle   TempHandle
33

34
    def analyse_types(self, env):
35
        assert self.type == self.handle.type
36
        return self
37

38
    def analyse_target_types(self, env):
39
        assert self.type == self.handle.type
40
        return self
41

42
    def analyse_target_declaration(self, env):
43
        pass
44

45
    def calculate_result_code(self):
46
        result = self.handle.temp
47
        if result is None: result = "<error>"  # might be called and overwritten
48
        return result
49

50
    def generate_result_code(self, code):
51
        pass
52

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;' % (
59
            self.result(),
60
            rhs.result() if overloaded_assignment else rhs.result_as(self.ctype()),
61
        ))
62
        rhs.generate_post_assignment_code(code)
63
        rhs.free_temps(code)
64

65

66
class TempsBlockNode(Node):
67
    # THIS IS DEPRECATED, USE LetNode instead
68

69
    """
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.
74

75
    The variables can be referred to using a TempRefNode
76
    (which can be constructed by calling get_ref_node).
77
    """
78

79
    # temps   [TempHandle]
80
    # body    StatNode
81

82
    child_attrs = ["body"]
83

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)
93
                else:
94
                    code.put_decref_clear(handle.temp, handle.type)
95
            code.funcstate.release_temp(handle.temp)
96

97
    def analyse_declarations(self, env):
98
        self.body.analyse_declarations(env)
99

100
    def analyse_expressions(self, env):
101
        self.body = self.body.analyse_expressions(env)
102
        return self
103

104
    def generate_function_definitions(self, env, code):
105
        self.body.generate_function_definitions(env, code)
106

107
    def annotate(self, code):
108
        self.body.annotate(code)
109

110

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).
114

115
    subexprs = []
116
    lhs_of_first_assignment = False
117

118
    def __init__(self, expression=None, pos=None, type=None, may_hold_none=True, is_temp=False):
119
        self.expression = expression
120
        self.pos = None
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)
125
        if pos is not None:
126
            self.pos = pos
127
        if type is not None:
128
            self.type = type
129
        if is_temp:
130
            self.is_temp = True
131
        assert self.pos is not None
132

133
    def clone_node(self):
134
        # nothing to do here
135
        return self
136

137
    def type_dependencies(self, env):
138
        if self.expression:
139
            return self.expression.type_dependencies(env)
140
        else:
141
            return ()
142

143
    def update_expression(self, expression):
144
        self.expression = expression
145
        type = getattr(expression, "type", None)
146
        if type:
147
            self.type = type
148

149
    def analyse_target_declaration(self, env):
150
        pass  # OK - we can assign to this
151

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
157
        return self
158

159
    def infer_type(self, env):
160
        if self.type is not None:
161
            return self.type
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"
167

168
    def may_be_none(self):
169
        if not self.type.is_pyobject:
170
            return False
171
        return self.may_hold_none
172

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
181

182
    def is_simple(self):
183
        return True
184

185
    def result(self):
186
        try:
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
192

193
    def generate_evaluation_code(self, code):
194
        pass
195

196
    def generate_result_code(self, code):
197
        pass
198

199
    def generate_disposal_code(self, code):
200
        pass
201

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;' % (
208
            self.result(),
209
            rhs.result() if overloaded_assignment else rhs.result_as(self.ctype()),
210
        ))
211
        rhs.generate_post_assignment_code(code)
212
        rhs.free_temps(code)
213

214
    def allocate_temps(self, env):
215
        pass
216

217
    def release_temp(self, env):
218
        pass
219

220
    def free_temps(self, code):
221
        pass
222

223

224
class LetNodeMixin:
225
    def set_temp_expr(self, lazy_temp):
226
        self.lazy_temp = lazy_temp
227
        self.temp_expression = lazy_temp.expression
228

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()
237
        else:
238
            if self.temp_type.is_memoryviewslice:
239
                self.temp_expression.make_owned_memoryviewslice(code)
240
            else:
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
248

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)
253
        else:
254
            if self.temp_type.needs_refcounting:
255
                code.put_decref_clear(self.temp, self.temp_type)
256
            code.funcstate.release_temp(self.temp)
257

258

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.
262

263
    subexprs = ['temp_expression', 'subexpression']
264

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
271

272
    def infer_type(self, env):
273
        return self.subexpression.infer_type(env)
274

275
    def may_be_none(self):
276
        return self.subexpression.may_be_none()
277

278
    def result(self):
279
        return self.subexpression.result()
280

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
286
        return self
287

288
    def free_subexpr_temps(self, code):
289
        self.subexpression.free_temps(code)
290

291
    def generate_subexpr_disposal_code(self, code):
292
        self.subexpression.generate_disposal_code(code)
293

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)
298

299

300
LetRefNode = ResultRefNode
301

302

303
class LetNode(Nodes.StatNode, LetNodeMixin):
304
    # Implements a local temporary variable scope. Imagine this
305
    # syntax being present:
306
    # let temp = VALUE:
307
    #     BLOCK (can modify temp)
308
    #     if temp is an object, decref
309
    #
310
    # Usually used after analysis phase, but forwards analysis methods
311
    # to its children
312

313
    child_attrs = ['temp_expression', 'body']
314

315
    def __init__(self, lazy_temp, body):
316
        self.set_temp_expr(lazy_temp)
317
        self.pos = body.pos
318
        self.body = body
319

320
    def analyse_declarations(self, env):
321
        self.temp_expression.analyse_declarations(env)
322
        self.body.analyse_declarations(env)
323

324
    def analyse_expressions(self, env):
325
        self.temp_expression = self.temp_expression.analyse_expressions(env)
326
        self.body = self.body.analyse_expressions(env)
327
        return self
328

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)
333

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)
337

338

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.
344

345
    subexprs = []
346
    child_attrs = ['body']
347

348
    def __init__(self, result_ref, body):
349
        self.result_ref = result_ref
350
        self.pos = body.pos
351
        self.body = body
352
        self.type = result_ref.type
353
        self.is_temp = 1
354

355
    def analyse_declarations(self, env):
356
        self.body.analyse_declarations(env)
357

358
    def analyse_types(self, env):
359
        self.body = self.body.analyse_expressions(env)
360
        return self
361

362
    def may_be_none(self):
363
        return self.result_ref.may_be_none()
364

365
    def generate_result_code(self, code):
366
        self.result_ref.result_code = self.result()
367
        self.body.generate_execution_code(code)
368

369
    def generate_function_definitions(self, env, code):
370
        self.body.generate_function_definitions(env, code)
371

372

373
class HasGilNode(AtomicExprNode):
374
    """
375
    Simple node that evaluates to 0 or 1 depending on whether we're
376
    in a nogil context
377
    """
378
    type = c_bint_type
379

380
    def analyse_types(self, env):
381
        return self
382

383
    def generate_result_code(self, code):
384
        self.has_gil = code.funcstate.gil_owned
385

386
    def calculate_result_code(self):
387
        return "1" if self.has_gil else "0"
388

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.