OLD | NEW |
(Empty) | |
| 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 seperate module. |
| 5 # |
| 6 |
| 7 import Nodes |
| 8 import ExprNodes |
| 9 from Nodes import Node |
| 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 def __init__(self, type, needs_cleanup=None): |
| 18 self.type = type |
| 19 if needs_cleanup is None: |
| 20 self.needs_cleanup = type.is_pyobject |
| 21 else: |
| 22 self.needs_cleanup = needs_cleanup |
| 23 |
| 24 def ref(self, pos): |
| 25 return TempRefNode(pos, handle=self, type=self.type) |
| 26 |
| 27 def cleanup_ref(self, pos): |
| 28 return CleanupTempRefNode(pos, handle=self, type=self.type) |
| 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): |
| 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) |
| 60 rhs.free_temps(code) |
| 61 |
| 62 class CleanupTempRefNode(TempRefNode): |
| 63 # THIS IS DEPRECATED, USE LetRefNode instead |
| 64 # handle TempHandle |
| 65 |
| 66 def generate_assignment_code(self, rhs, code): |
| 67 pass |
| 68 |
| 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 |
| 73 |
| 74 class TempsBlockNode(Node): |
| 75 # THIS IS DEPRECATED, USE LetNode instead |
| 76 |
| 77 """ |
| 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. |
| 82 |
| 83 The variables can be referred to using a TempRefNode |
| 84 (which can be constructed by calling get_ref_node). |
| 85 """ |
| 86 |
| 87 # temps [TempHandle] |
| 88 # body StatNode |
| 89 |
| 90 child_attrs = ["body"] |
| 91 |
| 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) |
| 101 else: |
| 102 code.put_decref_clear(handle.temp, handle.type) |
| 103 code.funcstate.release_temp(handle.temp) |
| 104 |
| 105 def analyse_declarations(self, env): |
| 106 self.body.analyse_declarations(env) |
| 107 |
| 108 def analyse_expressions(self, env): |
| 109 self.body = self.body.analyse_expressions(env) |
| 110 return self |
| 111 |
| 112 def generate_function_definitions(self, env, code): |
| 113 self.body.generate_function_definitions(env, code) |
| 114 |
| 115 def annotate(self, code): |
| 116 self.body.annotate(code) |
| 117 |
| 118 |
| 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). |
| 122 |
| 123 subexprs = [] |
| 124 lhs_of_first_assignment = False |
| 125 |
| 126 def __init__(self, expression=None, pos=None, type=None, may_hold_none=True,
is_temp=False): |
| 127 self.expression = expression |
| 128 self.pos = None |
| 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 |
| 134 if pos is not None: |
| 135 self.pos = pos |
| 136 if type is not None: |
| 137 self.type = type |
| 138 if is_temp: |
| 139 self.is_temp = True |
| 140 assert self.pos is not None |
| 141 |
| 142 def clone_node(self): |
| 143 # nothing to do here |
| 144 return self |
| 145 |
| 146 def type_dependencies(self, env): |
| 147 if self.expression: |
| 148 return self.expression.type_dependencies(env) |
| 149 else: |
| 150 return () |
| 151 |
| 152 def analyse_types(self, env): |
| 153 if self.expression is not None: |
| 154 self.type = self.expression.type |
| 155 return self |
| 156 |
| 157 def infer_type(self, env): |
| 158 if self.type is not None: |
| 159 return self.type |
| 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" |
| 165 |
| 166 def may_be_none(self): |
| 167 if not self.type.is_pyobject: |
| 168 return False |
| 169 return self.may_hold_none |
| 170 |
| 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 |
| 179 |
| 180 def is_simple(self): |
| 181 return True |
| 182 |
| 183 def result(self): |
| 184 try: |
| 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 |
| 190 |
| 191 def generate_evaluation_code(self, code): |
| 192 pass |
| 193 |
| 194 def generate_result_code(self, code): |
| 195 pass |
| 196 |
| 197 def generate_disposal_code(self, code): |
| 198 pass |
| 199 |
| 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) |
| 207 rhs.free_temps(code) |
| 208 |
| 209 def allocate_temps(self, env): |
| 210 pass |
| 211 |
| 212 def release_temp(self, env): |
| 213 pass |
| 214 |
| 215 def free_temps(self, code): |
| 216 pass |
| 217 |
| 218 |
| 219 class LetNodeMixin: |
| 220 def set_temp_expr(self, lazy_temp): |
| 221 self.lazy_temp = lazy_temp |
| 222 self.temp_expression = lazy_temp.expression |
| 223 |
| 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() |
| 232 else: |
| 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 |
| 240 |
| 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) |
| 245 else: |
| 246 if self.temp_type.is_pyobject: |
| 247 code.put_decref_clear(self.temp, self.temp_type) |
| 248 code.funcstate.release_temp(self.temp) |
| 249 |
| 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. |
| 253 |
| 254 subexprs = ['temp_expression', 'subexpression'] |
| 255 |
| 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 |
| 262 |
| 263 def infer_type(self, env): |
| 264 return self.subexpression.infer_type(env) |
| 265 |
| 266 def result(self): |
| 267 return self.subexpression.result() |
| 268 |
| 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 |
| 273 return self |
| 274 |
| 275 def free_subexpr_temps(self, code): |
| 276 self.subexpression.free_temps(code) |
| 277 |
| 278 def generate_subexpr_disposal_code(self, code): |
| 279 self.subexpression.generate_disposal_code(code) |
| 280 |
| 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) |
| 285 |
| 286 LetRefNode = ResultRefNode |
| 287 |
| 288 class LetNode(Nodes.StatNode, LetNodeMixin): |
| 289 # Implements a local temporary variable scope. Imagine this |
| 290 # syntax being present: |
| 291 # let temp = VALUE: |
| 292 # BLOCK (can modify temp) |
| 293 # if temp is an object, decref |
| 294 # |
| 295 # Usually used after analysis phase, but forwards analysis methods |
| 296 # to its children |
| 297 |
| 298 child_attrs = ['temp_expression', 'body'] |
| 299 |
| 300 def __init__(self, lazy_temp, body): |
| 301 self.set_temp_expr(lazy_temp) |
| 302 self.pos = body.pos |
| 303 self.body = body |
| 304 |
| 305 def analyse_declarations(self, env): |
| 306 self.temp_expression.analyse_declarations(env) |
| 307 self.body.analyse_declarations(env) |
| 308 |
| 309 def analyse_expressions(self, env): |
| 310 self.temp_expression = self.temp_expression.analyse_expressions(env) |
| 311 self.body = self.body.analyse_expressions(env) |
| 312 return self |
| 313 |
| 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) |
| 318 |
| 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) |
| 322 |
| 323 |
| 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. |
| 329 |
| 330 subexprs = [] |
| 331 child_attrs = ['body'] |
| 332 |
| 333 def __init__(self, result_ref, body): |
| 334 self.result_ref = result_ref |
| 335 self.pos = body.pos |
| 336 self.body = body |
| 337 self.type = result_ref.type |
| 338 self.is_temp = 1 |
| 339 |
| 340 def analyse_declarations(self, env): |
| 341 self.body.analyse_declarations(env) |
| 342 |
| 343 def analyse_types(self, env): |
| 344 self.body = self.body.analyse_expressions(env) |
| 345 return self |
| 346 |
| 347 def generate_result_code(self, code): |
| 348 self.result_ref.result_code = self.result() |
| 349 self.body.generate_execution_code(code) |
OLD | NEW |