All exprnodes over; NewTempExprNode folded into ExprNode
authorDag Sverre Seljebotn <dagss@student.matnat.uio.no>
Mon, 30 Mar 2009 20:14:31 +0000 (22:14 +0200)
committerDag Sverre Seljebotn <dagss@student.matnat.uio.no>
Mon, 30 Mar 2009 20:14:31 +0000 (22:14 +0200)
Cython/Compiler/ExprNodes.py
Cython/Compiler/Nodes.py
Cython/Compiler/UtilNodes.py

index b775d4310eeaa254c87799df62e40bf814897bf1..b3964def6132e59676977cda5a03dff363cbb52f 100644 (file)
@@ -46,6 +46,8 @@ class ExprNode(Node):
     
     result_ctype = None
     type = None
+    temp_code = None
+    old_temp = None # error checker for multiple frees etc.
 
     #  The Analyse Expressions phase for expressions is split
     #  into two sub-phases:
@@ -222,10 +224,10 @@ class ExprNode(Node):
         return nodes
         
     def result(self):
-        if not self.is_temp or self.is_target:
+        if self.is_temp:
+            return self.temp_code
+        else:
             return self.calculate_result_code()
-        else: # i.e. self.is_temp:
-            return self.result_code
     
     def result_as(self, type = None):
         #  Return the result code cast to the specified C type.
@@ -370,15 +372,18 @@ class ExprNode(Node):
         return self.is_temp
             
     def allocate_target_temps(self, env, rhs):
-        #  Perform temp allocation for the LHS of an assignment.
-        if debug_temp_alloc:
-            print("%s Allocating target temps" % self)
         self.allocate_subexpr_temps(env)
         self.is_target = True
         if rhs:
             rhs.release_temp(env)
         self.release_subexpr_temps(env)
-    
+
+    def allocate_temps(self, env, result = None):
+        assert result is None, "deprecated, contact dagss if this triggers"
+        self.allocate_subexpr_temps(env)
+        if self.is_temp:
+            self.release_subexpr_temps(env)
+
     def allocate_temps(self, env, result = None):
         #  Allocate temporary variables for this node and
         #  all its sub-expressions. If a result is specified,
@@ -405,28 +410,7 @@ class ExprNode(Node):
                 node.allocate_temps(env)
     
     def allocate_temp(self, env, result = None):
-        #  If this node requires a temporary variable for its
-        #  result, allocate one, otherwise set the result to
-        #  a C code fragment. If a result is specified,
-        #  this must be a temp node and the specified variable
-        #  is used as the result instead of allocating a new
-        #  one.
-        if debug_temp_alloc:
-            print("%s Allocating temp" % self)
-        if result:
-            if not self.is_temp:
-                raise InternalError("Result forced on non-temp node")
-            self.result_code = result
-        elif self.is_temp:
-            type = self.type
-            if not type.is_void:
-                if type.is_pyobject:
-                    type = PyrexTypes.py_object_type
-                self.result_code = env.allocate_temp(type)
-            else:
-                self.result_code = None
-            if debug_temp_alloc:
-                print("%s Allocated result %s" % (self, self.result_code))
+        assert result is None
                 
     def target_code(self):
         #  Return code fragment for use as LHS of a C assignment.
@@ -439,13 +423,10 @@ class ExprNode(Node):
 #        #  Release temporaries used by LHS of an assignment.
 #        self.release_subexpr_temps(env)
 
+
     def release_temp(self, env):
-        #  If this node owns a temporary result, release it,
-        #  otherwise release results of its sub-expressions.
         if self.is_temp:
-            if debug_temp_alloc:
-                print("%s Releasing result %s" % (self, self.result_code))
-            env.release_temp(self.result_code)
+            pass
         else:
             self.release_subexpr_temps(env)
     
@@ -456,6 +437,30 @@ class ExprNode(Node):
             if node:
                 node.release_temp(env)
     
+    def allocate_temp_result(self, code):
+        if self.temp_code:
+            raise RuntimeError("Temp allocated multiple times")
+        type = self.type
+        if not type.is_void:
+            if type.is_pyobject:
+                type = PyrexTypes.py_object_type
+            self.temp_code = code.funcstate.allocate_temp(
+                type, manage_ref=True)
+        else:
+            self.temp_code = None
+
+    def release_temp_result(self, code):
+        if not self.temp_code:
+            if self.old_temp:
+                raise RuntimeError("temp %s released multiple times in %s" % (
+                        self.old_temp, self.__class__.__name__))
+            else:
+                raise RuntimeError("no temp, but release requested in %s" % (
+                        self.__class__.__name__))
+        code.funcstate.release_temp(self.temp_code)
+        self.old_temp = self.temp_code
+        self.temp_code = None
+
     # ---------------- Code Generation -----------------
     
     def make_owned_reference(self, code):
@@ -466,12 +471,19 @@ class ExprNode(Node):
     
     def generate_evaluation_code(self, code):
         code.mark_pos(self.pos)
+        
         #  Generate code to evaluate this node and
         #  its sub-expressions, and dispose of any
         #  temporary results of its sub-expressions.
         self.generate_subexpr_evaluation_code(code)
+
+        if self.is_temp:
+            self.allocate_temp_result(code)
+
         self.generate_result_code(code)
         if self.is_temp:
+            # If we are temp we do not need to wait until this node is disposed
+            # before disposing children.
             self.generate_subexpr_disposal_code(code)
             self.free_subexpr_temps(code)
 
@@ -483,14 +495,13 @@ class ExprNode(Node):
         self.not_implemented("generate_result_code")
     
     def generate_disposal_code(self, code):
-        # If necessary, generate code to dispose of 
-        # temporary Python reference.
         if self.is_temp:
             if self.type.is_pyobject:
                 code.put_decref_clear(self.result(), self.ctype())
         else:
+            # Already done if self.is_temp
             self.generate_subexpr_disposal_code(code)
-    
+
     def generate_subexpr_disposal_code(self, code):
         #  Generate code to dispose of temporary results
         #  of all sub-expressions.
@@ -498,15 +509,12 @@ class ExprNode(Node):
             node.generate_disposal_code(code)
     
     def generate_post_assignment_code(self, code):
-        # Same as generate_disposal_code except that
-        # assignment will have absorbed a reference to
-        # the result if it is a Python object.
         if self.is_temp:
             if self.type.is_pyobject:
                 code.putln("%s = 0;" % self.result())
         else:
             self.generate_subexpr_disposal_code(code)
-    
+
     def generate_assignment_code(self, rhs, code):
         #  Stub method for nodes which are not legal as
         #  the LHS of an assignment. An error will have 
@@ -520,9 +528,11 @@ class ExprNode(Node):
         pass
 
     def free_temps(self, code):
-        if not self.is_temp:
+        if self.is_temp:
+            if not self.type.is_void:
+                self.release_temp_result(code)
+        else:
             self.free_subexpr_temps(code)
-        # otherwise, already freed in generate_evaluation_code
     
     def free_subexpr_temps(self, code):
         for sub in self.subexpr_nodes():
@@ -612,125 +622,7 @@ class ExprNode(Node):
     def as_cython_attribute(self):
         return None
 
-
-class RemoveAllocateTemps(type):
-    def __init__(cls, name, bases, dct):
-        super(RemoveAllocateTemps, cls).__init__(name, bases, dct)
-        def noop(self, env): pass
-        setattr(cls, 'allocate_temps', noop)
-        setattr(cls, 'allocate_temp', noop)
-        setattr(cls, 'release_temp', noop)
-
-class NewTempExprNode(ExprNode):
-    temp_code = None
-    old_temp = None # error checker for multiple frees etc.
-
-#   Do not enable this unless you are trying to make all ExprNodes
-#   NewTempExprNodes (child nodes reached via recursion may not have
-#   transferred).
-#    __metaclass__ = RemoveAllocateTemps
-
-    def result(self):
-        if self.is_temp:
-            return self.temp_code
-        else:
-            return self.calculate_result_code()
-
-    def allocate_target_temps(self, env, rhs):
-        self.allocate_subexpr_temps(env)
-        self.is_target = True
-        if rhs:
-            rhs.release_temp(env)
-        self.release_subexpr_temps(env)
-
-    def allocate_temps(self, env, result = None):
-        assert result is None, "deprecated, contact dagss if this triggers"
-        self.allocate_subexpr_temps(env)
-        if self.is_temp:
-            self.release_subexpr_temps(env)
-
-    def allocate_temp(self, env, result = None):
-        assert result is None
-
-    def release_temp(self, env):
-        if self.is_temp:
-            pass
-        else:
-            self.release_subexpr_temps(env)
-
-    def allocate_temp_result(self, code):
-        if self.temp_code:
-            raise RuntimeError("Temp allocated multiple times")
-        type = self.type
-        if not type.is_void:
-            if type.is_pyobject:
-                type = PyrexTypes.py_object_type
-            self.temp_code = code.funcstate.allocate_temp(
-                type, manage_ref=True)
-        else:
-            self.temp_code = None
-
-    def release_temp_result(self, code):
-        if not self.temp_code:
-            if self.old_temp:
-                raise RuntimeError("temp %s released multiple times in %s" % (
-                        self.old_temp, self.__class__.__name__))
-            else:
-                raise RuntimeError("no temp, but release requested in %s" % (
-                        self.__class__.__name__))
-        code.funcstate.release_temp(self.temp_code)
-        self.old_temp = self.temp_code
-        self.temp_code = None
-
-    def generate_evaluation_code(self, code):
-        code.mark_pos(self.pos)
-        
-        #  Generate code to evaluate this node and
-        #  its sub-expressions, and dispose of any
-        #  temporary results of its sub-expressions.
-        self.generate_subexpr_evaluation_code(code)
-
-        if self.is_temp:
-            self.allocate_temp_result(code)
-
-        self.generate_result_code(code)
-        if self.is_temp:
-            # If we are temp we do not need to wait until this node is disposed
-            # before disposing children.
-            self.generate_subexpr_disposal_code(code)
-            self.free_subexpr_temps(code)
-
-    def generate_disposal_code(self, code):
-        if self.is_temp:
-            if self.type.is_pyobject:
-                code.put_decref_clear(self.result(), self.ctype())
-        else:
-            # Already done if self.is_temp
-            self.generate_subexpr_disposal_code(code)
-
-    def generate_post_assignment_code(self, code):
-        if self.is_temp:
-            if self.type.is_pyobject:
-                code.putln("%s = 0;" % self.result())
-        else:
-            self.generate_subexpr_disposal_code(code)
-
-    def free_temps(self, code):
-        if self.is_temp:
-            if not self.type.is_void:
-                self.release_temp_result(code)
-        else:
-            self.free_subexpr_temps(code)
-        
-# ExprNode = NewTempExprNode     
-
 class AtomicExprNode(ExprNode):
-    #  Abstract base class for expression nodes which have
-    #  no sub-expressions.
-    
-    subexprs = []
-
-class AtomicNewTempExprNode(NewTempExprNode):
     # I do not dare to convert NameNode yet. This is now
     # ancestor of all former AtomicExprNode except
     # NameNode. Should be renamed to AtomicExprNode
@@ -747,7 +639,7 @@ class AtomicNewTempExprNode(NewTempExprNode):
     def generate_subexpr_disposal_code(self, code):
         pass
 
-class PyConstNode(AtomicNewTempExprNode):
+class PyConstNode(AtomicExprNode):
     #  Abstract base class for constant Python values.
     
     is_literal = 1
@@ -787,7 +679,7 @@ class EllipsisNode(PyConstNode):
         return Ellipsis
 
 
-class ConstNode(AtomicNewTempExprNode):
+class ConstNode(AtomicExprNode):
     # Abstract base type for literal constant nodes.
     #
     # value     string      C code fragment
@@ -1017,7 +909,7 @@ class IdentifierStringNode(ConstNode):
         return self.result_code
 
 
-class LongNode(AtomicNewTempExprNode):
+class LongNode(AtomicExprNode):
     #  Python long integer literal
     #
     #  value   string
@@ -1043,7 +935,7 @@ class LongNode(AtomicNewTempExprNode):
         code.put_gotref(self.py_result())
 
 
-class ImagNode(AtomicNewTempExprNode):
+class ImagNode(AtomicExprNode):
     #  Imaginary number literal
     #
     #  value   float    imaginary part
@@ -1070,7 +962,7 @@ class ImagNode(AtomicNewTempExprNode):
         
 
 
-class NameNode(AtomicNewTempExprNode):
+class NameNode(AtomicExprNode):
     #  Reference to a local or global variable name.
     #
     #  name            string    Python name of the variable
@@ -1425,7 +1317,7 @@ class NameNode(AtomicNewTempExprNode):
             else:
                 code.annotate(pos, AnnotationItem('c_call', 'c function', size=len(self.name)))
             
-class BackquoteNode(NewTempExprNode):
+class BackquoteNode(ExprNode):
     #  `expr`
     #
     #  arg    ExprNode
@@ -1453,7 +1345,7 @@ class BackquoteNode(NewTempExprNode):
         
 
 
-class ImportNode(NewTempExprNode):
+class ImportNode(ExprNode):
     #  Used as part of import statement implementation.
     #  Implements result = 
     #    __import__(module_name, globals(), None, name_list)
@@ -1489,7 +1381,7 @@ class ImportNode(NewTempExprNode):
         code.put_gotref(self.py_result())
 
 
-class IteratorNode(NewTempExprNode):
+class IteratorNode(ExprNode):
     #  Used as part of for statement implementation.
     #
     #  allocate_counter_temp/release_counter_temp needs to be called
@@ -1548,7 +1440,7 @@ class IteratorNode(NewTempExprNode):
         code.putln("}")
 
 
-class NextNode(AtomicNewTempExprNode):
+class NextNode(AtomicExprNode):
     #  Used as part of for statement implementation.
     #  Implements result = iterator.next()
     #  Created during analyse_types phase.
@@ -1607,7 +1499,7 @@ class NextNode(AtomicNewTempExprNode):
         code.putln("}")
 
 
-class ExcValueNode(AtomicNewTempExprNode):
+class ExcValueNode(AtomicExprNode):
     #  Node created during analyse_types phase
     #  of an ExceptClauseNode to fetch the current
     #  exception value.
@@ -1627,7 +1519,7 @@ class ExcValueNode(AtomicNewTempExprNode):
         pass
 
 
-class TempNode(NewTempExprNode):
+class TempNode(ExprNode):
     # Node created during analyse_types phase
     # of some nodes to hold a temporary value.
     #
@@ -1685,7 +1577,7 @@ class PyTempNode(TempNode):
 #
 #-------------------------------------------------------------------
 
-class IndexNode(NewTempExprNode):
+class IndexNode(ExprNode):
     #  Sequence indexing.
     #
     #  base     ExprNode
@@ -2012,7 +1904,7 @@ class IndexNode(NewTempExprNode):
         code.putln(code.error_goto(self.pos))
         code.putln("}")
 
-class SliceIndexNode(NewTempExprNode):
+class SliceIndexNode(ExprNode):
     #  2-element slice indexing
     #
     #  base      ExprNode
@@ -2214,7 +2106,7 @@ class SliceIndexNode(NewTempExprNode):
         return "<unused>"
     
 
-class SliceNode(NewTempExprNode):
+class SliceNode(ExprNode):
     #  start:stop:step in subscript list
     #
     #  start     ExprNode
@@ -2267,7 +2159,7 @@ class SliceNode(NewTempExprNode):
         code.put_gotref(self.py_result())
 
 
-class CallNode(NewTempExprNode):
+class CallNode(ExprNode):
     def analyse_as_type_constructor(self, env):
         type = self.function.analyse_as_type(env)
         if type and type.is_struct_or_union:
@@ -2661,7 +2553,7 @@ class GeneralCallNode(CallNode):
         code.put_gotref(self.py_result())
 
 
-class AsTupleNode(NewTempExprNode):
+class AsTupleNode(ExprNode):
     #  Convert argument to tuple. Used for normalising
     #  the * argument of a function call.
     #
@@ -2697,7 +2589,7 @@ class AsTupleNode(NewTempExprNode):
         code.put_gotref(self.py_result())
     
 
-class AttributeNode(NewTempExprNode):
+class AttributeNode(ExprNode):
     #  obj.attribute
     #
     #  obj          ExprNode
@@ -3041,7 +2933,7 @@ class AttributeNode(NewTempExprNode):
 #
 #-------------------------------------------------------------------
 
-class SequenceNode(NewTempExprNode):
+class SequenceNode(ExprNode):
     #  Base class for list and tuple constructor nodes.
     #  Contains common code for performing sequence unpacking.
     #
@@ -3366,7 +3258,7 @@ class ListNode(SequenceNode):
             # generate_evaluation_code which will do that.
 
 
-class ComprehensionNode(NewTempExprNode):
+class ComprehensionNode(ExprNode):
     subexprs = ["target"]
     child_attrs = ["loop", "append"]
 
@@ -3397,7 +3289,7 @@ class ComprehensionNode(NewTempExprNode):
         self.loop.annotate(code)
 
 
-class ComprehensionAppendNode(NewTempExprNode):
+class ComprehensionAppendNode(ExprNode):
     # Need to be careful to avoid infinite recursion:
     # target must not be in child_attrs/subexprs
     subexprs = ['expr']
@@ -3447,7 +3339,7 @@ class DictComprehensionAppendNode(ComprehensionAppendNode):
              code.error_goto_if(self.result(), self.pos)))
 
 
-class SetNode(NewTempExprNode):
+class SetNode(ExprNode):
     #  Set constructor.
 
     subexprs = ['args']
@@ -3491,7 +3383,7 @@ class SetNode(NewTempExprNode):
             arg.free_temps(code)
 
 
-class DictNode(NewTempExprNode):
+class DictNode(ExprNode):
     #  Dictionary constructor.
     #
     #  key_value_pairs  [DictItemNode]
@@ -3591,7 +3483,7 @@ class DictNode(NewTempExprNode):
         for item in self.key_value_pairs:
             item.annotate(code)
             
-class DictItemNode(NewTempExprNode):
+class DictItemNode(ExprNode):
     # Represents a single item in a DictNode
     #
     # key          ExprNode
@@ -3626,7 +3518,7 @@ class DictItemNode(NewTempExprNode):
         return iter([self.key, self.value])
 
 
-class ClassNode(NewTempExprNode):
+class ClassNode(ExprNode):
     #  Helper class used in the implementation of Python
     #  class definitions. Constructs a class object given
     #  a name, tuple of bases and class dictionary.
@@ -3669,7 +3561,7 @@ class ClassNode(NewTempExprNode):
         code.put_gotref(self.py_result())
 
 
-class UnboundMethodNode(NewTempExprNode):
+class UnboundMethodNode(ExprNode):
     #  Helper class used in the implementation of Python
     #  class definitions. Constructs an unbound method
     #  object from a class and a function.
@@ -3695,7 +3587,7 @@ class UnboundMethodNode(NewTempExprNode):
                 code.error_goto_if_null(self.result(), self.pos)))
         code.put_gotref(self.py_result())
 
-class PyCFunctionNode(AtomicNewTempExprNode):
+class PyCFunctionNode(AtomicExprNode):
     #  Helper class used in the implementation of Python
     #  class definitions. Constructs a PyCFunction object
     #  from a PyMethodDef struct.
@@ -3729,7 +3621,7 @@ compile_time_unary_operators = {
     '+': operator.pos,
 }
 
-class UnopNode(NewTempExprNode):
+class UnopNode(ExprNode):
     #  operator     string
     #  operand      ExprNode
     #
@@ -3805,7 +3697,7 @@ class UnopNode(NewTempExprNode):
         self.type = PyrexTypes.error_type
 
 
-class NotNode(NewTempExprNode):
+class NotNode(ExprNode):
     #  'not' operator
     #
     #  operand   ExprNode
@@ -3883,7 +3775,7 @@ class TildeNode(UnopNode):
         return "(~%s)" % self.operand.result()
 
 
-class AmpersandNode(NewTempExprNode):
+class AmpersandNode(ExprNode):
     #  The C address-of operator.
     #
     #  operand  ExprNode
@@ -3934,7 +3826,7 @@ def unop_node(pos, operator, operand):
         operand = operand)
 
 
-class TypecastNode(NewTempExprNode):
+class TypecastNode(ExprNode):
     #  C type cast
     #
     #  operand      ExprNode
@@ -4009,7 +3901,7 @@ class TypecastNode(NewTempExprNode):
             code.put_incref(self.result(), self.ctype())
 
 
-class SizeofNode(NewTempExprNode):
+class SizeofNode(ExprNode):
     #  Abstract base class for sizeof(x) expression nodes.
     
     type = PyrexTypes.c_size_t_type
@@ -4138,7 +4030,7 @@ def get_compile_time_binop(node):
                 % node.operator)
     return func
 
-class BinopNode(NewTempExprNode):
+class BinopNode(ExprNode):
     #  operator     string
     #  operand1     ExprNode
     #  operand2     ExprNode
@@ -4444,7 +4336,7 @@ class PowNode(NumBinopNode):
 # one could have a look at adding this again after /all/ classes
 # are converted to the new temp scheme. (The temp juggling cannot work
 # otherwise).
-class BoolBinopNode(NewTempExprNode):
+class BoolBinopNode(ExprNode):
     #  Short-circuiting boolean operation.
     #
     #  operator     string
@@ -4574,7 +4466,7 @@ class BoolBinopNode(NewTempExprNode):
         return (test_result, self.type.is_pyobject)
 
 
-class CondExprNode(NewTempExprNode):
+class CondExprNode(ExprNode):
     #  Short-circuiting conditional expression.
     #
     #  test        ExprNode
@@ -4781,7 +4673,7 @@ class CmpNode(object):
             return op
     
 
-class PrimaryCmpNode(NewTempExprNode, CmpNode):
+class PrimaryCmpNode(ExprNode, CmpNode):
     #  Non-cascaded comparison or first comparison of
     #  a cascaded sequence.
     #
@@ -5035,7 +4927,7 @@ def binop_node(pos, operator, operand1, operand2):
 #
 #-------------------------------------------------------------------
 
-class CoercionNode(NewTempExprNode):
+class CoercionNode(ExprNode):
     #  Abstract base class for coercion nodes.
     #
     #  arg       ExprNode       node being coerced
index 2400fd789d5293849a649b17b6f1442a561461da..c76e5d757fb68ce7170506267837d4bf44fb3b7b 100644 (file)
@@ -3084,10 +3084,8 @@ class InPlaceAssignmentNode(AssignmentNode):
         import ExprNodes
         self.rhs.generate_evaluation_code(code)
         self.dup.generate_subexpr_evaluation_code(code)
-        if isinstance(self.dup, ExprNodes.NewTempExprNode):
-            # This is because we're manually messing with subexpr nodes
-            if self.dup.is_temp:
-                self.dup.allocate_temp_result(code)
+        if self.dup.is_temp:
+            self.dup.allocate_temp_result(code)
         # self.dup.generate_result_code is run only if it is not buffer access
         if self.operator == "**":
             extra = ", Py_None"
index 1125657425777de69b5d34eab5276795778aa634..091a8f542b1c9065fe3b5bc4f5ee5780a496e688 100644 (file)
@@ -142,7 +142,7 @@ class ResultRefNode(AtomicExprNode):
         pass
 
 
-class EvalWithTempExprNode(ExprNodes.NewTempExprNode):
+class EvalWithTempExprNode(ExprNodes.ExprNode):
     # A wrapper around a subexpression that moves an expression into a
     # temp variable and provides it to the subexpression.