[cig-commits] r6505 - cs/babel/trunk/spike/Spike/Compiler

leif at geodynamics.org leif at geodynamics.org
Tue Apr 3 20:43:08 PDT 2007


Author: leif
Date: 2007-04-03 20:43:07 -0700 (Tue, 03 Apr 2007)
New Revision: 6505

Modified:
   cs/babel/trunk/spike/Spike/Compiler/ExprNodes.py
   cs/babel/trunk/spike/Spike/Compiler/Nodes.py
   cs/babel/trunk/spike/Spike/Compiler/Symtab.py
Log:
Allow Pyre components to be declared from Pyrex code.  This was
prevented by the fact that Pyrex passes an empty dictionary to
PyClass_New() -- and therefore the __init__ methods in Pyre's
metaclasses likewise get fed an empty dictionary.

Currently, Pyrex-based Components must be declared in the CIG-Pyre
abbreviated style:

    from pyre.components import Component
    class Tomato(Component):
        name = "tomato"
        import pyre.inventory
        color = pyre.inventory.str("color", default="red")

One can't use 'Inventory' because I haven't fixed Pyrex's "no nested
classes" limitation (yet).

(As for Spike: it still doesn't have grammar rules for classes.)


Modified: cs/babel/trunk/spike/Spike/Compiler/ExprNodes.py
===================================================================
--- cs/babel/trunk/spike/Spike/Compiler/ExprNodes.py	2007-04-02 22:08:35 UTC (rev 6504)
+++ cs/babel/trunk/spike/Spike/Compiler/ExprNodes.py	2007-04-04 03:43:07 UTC (rev 6505)
@@ -742,7 +742,7 @@
         # Reference to C array turns into pointer to first element.
         while self.type.is_array:
             self.type = self.type.element_ptr_type()
-        if self.entry.is_pyglobal or self.entry.is_builtin:
+        if self.entry.is_pyglobal or self.entry.is_builtin or self.entry.is_pyclass:
             assert self.type.is_pyobject, "Python global or builtin not a Python object"
             self.is_temp = 1
             if Options.intern_names:
@@ -834,6 +834,27 @@
                     self.entry.name,
                     self.result_code, 
                     code.error_goto(self.pos)))		
+        elif entry.is_pyclass:
+            namespace = entry.dict_cname
+            if Options.intern_names:
+                #assert entry.interned_cname is not None
+                code.putln(
+                    '%s = PyDict_GetItem(%s, %s); if (!%s) %s' % (
+                    self.result_code,
+                    namespace,
+                    entry.interned_cname,
+                    self.result_code,
+                    code.error_goto(self.pos)))
+            else:
+                code.putln(
+                    '%s = PyDict_GetItem(%s, "%s"); if (!%s) %s' % (
+                    self.result_code,
+                    namespace,
+                    self.entry.name,
+                    self.result_code,
+                    code.error_goto(self.pos)))
+            # PyDict_GetItem returns a borrowed reference.
+            code.put_incref(self.result_code, self.ctype())
 
     def generate_assignment_code(self, rhs, code):
         entry = self.entry
@@ -859,6 +880,26 @@
                 print "NameNode.generate_assignment_code:"
                 print "...generating disposal code for", rhs
             rhs.generate_disposal_code(code)
+        elif entry.is_pyclass:
+            namespace = self.entry.dict_cname
+            if Options.intern_names:
+                code.putln(
+                    'if (PyDict_SetItem(%s, %s, %s) < 0) %s' % (
+                        namespace, 
+                        entry.interned_cname,
+                        rhs.py_result(), 
+                        code.error_goto(self.pos)))
+            else:
+                code.putln(
+                    'if (PyDict_SetItemString(%s, "%s", %s) < 0) %s' % (
+                        namespace, 
+                        entry.name,
+                        rhs.py_result(), 
+                        code.error_goto(self.pos)))
+            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 ###
@@ -1981,31 +2022,6 @@
                 code.error_goto(self.pos)))
 
 
-class UnboundMethodNode(ExprNode):
-    #  Helper class used in the implementation of Python
-    #  class definitions. Constructs an unbound method
-    #  object from a class and a function.
-    #
-    #  class_cname   string     C var holding the class object
-    #  function      ExprNode   Function object
-    
-    subexprs = ['function']
-    
-    def analyse_types(self, env):
-        self.function.analyse_types(env)
-        self.type = py_object_type
-        self.is_temp = 1
-    
-    def generate_result_code(self, code):
-        code.putln(
-            "%s = PyMethod_New(%s, 0, %s); if (!%s) %s" % (
-                self.result_code,
-                self.function.py_result(),
-                self.class_cname,
-                self.result_code,
-                code.error_goto(self.pos)))
-
-
 class PyCFunctionNode(AtomicExprNode):
     #  Helper class used in the implementation of Python
     #  class definitions. Constructs a PyCFunction object
@@ -3431,15 +3447,44 @@
     PyObject *bases, PyObject *dict, PyObject *name, char *modname)
 {
     PyObject *py_modname;
+    PyObject *new_class = 0;
+    PyObject *method = 0;
     PyObject *result = 0;
+    PyObject *key, *value;
+    int pos;
     
     py_modname = PyString_FromString(modname);
     if (!py_modname)
         goto bad;
     if (PyDict_SetItemString(dict, "__module__", py_modname) < 0)
         goto bad;
-    result = PyClass_New(bases, dict, name);
+    new_class = PyClass_New(bases, dict, name);
+    if (!new_class)
+        goto bad;
+    /*
+     * Manually wrap PyCFunction objects in PyMethod objects.  This is
+     * necessary because -- whereas PyFunction_Type's tp_descr_get
+     * slot points to the func_descr_get "bind a function to an
+     * object" magic function -- PyCFunction_Type's tp_descr_get slot
+     * is null... i.e., "built-in" (native) functions don't get the
+     * object-binding magic.
+     */
+    pos = 0;
+    while (PyDict_Next(dict, &pos, &key, &value)) {
+        if (PyCFunction_Check(value)) {
+            Py_XDECREF(method);
+            method = PyMethod_New(value, 0, new_class);
+            if (!method)
+                goto bad;
+            if (PyObject_SetAttr(new_class, key, method) < 0)
+                goto bad;
+        }
+    }
+    result = new_class;
+    Py_INCREF(result);
 bad:
+    Py_XDECREF(method);
+    Py_XDECREF(new_class);
     Py_XDECREF(py_modname);
     return result;
 }

Modified: cs/babel/trunk/spike/Spike/Compiler/Nodes.py
===================================================================
--- cs/babel/trunk/spike/Spike/Compiler/Nodes.py	2007-04-02 22:08:35 UTC (rev 6504)
+++ cs/babel/trunk/spike/Spike/Compiler/Nodes.py	2007-04-04 03:43:07 UTC (rev 6505)
@@ -2200,10 +2200,8 @@
         import ExprNodes
         self.assmt = SingleAssignmentNode(self.pos,
             lhs = ExprNodes.NameNode(self.pos, name = self.name),
-            rhs = ExprNodes.UnboundMethodNode(self.pos, 
-                class_cname = env.class_obj_cname,
-                function = ExprNodes.PyCFunctionNode(self.pos,
-                    pymethdef_cname = self.entry.pymethdef_cname)))
+            rhs = ExprNodes.PyCFunctionNode(self.pos,
+                                            pymethdef_cname = self.entry.pymethdef_cname))
         self.assmt.analyse_declarations(env)
         self.assmt.analyse_expressions(env)
             
@@ -2554,14 +2552,13 @@
     
     def analyse_expressions(self, env):
         self.dict.analyse_expressions(env)
-        self.classobj.analyse_expressions(env)
         genv = env.global_scope()
         cenv = PyClassScope(name = self.name, outer_scope = genv)
         cenv.class_dict_cname = self.dict.result_code
-        cenv.class_obj_cname = self.classobj.result_code
         self.scope = cenv
         self.body.analyse_declarations(cenv)
         self.body.analyse_expressions(cenv)
+        self.classobj.analyse_expressions(env)
         self.target.analyse_target_expression(env)
         self.dict.release_temp(env)
         self.classobj.release_temp(env)
@@ -2575,8 +2572,8 @@
     
     def generate_execution_code(self, code):
         self.dict.generate_evaluation_code(code)
-        self.classobj.generate_evaluation_code(code)
         self.body.generate_execution_code(code)
+        self.classobj.generate_evaluation_code(code)
         self.target.generate_assignment_code(self.classobj, code)
         self.dict.generate_disposal_code(code)
 

Modified: cs/babel/trunk/spike/Spike/Compiler/Symtab.py
===================================================================
--- cs/babel/trunk/spike/Spike/Compiler/Symtab.py	2007-04-02 22:08:35 UTC (rev 6504)
+++ cs/babel/trunk/spike/Spike/Compiler/Symtab.py	2007-04-04 03:43:07 UTC (rev 6505)
@@ -29,7 +29,7 @@
     # is_builtin       boolean    Is a Python builtin name
     # is_cglobal       boolean    Is a C global variable
     # is_pyglobal      boolean    Is a Python module-level variable
-    #                               or class attribute during
+    # is_pyclass       boolean    Is a Python class attribute during
     #                               class construction
     # is_variable      boolean    Is a variable
     # is_cfunction     boolean    Is a C function
@@ -72,6 +72,7 @@
     is_builtin = 0
     is_cglobal = 0
     is_pyglobal = 0
+    is_pyclass = 0
     is_variable = 0
     is_cfunction = 0
     is_spikefunction = 0
@@ -902,8 +903,8 @@
         # Add an entry for a class attribute.
         entry = Scope.declare_var(self, name, type, pos, 
             cname, visibility, is_cdef)
-        entry.is_pyglobal = 1
-        entry.namespace_cname = self.class_obj_cname
+        entry.is_pyclass = 1
+        entry.dict_cname = self.class_dict_cname
         if Options.intern_names:
             entry.interned_cname = self.intern(name)
         return entry



More information about the cig-commits mailing list