UtilNodes.py 10.1 KB
Newer Older
1 2 3 4 5 6 7 8 9
#
# Nodes used as utilities and support for transforms etc.
# These often make up sets including both Nodes and ExprNodes
# so it is convenient to have them in a seperate module.
#

import Nodes
import ExprNodes
from Nodes import Node
Stefan Behnel's avatar
Stefan Behnel committed
10
from ExprNodes import AtomicExprNode
11
from PyrexTypes import c_ptr_type
12 13

class TempHandle(object):
14
    # THIS IS DEPRECATED, USE LetRefNode instead
15
    temp = None
16
    needs_xdecref = False
17 18
    def __init__(self, type):
        self.type = type
19
        self.needs_cleanup = type.is_pyobject
20

21 22 23
    def ref(self, pos):
        return TempRefNode(pos, handle=self, type=self.type)

24 25 26
    def cleanup_ref(self, pos):
        return CleanupTempRefNode(pos, handle=self, type=self.type)

Stefan Behnel's avatar
Stefan Behnel committed
27
class TempRefNode(AtomicExprNode):
28
    # THIS IS DEPRECATED, USE LetRefNode instead
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
    # handle   TempHandle

    def analyse_types(self, env):
        assert self.type == self.handle.type
    
    def analyse_target_types(self, env):
        assert self.type == self.handle.type

    def analyse_target_declaration(self, env):
        pass

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

    def generate_result_code(self, code):
        pass

    def generate_assignment_code(self, rhs, code):
        if self.type.is_pyobject:
            rhs.make_owned_reference(code)
51
            # TODO: analyse control flow to see if this is necessary
52 53 54
            code.put_xdecref(self.result(), self.ctype())
        code.putln('%s = %s;' % (self.result(), rhs.result_as(self.ctype())))
        rhs.generate_post_assignment_code(code)
55
        rhs.free_temps(code)
56

57
class CleanupTempRefNode(TempRefNode):
58
    # THIS IS DEPRECATED, USE LetRefNode instead
59 60 61 62 63 64 65 66 67 68
    # handle   TempHandle

    def generate_assignment_code(self, rhs, code):
        pass

    def generate_execution_code(self, code):
        if self.type.is_pyobject:
            code.put_decref_clear(self.result(), self.type)
            self.handle.needs_cleanup = False

69
class TempsBlockNode(Node):
70 71
    # THIS IS DEPRECATED, USE LetNode instead
    
72 73 74 75 76 77 78 79 80 81
    """
    Creates a block which allocates temporary variables.
    This is used by transforms to output constructs that need
    to make use of a temporary variable. Simply pass the types
    of the needed temporaries to the constructor.
    
    The variables can be referred to using a TempRefNode
    (which can be constructed by calling get_ref_node).
    """

82 83 84 85
    # temps   [TempHandle]
    # body    StatNode
    
    child_attrs = ["body"]
86 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 94 95 96 97
            if handle.needs_cleanup:
                if handle.needs_xdecref:
                    code.put_xdecref_clear(handle.temp, handle.type)
                else:
                    code.put_decref_clear(handle.temp, handle.type)
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
            code.funcstate.release_temp(handle.temp)

    def analyse_control_flow(self, env):
        self.body.analyse_control_flow(env)

    def analyse_declarations(self, env):
        self.body.analyse_declarations(env)
    
    def analyse_expressions(self, env):
        self.body.analyse_expressions(env)
    
    def generate_function_definitions(self, env, code):
        self.body.generate_function_definitions(env, code)
            
    def annotate(self, code):
        self.body.annotate(code)

115 116 117 118 119 120

class ResultRefNode(AtomicExprNode):
    # A reference to the result of an expression.  The result_code
    # must be set externally (usually a temp name).

    subexprs = []
121
    lhs_of_first_assignment = False
122

123
    def __init__(self, expression=None, pos=None, type=None):
124
        self.expression = expression
125 126 127 128 129 130 131
        self.pos = None
        if expression is not None:
            self.pos = expression.pos
            if hasattr(expression, "type"):
                self.type = expression.type
        if pos is not None:
            self.pos = pos
132 133
        if type is not None:
            self.type = type
134
        assert self.pos is not None
135 136

    def analyse_types(self, env):
137 138
        if self.expression is not None:
            self.type = self.expression.type
139

140
    def infer_type(self, env):
141 142
        if self.expression is not None:
            return self.expression.infer_type(env)
143

Stefan Behnel's avatar
Stefan Behnel committed
144 145 146 147 148 149 150 151 152
    def _DISABLED_may_be_none(self):
        # not sure if this is safe - the expression may not be the
        # only value that gets assigned
        if self.expression is not None:
            return self.expression.may_be_none()
        if self.type is not None:
            return self.type.is_pyobject
        return True # play safe

153 154 155
    def is_simple(self):
        return True

156
    def result(self):
157 158 159 160 161
        try:
            return self.result_code
        except AttributeError:
            if self.expression is not None:
                self.result_code = self.expression.result()
162 163 164 165 166 167 168 169 170 171 172
        return self.result_code

    def generate_evaluation_code(self, code):
        pass

    def generate_result_code(self, code):
        pass
        
    def generate_disposal_code(self, code):
        pass
                
173 174 175
    def generate_assignment_code(self, rhs, code):
        if self.type.is_pyobject:
            rhs.make_owned_reference(code)
176 177
            if not self.lhs_of_first_assignment:
                code.put_decref(self.result(), self.ctype())
178 179 180 181
        code.putln('%s = %s;' % (self.result(), rhs.result_as(self.ctype())))
        rhs.generate_post_assignment_code(code)
        rhs.free_temps(code)

182 183 184 185 186 187 188 189 190 191
    def allocate_temps(self, env):
        pass
        
    def release_temp(self, env):
        pass

    def free_temps(self, code):
        pass


192 193 194 195 196 197 198 199
class LetNodeMixin:
    def set_temp_expr(self, lazy_temp):
        self.lazy_temp = lazy_temp
        self.temp_expression = lazy_temp.expression

    def setup_temp_expr(self, code):
        self.temp_expression.generate_evaluation_code(code)
        self.temp_type = self.temp_expression.type
200 201
        if self.temp_type.is_array:
            self.temp_type = c_ptr_type(self.temp_type.base_type)
202
        self._result_in_temp = self.temp_expression.result_in_temp()
203
        if self._result_in_temp:
204 205 206 207 208 209
            self.temp = self.temp_expression.result()
        else:
            self.temp_expression.make_owned_reference(code)
            self.temp = code.funcstate.allocate_temp(
                self.temp_type, manage_ref=True)
            code.putln("%s = %s;" % (self.temp, self.temp_expression.result()))
210 211
            self.temp_expression.generate_disposal_code(code)
            self.temp_expression.free_temps(code)
212 213 214
        self.lazy_temp.result_code = self.temp

    def teardown_temp_expr(self, code):
215 216 217 218
        if self._result_in_temp:
            self.temp_expression.generate_disposal_code(code)
            self.temp_expression.free_temps(code)
        else:
219 220 221 222 223
            if self.temp_type.is_pyobject:
                code.put_decref_clear(self.temp, self.temp_type)
            code.funcstate.release_temp(self.temp)

class EvalWithTempExprNode(ExprNodes.ExprNode, LetNodeMixin):
224 225 226 227 228 229
    # A wrapper around a subexpression that moves an expression into a
    # temp variable and provides it to the subexpression.

    subexprs = ['temp_expression', 'subexpression']

    def __init__(self, lazy_temp, subexpression):
230
        self.set_temp_expr(lazy_temp)
231 232
        self.pos = subexpression.pos
        self.subexpression = subexpression
233 234
        # if called after type analysis, we already know the type here
        self.type = self.subexpression.type
235

236 237 238
    def infer_type(self, env):
        return self.subexpression.infer_type(env)

239 240 241 242 243 244 245 246
    def result(self):
        return self.subexpression.result()

    def analyse_types(self, env):
        self.temp_expression.analyse_types(env)
        self.subexpression.analyse_types(env)
        self.type = self.subexpression.type

247 248 249 250 251 252
    def free_subexpr_temps(self, code):
        self.subexpression.free_temps(code)

    def generate_subexpr_disposal_code(self, code):
        self.subexpression.generate_disposal_code(code)

253
    def generate_evaluation_code(self, code):
254
        self.setup_temp_expr(code)
255
        self.subexpression.generate_evaluation_code(code)
256 257 258 259 260 261 262 263 264 265 266
        self.teardown_temp_expr(code)
 
LetRefNode = ResultRefNode

class LetNode(Nodes.StatNode, LetNodeMixin):
    # Implements a local temporary variable scope. Imagine this
    # syntax being present:
    # let temp = VALUE:
    #     BLOCK (can modify temp)
    #     if temp is an object, decref
    #
267 268
    # Usually used after analysis phase, but forwards analysis methods
    # to its children
269 270 271 272 273 274 275 276

    child_attrs = ['temp_expression', 'body']

    def __init__(self, lazy_temp, body):
        self.set_temp_expr(lazy_temp)
        self.pos = body.pos
        self.body = body

277 278 279 280 281 282 283 284 285 286 287
    def analyse_control_flow(self, env):
        self.body.analyse_control_flow(env)

    def analyse_declarations(self, env):
        self.temp_expression.analyse_declarations(env)
        self.body.analyse_declarations(env)
    
    def analyse_expressions(self, env):
        self.temp_expression.analyse_expressions(env)
        self.body.analyse_expressions(env)

288 289 290 291
    def generate_execution_code(self, code):
        self.setup_temp_expr(code)
        self.body.generate_execution_code(code)
        self.teardown_temp_expr(code)
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308

class TempResultFromStatNode(ExprNodes.ExprNode):
    # An ExprNode wrapper around a StatNode that executes the StatNode
    # body.  Requires a ResultRefNode that it sets up to refer to its
    # own temp result.  The StatNode must assign a value to the result
    # node, which then becomes the result of this node.

    subexprs = []
    child_attrs = ['body']

    def __init__(self, result_ref, body):
        self.result_ref = result_ref
        self.pos = body.pos
        self.body = body
        self.type = result_ref.type
        self.is_temp = 1

309 310 311 312 313 314
    def analyse_declarations(self, env):
        self.body.analyse_declarations(env)
    
    def analyse_types(self, env):
        self.body.analyse_expressions(env)

315 316 317
    def generate_result_code(self, code):
        self.result_ref.result_code = self.result()
        self.body.generate_execution_code(code)