Home | History | Annotate | Download | only in Compiler
      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