[cig-commits] r6935 - cs/babel/trunk

leif at geodynamics.org leif at geodynamics.org
Mon May 21 18:20:11 PDT 2007


Author: leif
Date: 2007-05-21 18:20:10 -0700 (Mon, 21 May 2007)
New Revision: 6935

Modified:
   cs/babel/trunk/babel.cc
Log:
Generate a 'tp_new' method if a class has a unique (non-overloaded)
constructor (ignoring the copy constructor).

Also: write a single dummy method for overloaded C++ functions.  It is
theoretically possible to call overloaded C++ functions from Python,
but the implementation would be complex; I don't want to waste time on
it at this phase.

The dummy method simply raises a Python exception.  I figure this
offers better feedback to the user than simply skipping overloaded
functions (which would result in a generic attribute error).  I plan
to do the same for private/protected member functions.


Modified: cs/babel/trunk/babel.cc
===================================================================
--- cs/babel/trunk/babel.cc	2007-05-21 20:39:46 UTC (rev 6934)
+++ cs/babel/trunk/babel.cc	2007-05-22 01:20:10 UTC (rev 6935)
@@ -31,6 +31,10 @@
     std::string source;
     // interned strings
     std::set<std::string> interns;
+    // track overload sets to ensure uniqueness of PyMethods
+    std::set<OverloadSet *> overloads;
+
+    Env &env;
     
     enum State {
         typeDecls,
@@ -42,7 +46,7 @@
     State state;
 
 public:      // funcs
-    PyExtModuleGenerator(std::string n, std::string s);
+    PyExtModuleGenerator(std::string n, std::string s, Env &env);
     virtual ~PyExtModuleGenerator() {}
 
     void generate(TranslationUnit *unit);
@@ -55,7 +59,9 @@
     
     bool visitFunctionVariable(Variable *var);
     void writePyMethod(Variable *var);
+    void writeNewMethod(CompoundType *ct);
     void writeDeallocMethod(CompoundType *ct);
+    void writeMethodPrologue(Variable *var, std::string &args);
     void scanFunctionParams(Variable *var,
                             std::string &format,
                             std::string &argnames,
@@ -67,9 +73,7 @@
     virtual bool visitMember(Member *obj);
     virtual void postvisitTypeSpecifier(TypeSpecifier *ts);
     void generateTypeObject(CompoundType *ct);
-    bool isDiscardedFunction(Variable *var);
-
-    std::string tpName(std::string funcName, CompoundType *ct);
+    bool isDiscardedFunction(Variable *var);    std::string tpName(std::string funcName, CompoundType *ct);
     std::string mangledMemberFuncName(Variable *var, std::string ns = "m");
     std::string mangledMemberFuncName(Variable *var, std::string funcName, std::string ns = "m");
     std::string mangledMemberFuncName(CompoundType *ct, std::string funcName, std::string ns);
@@ -77,9 +81,10 @@
 };
 
 
-PyExtModuleGenerator::PyExtModuleGenerator(std::string n, std::string s) :
+PyExtModuleGenerator::PyExtModuleGenerator(std::string n, std::string s, Env &env) :
     name(n),
-    source(s)
+    source(s),
+    env(env)
 {
 }
 
@@ -218,6 +223,12 @@
         interns.insert(var->name);
         break;
     case methods:
+        if (var->isOverloaded()) {
+            if (overloads.find(var->overload) != overloads.end()) {
+                return true;
+            }
+            overloads.insert(var->overload);
+        }
         this->writePyMethod(var);
         cout << endl;
         break;
@@ -248,13 +259,16 @@
     }
     cout << "static PyObject *" << mname << "(PyObject *self, PyObject *args, PyObject *kwds) {" << endl;
     
-    std::string format, argnames, varargs, args;
-    this->scanFunctionParams(var, format, argnames, varargs, args);
-    cout << "    PyObject *r;" << endl;
+    if (var->isOverloaded()) {
+        cout << "    PyErr_SetString(PyExc_NotImplementedError, \"cannot call overloaded function '"
+             << var->name << "' from Python\");" << endl
+             << "    return 0;" << endl
+             << "}" << endl;
+        return;
+    }
     
-    cout << "    static char *argnames[] = {" << argnames << "0};" << endl
-         << "    if (!PyArg_ParseTupleAndKeywords(args, kwds, \"" << format << "\", argnames" << varargs << ")) return 0;" << endl;
-
+    std::string args;
+    this->writeMethodPrologue(var, args);
     const char *pyXXX_FromXXX = this->returnValueConversionFunction(var);
     
     if (var->isMember() && !var->isStatic()) {
@@ -281,18 +295,73 @@
 }
 
 
+void PyExtModuleGenerator::writeNewMethod(CompoundType *ct)
+{
+    std::string tpNew = tpName("new", ct);
+    cout << "static PyObject *" << tpNew << "(PyTypeObject *type, PyObject *args, PyObject *kwds) {" << endl;
+    Variable *ctor0 = ct->getNamedField(env.constructorSpecialName, env, LF_INNER_ONLY);
+    // This is an elaborated AST, so there must be at least one constructor.
+    xassert(ctor0);
+    Variable *ctor = NULL;
+    if (ctor0->overload) {
+        SFOREACH_OBJLIST_NC(Variable, ctor0->overload->set, iter) {
+            Variable *ctorN = iter.data();
+            if (isCopyConstructor(ctorN, ct)) {
+                // skip
+            } else if (ctor) {
+                // we already found one
+                ctor = NULL;
+                break;
+            } else {
+                ctor = ctorN;
+            }
+        }
+    } else {
+        ctor = ctor0;
+    }
+    if (!ctor) {
+        cout << "    PyErr_SetString(PyExc_NotImplementedError, \"cannot call overloaded constructor from Python\");" << endl
+             << "    return 0;" << endl
+             << "}" << endl;
+        return;
+    }
+
+    // We found a unique constructor.
+    std::string args;
+    this->writeMethodPrologue(ctor, args);
+    
+    cout << "    PyObject *o = (*type->tp_alloc)(type, 0);" << endl
+         << "    ((struct __babel_obj_" << ct->name << " *)o)->_this = "
+         << "new " << ct->typedefVar->fullyQualifiedName() << "(" << args << ");" << endl
+         << "    return o;" << endl
+         << "}" << endl;
+}
+
+
 void PyExtModuleGenerator::writeDeallocMethod(CompoundType *ct)
 {
-    std::string dealloc = tpName("dealloc", ct);
-    cout << "static void " << dealloc << "(PyObject *self) {" << endl
-         << "    " << ct->toCString() << " *_this = ((struct __babel_obj_" << ct->name << " *)self)->_this;" << endl
+    std::string tpDealloc = tpName("dealloc", ct);
+    cout << "static void " << tpDealloc << "(PyObject *o) {" << endl
+         << "    " << ct->toCString() << " *_this = ((struct __babel_obj_" << ct->name << " *)o)->_this;" << endl
          << "    delete _this;" << endl
-         << "    (*self->ob_type->tp_free)(self);" << endl
-         << "}" << endl
-         << endl;
+         << "    (*o->ob_type->tp_free)(o);" << endl
+         << "}" << endl;
 }
 
 
+void PyExtModuleGenerator::writeMethodPrologue(Variable *var, std::string &args)
+{
+    std::string format, argnames, varargs;
+    this->scanFunctionParams(var, format, argnames, varargs, args);
+    cout << "    PyObject *r;" << endl;
+    
+    cout << "    static char *argnames[] = {" << argnames << "0};" << endl
+         << "    if (!PyArg_ParseTupleAndKeywords(args, kwds, \"" << format << "\", argnames" << varargs << ")) return 0;" << endl;
+
+    return;
+}
+
+
 void PyExtModuleGenerator::scanFunctionParams(Variable *var,
                                               std::string &format,
                                               std::string &argnames,
@@ -530,8 +599,12 @@
             cout << "    {0, 0, 0, 0}" << endl
                  << "};" << endl
                  << endl;
+            this->writeNewMethod(ct);
+            cout << endl;
             this->writeDeallocMethod(ct);
+            cout << endl;
             this->generateTypeObject(ct);
+            cout << endl;
             break;
         default:
             break;
@@ -595,8 +668,7 @@
         "    0, /*tp_cache*/\n"
         "    0, /*tp_subclasses*/\n"
         "    0, /*tp_weaklist*/\n"
-        "};\n"
-        "\n";
+        "};\n";
 }
 
 
@@ -671,7 +743,6 @@
         return;
     }
 
-    PyExtModuleGenerator visitor(argv[2], argv[1]);
     string inputFname = argv[1];
 
     // parse+tcheck (TODO: make this more convenient)
@@ -722,10 +793,13 @@
         // do elaboration
         ElabVisitor vis(strTable, tfac, unit);
         unit->traverse(vis.loweredVisitor);
+
+        // generate Python module
+        PyExtModuleGenerator visitor(argv[2], argv[1], env);
+        visitor.generate(unit);
+
     }
 
-    visitor.generate(unit);
-
     if (false) {
         // pretty printing
         OStreamOutStream out0(cout);



More information about the cig-commits mailing list