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