Changed the assigment code generator to emit
authorThomas Hunger <none@none>
Wed, 19 Sep 2007 13:40:17 +0000 (15:40 +0200)
committerThomas Hunger <none@none>
Wed, 19 Sep 2007 13:40:17 +0000 (15:40 +0200)
a direct change of a classes tp_dict instead
of SetAttr if assignment code is executed in
a class body.
To tell the code generator that we have a class
entry, entry has a new attribute "is_member".

Cython/Compiler/ExprNodes.py
Cython/Compiler/Symtab.py

index 31ad5379d9b3c8ecbc89109dad679893d99d8dc0..aa147d11ab966c46f1cd837e023bd4d0e5810135 100644 (file)
@@ -814,24 +814,45 @@ class NameNode(AtomicExprNode):
         entry = self.entry
         if entry is None:
             return # There was an error earlier
+
+        # is_pyglobal seems to be True for module level-globals only.
+        # We use this to access class->tp_dict if necessary.
         if entry.is_pyglobal:
             namespace = self.entry.namespace_cname
-            if Options.intern_names:
-                code.put_error_if_neg(self.pos, 
-                    'PyObject_SetAttr(%s, %s, %s)' % (
-                        namespace, 
-                        entry.interned_cname,
-                        rhs.py_result()))
-            else:
-                code.put_error_if_neg(self.pos,
-                    'PyObject_SetAttrString(%s, "%s", %s)' % (
-                        namespace, 
-                        entry.name,
-                        rhs.py_result()))
-            if debug_disposal_code:
-                print "NameNode.generate_assignment_code:"
-                print "...generating disposal code for", rhs
-            rhs.generate_disposal_code(code)
+            if entry.is_member:
+                # if we entry is a member we have to cheat: SetAttr does not work
+                # on types, so we create a descriptor which is then added to tp_dict
+                if Options.intern_names:
+                    code.put_error_if_neg(self.pos,
+                        'PyDict_SetItem(%s->tp_dict, %s, %s)' % (
+                            namespace,
+                            entry.interned_cname,
+                            rhs.py_result()))
+                else:
+                    code.put_error_if_neg(self.pos,
+                        'PyDict_SetItemString(%s->tp_dict, %s, %s)' % (
+                            namespace,
+                            entry.name,
+                            rhs.py_result()))
+
+            else: 
+                if Options.intern_names:
+                    code.put_error_if_neg(self.pos,
+                        'PyObject_SetAttr(%s, %s, %s)' % (
+                            namespace,
+                            entry.interned_cname,
+                            rhs.py_result()))
+                else:
+                    code.put_error_if_neg(self.pos,
+                        'PyObject_SetAttrString(%s, "%s", %s)' % (
+                            namespace, 
+                            entry.name,
+                            rhs.py_result()))
+                if debug_disposal_code:
+                    print "NameNode.generate_assignment_code:"
+                    print "...generating disposal code for", rhs
+                rhs.generate_disposal_code(code)
+                
         else:
             if self.type.is_pyobject:
                 #print "NameNode.generate_assignment_code: to", self.name ###
index 2f0c0c3ea476539ad85428f1609229c98cacdac4..9279282e8fca622f045f2d97473d5a7b1c4878b0 100644 (file)
@@ -30,6 +30,7 @@ class Entry:
     #                               or class attribute during
     #                               class construction
     # is_special       boolean    Is a special class method
+    # is_member        boolean    Is an assigned class member
     # is_variable      boolean    Is a variable
     # is_cfunction     boolean    Is a C function
     # is_cmethod       boolean    Is a C method of an extension type
@@ -72,6 +73,7 @@ class Entry:
     is_cglobal = 0
     is_pyglobal = 0
     is_special = 0
+    is_member = 0
     is_variable = 0
     is_cfunction = 0
     is_cmethod = 0
@@ -979,10 +981,7 @@ class ClassScope(Scope):
         return self.outer_scope.add_string_const(value)
 
     def lookup(self, name):
-        print "*** Looking for", name, "in ClassScope", self
-        print self.entries
         res = Scope.lookup(self, name)
-        print "got", res, res.type
         return res
     
 
@@ -1095,7 +1094,10 @@ class CClassScope(ClassScope):
             # Add an entry for a class attribute.
             entry = Scope.declare_var(self, name, type, pos, 
                 cname, visibility, is_cdef)
-            entry.is_pyglobal = 1
+            entry.is_member = 1
+            entry.is_pyglobal = 1 # xxx: is_pyglobal changes behaviour in so many places that
+                                  # I keep it in for now. is_member should be enough
+                                  # later on
             entry.namespace_cname = "(PyObject *)%s" % self.parent_type.typeptr_cname
             if Options.intern_names:
                 entry.interned_cname = self.intern(name)