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

leif at geodynamics.org leif at geodynamics.org
Sun May 27 04:25:19 PDT 2007


Author: leif
Date: 2007-05-27 04:25:19 -0700 (Sun, 27 May 2007)
New Revision: 6980

Modified:
   cs/babel/trunk/mkpyxm.cc
Log:
Cleanly separated syntax processing (C++ AST treewalk) from semantics
(a Python extension module).  This elminates the clumsy 'state'
variable and the multiple passes over the AST.


Modified: cs/babel/trunk/mkpyxm.cc
===================================================================
--- cs/babel/trunk/mkpyxm.cc	2007-05-26 23:38:07 UTC (rev 6979)
+++ cs/babel/trunk/mkpyxm.cc	2007-05-27 11:25:19 UTC (rev 6980)
@@ -2,6 +2,7 @@
 #include <iostream>       // cout
 #include <sstream>
 #include <set>
+#include <vector>
 
 #include <stdlib.h>       // exit, atoi
 #include <string.h>
@@ -20,266 +21,83 @@
 
 #include "cc_print.h"     // PrintEnv
 
-// ---------------------- PyExtModuleVisitor ------------------------
 
+/**********************************************************************
+ * PyMethod & PyType                                                  *
+ **********************************************************************/
 
-class PyExtModuleGenerator : public ASTVisitor {
-private:      // data
-    // name of module
-    std::string name;
-    // C/C++ source filename
-    std::string source;
-    // interned strings
-    std::set<std::string> interns;
-    // these ensure the uniqueness of PyMethods
-    std::set<Variable *> vars;
-    std::set<OverloadSet *> overloads;
-    // global method table
-    std::set<std::string> gmt;
 
-    Env &env;
-    
-    enum State {
-        typeDecls,
-        collectInterns,
-        methods,
-        typeObjs,
-        modInitFunc,
-    };
-    State state;
+class PyType;
 
-public:      // funcs
-    PyExtModuleGenerator(std::string n, std::string s, Env &env);
-    virtual ~PyExtModuleGenerator() {}
 
-    void generate(TranslationUnit *unit);
-    void generatePreamble();
-    void generatePostamble();
-    void generateModInitFunc(TranslationUnit *unit);
-    void generateTypeInit(CompoundType *ct);
+class PyMethod {
+    Variable *var;
+    PyType *type;
 
-    virtual bool visitDeclarator(Declarator *obj);
-    virtual bool visitFunction(Function *f);
-    
-    void 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,
-                            std::string &varargs,
-                            std::string &args);
-    const char *returnValueConversionFunction(Variable *var);
+public:
+    PyMethod(Variable *v, PyType *t);
+    void generateSource();
 
-    virtual bool visitTypeSpecifier(TypeSpecifier *ts);
-    virtual bool visitMember(Member *obj);
-    virtual void postvisitTypeSpecifier(TypeSpecifier *ts);
-    void generateTypeObject(CompoundType *ct);
-    bool isDiscardedFunction(Variable *var);
-    bool uniqify(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);
+    std::string name() const { return var->name; }
+
+    static void writePrologue(Variable *var, std::string &args);
+    static void scanFunctionParams(Variable *var,
+                                   std::string &format,
+                                   std::string &argnames,
+                                   std::string &varargs,
+                                   std::string &args);
+private:
+    void writePrologue(std::string &args) { writePrologue(var, args); }
+    const char *returnValueConversionFunction();
+    std::string mangledName();
 };
 
 
-PyExtModuleGenerator::PyExtModuleGenerator(std::string n, std::string s, Env &env) :
-    name(n),
-    source(s),
-    env(env)
-{
-}
+class PyType {
+    CompoundType *ct;
+    Env &env;
 
+public:
+    std::vector<PyMethod *> methods;
 
-void PyExtModuleGenerator::generate(TranslationUnit *unit)
-{
-    cout << "/* Generated by Babel */" << endl
-         << endl;
+public:
+    PyType(CompoundType *t, Env &e);
+    void addMethod(PyMethod *method) { methods.push_back(method); }
     
-    cout << "#include \"" << source << "\"" << endl
-         << endl;
-    
-    cout << "#include \"Python.h\"" << endl
-         << endl;
+    void generateDecl();
+    void generateSource(std::string moduleName);
+    void generateInitCode();
 
-    this->generatePreamble();
+    void writeThisDecl();
 
-    state = typeDecls;
-    unit->traverse(*this);
-    cout << endl;
+private:
+    void generateMethodTable();
+    void generateNewMethod();
+    void generateDeallocMethod();
+    void generateObject(std::string moduleName);
     
-    state = collectInterns;
-    unit->traverse(*this);
-    for (std::set<std::string>::const_iterator i = interns.begin();
-         i != interns.end();
-         ++i) {
-        cout << "static PyObject *__babel_n_" << *i << ";" << endl;
-    }
-    cout << endl;
-    
-    state = methods;
-    unit->traverse(*this);
-    cout << endl;
+    std::string tpName(std::string funcName);
 
-    // reset uniquify
-    vars.clear();
-    overloads.clear();
-    
-    cout << "static __Babel_InternTabEntry __babel_intern_tab[] = {" << endl;
-    for (std::set<std::string>::const_iterator i = interns.begin();
-         i != interns.end();
-         ++i) {
-        cout << "    {&__babel_n_" << *i << ", \"" << *i << "\"}," << endl;
-    }
-    cout << "    {0, 0}" << endl
-         << "};" << endl
-         << endl;
+public:
+    std::string mangledMemberFuncName(std::string funcName, std::string ns = "m");
+};
 
-    state = typeObjs;
-    unit->traverse(*this);
-    cout << endl;
-    
-    cout << "static struct PyMethodDef __babel_methods[] = {" << endl;
-    for (std::set<std::string>::const_iterator i = gmt.begin();
-         i != gmt.end();
-         ++i) {
-        cout << "    {\"" << *i << "\", (PyCFunction)__babel_m_" << *i << ", METH_VARARGS|METH_KEYWORDS, 0}," << endl;
-    }
-    cout << "    {0, 0, 0, 0}" << endl
-         << "};" << endl
-         << endl;
 
-    this->generateModInitFunc(unit);
+/**********************************************************************
+ * PyMethod methods                                                   *
+ **********************************************************************/
 
-    this->generatePostamble();
-    
-}
 
-
-void PyExtModuleGenerator::generatePreamble()
+PyMethod::PyMethod(Variable *v, PyType *t) :
+    var(v),
+    type(t)
 {
-    cout << "typedef struct {PyObject **p; char *s;} __Babel_InternTabEntry;" << endl
-         << endl
-         << "static PyObject *__babel_m;" << endl
-         << endl
-         << "static int __Babel_InternStrings(__Babel_InternTabEntry *t);" << endl
-         << endl;
 }
 
 
-void PyExtModuleGenerator::generatePostamble()
+void PyMethod::generateSource()
 {
-    cout << "static int __Babel_InternStrings(__Babel_InternTabEntry *t) {" << endl
-         << "    while (t->p) {" << endl
-         << "        *t->p = PyString_InternFromString(t->s);" << endl
-         << "        if (!*t->p)" << endl
-         << "            return -1;" << endl
-         << "        ++t;" << endl
-         << "    }" << endl
-         << "    return 0;" << endl
-         << "}" << endl
-         << endl;
-}
-
-
-void PyExtModuleGenerator::generateModInitFunc(TranslationUnit *unit)
-{
-    cout << "PyMODINIT_FUNC init" << name <<"(void) {" << endl
-         << "    __babel_m = Py_InitModule4(\"" << name << "\", __babel_methods, 0, 0, PYTHON_API_VERSION);" << endl
-         << "    if (!__babel_m) return;" << endl
-         << "    if (__Babel_InternStrings(__babel_intern_tab) < 0) return;" << endl;
-    state = modInitFunc;
-    unit->traverse(*this);
-    cout << "    return;" << endl
-         << "}" << endl
-         << endl;
-}
-
-
-void PyExtModuleGenerator::generateTypeInit(CompoundType *ct)
-{
-    std::string ptype = std::string("&__babel_type_") + ct->name;
-    cout << "    if (PyType_Ready(" << ptype << ") < 0) return;" << endl
-         << "    if (PyObject_SetAttrString(__babel_m, \"" << ct->name << "\", "
-         << "(PyObject *)" << ptype << ") < 0) return;" << endl
-         << "    __babel_ptype_" << ct->name << " = " << ptype << ";" << endl;
-}
-
-
-bool PyExtModuleGenerator::visitDeclarator(Declarator *obj)
-{
-    Variable *var = obj->var;
-    if (var->type->isFunctionType()) {
-        if (!this->isDiscardedFunction(var)) {
-            this->visitFunctionVariable(var);
-       }
-    }
-    return true;
-}
-
-
-bool PyExtModuleGenerator::visitFunction(Function *f)
-{
-    // This is called only for function bodies.  But 'visitDeclarator'
-    // is called for prototypes as well; so all our processing is done
-    // there.
-    if (false) {
-        Variable *var = f->nameAndParams->var;
-        if (!this->isDiscardedFunction(var)) {
-            this->visitFunctionVariable(var);
-        }
-    }
-    return true;
-}
-
-
-void PyExtModuleGenerator::visitFunctionVariable(Variable *var)
-{
-    switch (state) {
-    case typeDecls:
-        break;
-    case collectInterns:
-        interns.insert(var->name);
-        break;
-    case methods:
-        if (this->uniqify(var)) {
-            this->writePyMethod(var);
-            cout << endl;
-            if (!var->isMember()) {
-                gmt.insert(var->name);
-            }
-        }
-        break;
-    case typeObjs:
-        if (var->isMember() && this->uniqify(var)) {
-            // write a method table entry
-            cout << "    {\"" << var->name << "\", "
-                 << "(PyCFunction)" << mangledMemberFuncName(var)
-                 << ", METH_VARARGS|METH_KEYWORDS, 0}," << endl;
-        }
-        break;
-    default:
-        break;
-    }
-    if (false) {
-        cout << "    " << var->toCString() << endl;
-        cout << "    " << var->toQualifiedString() << endl;
-    }
-    return;
-}
-
-
-void PyExtModuleGenerator::writePyMethod(Variable *var)
-{
-    std::string mname;
-    if (var->isMember()) {
-        mname = this->mangledMemberFuncName(var);
-    } else {
-        mname = std::string("__babel_m_") + var->name;
-    }
+    std::string mname = this->mangledName();
     cout << "static PyObject *" << mname << "(PyObject *self, PyObject *args, PyObject *kwds) {" << endl;
     
     if (var->isOverloaded()) {
@@ -291,14 +109,13 @@
     }
     
     std::string args;
-    this->writeMethodPrologue(var, args);
-    const char *pyXXX_FromXXX = this->returnValueConversionFunction(var);
+    this->writePrologue(args);
+    const char *pyXXX_FromXXX = this->returnValueConversionFunction();
     
-    if (var->isMember() && !var->isStaticMember()) {
+    if (type && !var->isStaticMember()) {
         // method
-        CompoundType *ct = var->scope->curCompound;
-        cout << "    Py_INCREF(self);" << endl
-             << "    " << ct->toCString() << " *_this = ((struct __babel_obj_" << ct->name << " *)self)->_this;" << endl;
+        cout << "    Py_INCREF(self);" << endl;
+        type->writeThisDecl();
         if (pyXXX_FromXXX) {
             cout << "    r = " << pyXXX_FromXXX << "(_this->" << var->name << "(" << args << "));" << endl;
         } else {
@@ -318,64 +135,10 @@
 }
 
 
-void PyExtModuleGenerator::writeNewMethod(CompoundType *ct)
+void PyMethod::writePrologue(Variable *var, std::string &args)
 {
-    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->fullyQualifiedName0() << "(" << args << ");" << endl
-         << "    return o;" << endl
-         << "}" << endl;
-}
-
-
-void PyExtModuleGenerator::writeDeallocMethod(CompoundType *ct)
-{
-    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
-         << "    (*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);
+    scanFunctionParams(var, format, argnames, varargs, args);
     cout << "    PyObject *r;" << endl;
     
     cout << "    static char *argnames[] = {" << argnames << "0};" << endl
@@ -385,11 +148,11 @@
 }
 
 
-void PyExtModuleGenerator::scanFunctionParams(Variable *var,
-                                              std::string &format,
-                                              std::string &argnames,
-                                              std::string &varargs,
-                                              std::string &args)
+void PyMethod::scanFunctionParams(Variable *var,
+                                  std::string &format,
+                                  std::string &argnames,
+                                  std::string &varargs,
+                                  std::string &args)
 {
     int ct = 0;
     SFOREACH_OBJLIST(Variable, var->type->asFunctionType()->params, iter) {
@@ -473,7 +236,7 @@
 }
 
 
-const char *PyExtModuleGenerator::returnValueConversionFunction(Variable *var)
+const char *PyMethod::returnValueConversionFunction()
 {
     Type *rt = var->type->asFunctionType()->retType;
     const char *pyXXX_FromXXX = "<error>";
@@ -538,107 +301,136 @@
 }
 
 
-bool PyExtModuleGenerator::visitTypeSpecifier(TypeSpecifier *ts)
+std::string PyMethod::mangledName()
 {
-    switch (ts->kind()) {
-    case TypeSpecifier::TS_CLASSSPEC: {
-        TS_classSpec *spec = ts->asTS_classSpec();
-        CompoundType *ct = spec->ctype;
-        if (!ct->name) {
-            return true; // bail on anonymous classes
-        }
-        switch (state) {
-        case typeDecls:
-            cout << "struct __babel_obj_" << ct->name << " {" << endl
-                 << "    PyObject_HEAD" << endl
-                 << "    " << ct->toCString() << " *_this;" << endl
-                 << "};" << endl
-                 << endl
-                 << "static PyTypeObject *__babel_ptype_"<< ct->name << " = 0;" << endl
-                 << endl;
-            break;
-        case typeObjs:
-            // start the method table
-            cout << "static struct PyMethodDef __babel_methods_" << ct->name << "[] = {" << endl;
-            break;
-        case modInitFunc:
-            this->generateTypeInit(ct);
-        default:
-            break;
-        }
-        break; }
-    default:
-        break;
+    std::string mname;
+    if (type) {
+        mname = type->mangledMemberFuncName(var->name);
+    } else {
+        mname = std::string("__babel_m_") + var->name;
     }
-    return true;
+    return mname;
 }
 
 
-bool PyExtModuleGenerator::visitMember(Member *obj)
+/**********************************************************************
+ * PyType methods                                                     *
+ **********************************************************************/
+
+
+PyType::PyType(CompoundType *t, Env &e) :
+    ct(t),
+    env(e)
 {
-    if (obj->isMR_func()) {
-        // This fires for function bodies inside class declarations.
-        if (false) {
-            Function *f = obj->asMR_func()->f;
-            Variable *var = f->nameAndParams->var;
-            cout << "member function " << *(f->nameAndParams->getDeclaratorId()) << " (" << var->name << ")" << endl;
-            cout << "    " << var->toCString() << endl;
-            cout << "    " << var->toQualifiedString() << endl;
-        }
-    } else if (obj->isMR_access()) {
-    } else if (obj->isMR_decl()) {
-        if (false) {
-            cout << "member decl" << endl;
-            Declaration *d = obj->asMR_decl()->d;
-            d->debugPrint(cout, 0);
-        }
+}
+
+
+void PyType::generateDecl()
+{
+    cout << "struct __babel_obj_" << ct->name << " {" << endl
+         << "    PyObject_HEAD" << endl
+         << "    " << ct->toCString() << " *_this;" << endl
+         << "};" << endl
+         << endl
+         << "static PyTypeObject *__babel_ptype_"<< ct->name << " = 0;" << endl
+         << endl;
+}
+
+
+void PyType::generateSource(std::string moduleName)
+{
+    this->generateMethodTable();
+    cout << endl;
+    this->generateNewMethod();
+    cout << endl;
+    this->generateDeallocMethod();
+    cout << endl;
+    this->generateObject(moduleName);
+    cout << endl;
+}
+
+
+void PyType::generateMethodTable()
+{
+    cout << "static struct PyMethodDef __babel_methods_" << ct->name << "[] = {" << endl;
+    
+    for (std::vector<PyMethod *>::const_iterator m = methods.begin();
+         m != methods.end();
+         ++m) {
+        std::string name = (*m)->name();
+        cout << "    {\"" << name << "\", "
+             << "(PyCFunction)" << mangledMemberFuncName(name)
+             << ", METH_VARARGS|METH_KEYWORDS, 0}," << endl;
     }
-    return true;
+
+    cout << "    {0, 0, 0, 0}" << endl
+         << "};" << endl;
 }
 
 
-void PyExtModuleGenerator::postvisitTypeSpecifier(TypeSpecifier *ts)
+void PyType::generateNewMethod()
 {
-    switch (ts->kind()) {
-    case TypeSpecifier::TS_CLASSSPEC: {
-        TS_classSpec *spec = ts->asTS_classSpec();
-        CompoundType *ct = spec->ctype;
-        if (!ct->name) {
-            return; // bail on anonymous classes
+    std::string tpNew = tpName("new");
+    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;
+            }
         }
-        switch (state) {
-        case typeObjs:
-            // finish the method table
-            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;
-        }
-        break; }
-    default:
-        break;
+    } else {
+        ctor = ctor0;
     }
-    return;
+    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;
+    PyMethod::writePrologue(ctor, args);
+    
+    cout << "    PyObject *o = (*type->tp_alloc)(type, 0);" << endl
+         << "    ((struct __babel_obj_" << ct->name << " *)o)->_this = "
+         << "new " << ct->typedefVar->fullyQualifiedName0() << "(" << args << ");" << endl
+         << "    return o;" << endl
+         << "}" << endl;
 }
 
 
-void PyExtModuleGenerator::generateTypeObject(CompoundType *ct)
+void PyType::generateDeallocMethod()
 {
-    std::string tpDealloc = tpName("dealloc", ct);
-    std::string tpNew = tpName("new", ct);
+    std::string tpDealloc = tpName("dealloc");
+    cout << "static void " << tpDealloc << "(PyObject *self) {" << endl;
+    this->writeThisDecl();
+    cout << "    delete _this;" << endl
+         << "    (*self->ob_type->tp_free)(self);" << endl
+         << "}" << endl;
+}
+
+
+void PyType::generateObject(std::string moduleName)
+{
+    std::string tpDealloc = tpName("dealloc");
+    std::string tpNew = tpName("new");
     cout <<
         "PyTypeObject __babel_type_" << ct->name << " = {\n"
         "    PyObject_HEAD_INIT(0)\n"
         "    0, /*ob_size*/\n"
-        "    \"" << name << "." << ct->name << "\", /*tp_name*/\n"
+        "    \"" << moduleName << "." << ct->name << "\", /*tp_name*/\n"
         "    sizeof(struct __babel_obj_" << ct->name << "), /*tp_basicsize*/\n"
         "    0, /*tp_itemsize*/\n"
         "    " << tpDealloc << ", /*tp_dealloc*/\n"
@@ -686,6 +478,412 @@
 }
 
 
+void PyType::generateInitCode()
+{
+    std::string ptype = std::string("&__babel_type_") + ct->name;
+    cout << "    if (PyType_Ready(" << ptype << ") < 0) return;" << endl
+         << "    if (PyObject_SetAttrString(__babel_m, \"" << ct->name << "\", "
+         << "(PyObject *)" << ptype << ") < 0) return;" << endl
+         << "    __babel_ptype_" << ct->name << " = " << ptype << ";" << endl;
+}
+
+
+std::string PyType::tpName(std::string funcName)
+{
+    return this->mangledMemberFuncName(funcName, "tp");
+}
+
+
+std::string PyType::mangledMemberFuncName(std::string funcName, std::string ns)
+{
+    std::string className = ct->typedefVar->fullyQualifiedName0().c_str();
+    std::stringstream s;
+    s << "__babel_" << ns << "_" << className.length();
+    for (std::string::const_iterator i = className.begin(); i != className.end(); ++i) {
+        char c = *i;
+        if (c == ':') {
+            s << '_';
+            ++i;
+        } else {
+            s << *i;
+        }
+    }
+    s << "_" << funcName;
+    return s.str();
+}
+
+
+void PyType::writeThisDecl()
+{
+    cout << "    " << ct->toCString() << " *_this = ((struct __babel_obj_" << ct->name << " *)self)->_this;" << endl;
+}
+
+
+/**********************************************************************
+ * PyExtModule                                                        *
+ **********************************************************************/
+
+
+class PyExtModule {
+    
+    std::string name; // name of module
+    std::vector<PyType *> types; // global methods
+    std::vector<PyMethod *> methods; // global methods
+    std::set<std::string> interns; // interned strings
+
+    std::string source; // C/C++ source filename (for #include)
+
+public:
+    PyExtModule(std::string n, std::string s);
+    void addMethod(PyMethod *method) { methods.push_back(method); }
+    void addType(PyType *type) { types.push_back(type); }
+    void generateSource();
+
+private:
+    void collectInterns();
+    
+    void generatePreamble();
+    void generateTypeDecls();
+    void generateInternDecls();
+    void generateMethods();
+    void generateInternTable();
+    void generateTypeObjects();
+    void generateMethodTable();
+    void generateModInitFunc();
+    void generatePostamble();
+
+};
+
+
+//----------------------------------------------------------------------
+
+
+PyExtModule::PyExtModule(std::string n, std::string s) :
+    name(n),
+    source(s)
+{
+}
+
+
+void PyExtModule::collectInterns()
+{
+    // Intern the names of all methods.
+
+    for (std::vector<PyMethod *>::const_iterator m = methods.begin();
+         m != methods.end();
+         ++m) {
+        interns.insert((*m)->name());
+    }
+    for (std::vector<PyType *>::const_iterator t = types.begin();
+         t != types.end();
+         ++t) {
+        for (std::vector<PyMethod *>::const_iterator m = (*t)->methods.begin();
+             m != (*t)->methods.end();
+             ++m) {
+            interns.insert((*m)->name());
+        }
+    }
+}
+
+
+void PyExtModule::generateSource()
+{
+    this->collectInterns();
+    
+    cout << "/* Generated by Babel */" << endl
+         << endl;
+    
+    cout << "#include \"" << source << "\"" << endl
+         << endl;
+    
+    cout << "#include \"Python.h\"" << endl
+         << endl;
+
+    this->generatePreamble();
+
+    this->generateTypeDecls();
+    this->generateInternDecls();
+    this->generateMethods();
+    this->generateInternTable();
+    this->generateTypeObjects();
+    this->generateMethodTable();
+    
+    this->generateModInitFunc();
+
+    this->generatePostamble();
+    
+}
+
+
+void PyExtModule::generatePreamble()
+{
+    cout << "typedef struct {PyObject **p; char *s;} __Babel_InternTabEntry;" << endl
+         << endl
+         << "static PyObject *__babel_m;" << endl
+         << endl
+         << "static int __Babel_InternStrings(__Babel_InternTabEntry *t);" << endl
+         << endl;
+}
+
+
+void PyExtModule::generateTypeDecls()
+{
+    for (std::vector<PyType *>::const_iterator t = types.begin();
+         t != types.end();
+         ++t) {
+        (*t)->generateDecl();
+    }
+}
+
+
+void PyExtModule::generateInternDecls()
+{
+    for (std::set<std::string>::const_iterator i = interns.begin();
+         i != interns.end();
+         ++i) {
+        cout << "static PyObject *__babel_n_" << *i << ";" << endl;
+    }
+    cout << endl;
+}
+
+
+void PyExtModule::generateMethods()
+{
+    for (std::vector<PyMethod *>::const_iterator m = methods.begin();
+         m != methods.end();
+         ++m) {
+        (*m)->generateSource();
+        cout << endl;
+    }
+    for (std::vector<PyType *>::const_iterator t = types.begin();
+         t != types.end();
+         ++t) {
+        for (std::vector<PyMethod *>::const_iterator m = (*t)->methods.begin();
+             m != (*t)->methods.end();
+             ++m) {
+            (*m)->generateSource();
+            cout << endl;
+        }
+    }
+}
+
+
+void PyExtModule::generateInternTable()
+{
+    cout << "static __Babel_InternTabEntry __babel_intern_tab[] = {" << endl;
+    for (std::set<std::string>::const_iterator i = interns.begin();
+         i != interns.end();
+         ++i) {
+        cout << "    {&__babel_n_" << *i << ", \"" << *i << "\"}," << endl;
+    }
+    cout << "    {0, 0}" << endl
+         << "};" << endl
+         << endl;
+}
+
+
+void PyExtModule::generateTypeObjects()
+{
+    for (std::vector<PyType *>::const_iterator t = types.begin();
+         t != types.end();
+         ++t) {
+        (*t)->generateSource(name);
+    }
+}
+
+
+void PyExtModule::generateMethodTable()
+{
+    cout << "static struct PyMethodDef __babel_methods[] = {" << endl;
+    
+    for (std::vector<PyMethod *>::const_iterator m = methods.begin();
+         m != methods.end();
+         ++m) {
+        cout << "    {\"" << (*m)->name() << "\", (PyCFunction)__babel_m_" << (*m)->name()
+             << ", METH_VARARGS|METH_KEYWORDS, 0}," << endl;
+    }
+    
+    cout << "    {0, 0, 0, 0}" << endl
+         << "};" << endl
+         << endl;
+}
+
+
+void PyExtModule::generateModInitFunc()
+{
+    cout << "PyMODINIT_FUNC init" << name <<"(void) {" << endl
+         << "    __babel_m = Py_InitModule4(\"" << name << "\", __babel_methods, 0, 0, PYTHON_API_VERSION);" << endl
+         << "    if (!__babel_m) return;" << endl
+         << "    if (__Babel_InternStrings(__babel_intern_tab) < 0) return;" << endl;
+
+    for (std::vector<PyType *>::const_iterator t = types.begin();
+         t != types.end();
+         ++t) {
+        (*t)->generateInitCode();
+    }
+    
+    cout << "    return;" << endl
+         << "}" << endl
+         << endl;
+}
+
+
+void PyExtModule::generatePostamble()
+{
+    cout << "static int __Babel_InternStrings(__Babel_InternTabEntry *t) {" << endl
+         << "    while (t->p) {" << endl
+         << "        *t->p = PyString_InternFromString(t->s);" << endl
+         << "        if (!*t->p)" << endl
+         << "            return -1;" << endl
+         << "        ++t;" << endl
+         << "    }" << endl
+         << "    return 0;" << endl
+         << "}" << endl
+         << endl;
+}
+
+
+/**********************************************************************
+ * PyExtModuleGenerator                                               *
+ **********************************************************************/
+
+
+class PyExtModuleGenerator : public ASTVisitor {
+    PyExtModule *module;
+    Env &env;
+    
+    PyType *currentType;
+    
+    // these ensure the uniqueness of PyMethods
+    std::set<Variable *> vars;
+    std::set<OverloadSet *> overloads;
+
+public:
+    PyExtModuleGenerator(PyExtModule *m, Env &env);
+    virtual ~PyExtModuleGenerator();
+
+    virtual bool visitDeclarator(Declarator *obj);
+    virtual bool visitFunction(Function *f);
+    
+    virtual bool visitTypeSpecifier(TypeSpecifier *ts);
+    virtual bool visitMember(Member *obj);
+    virtual void postvisitTypeSpecifier(TypeSpecifier *ts);
+
+private:
+    void visitFunctionVariable(Variable *var);
+
+    bool isDiscardedFunction(Variable *var);
+    bool uniqify(Variable *var);
+};
+
+
+//----------------------------------------------------------------------
+
+
+PyExtModuleGenerator::PyExtModuleGenerator(PyExtModule *m, Env &e) :
+    module(m),
+    env(e),
+    currentType(0)
+{
+}
+
+
+PyExtModuleGenerator::~PyExtModuleGenerator()
+{
+}
+
+
+bool PyExtModuleGenerator::visitDeclarator(Declarator *obj)
+{
+    Variable *var = obj->var;
+    if (var->type->isFunctionType()) {
+        if (!this->isDiscardedFunction(var)) {
+            this->visitFunctionVariable(var);
+       }
+    }
+    return true;
+}
+
+
+bool PyExtModuleGenerator::visitFunction(Function *f)
+{
+    // This is called only for function bodies.  But 'visitDeclarator'
+    // is called for prototypes as well; so all our processing is done
+    // there.
+    if (false) {
+        Variable *var = f->nameAndParams->var;
+        if (!this->isDiscardedFunction(var)) {
+            this->visitFunctionVariable(var);
+        }
+    }
+    return true;
+}
+
+
+void PyExtModuleGenerator::visitFunctionVariable(Variable *var)
+{
+    if (this->uniqify(var)) {
+        PyMethod *method = new PyMethod(var, currentType);
+        if (currentType) {
+            xassert(var->isMember());
+            currentType->addMethod(method);
+        } else {
+            module->addMethod(method);
+        }
+    }
+    if (false) {
+        cout << "    " << var->toCString() << endl;
+        cout << "    " << var->toQualifiedString() << endl;
+    }
+    return;
+}
+
+
+bool PyExtModuleGenerator::visitTypeSpecifier(TypeSpecifier *ts)
+{
+    if (ts->kind() == TypeSpecifier::TS_CLASSSPEC) {
+        TS_classSpec *spec = ts->asTS_classSpec();
+        CompoundType *ct = spec->ctype;
+        if (ct->name) { // skip anonymous classes
+            currentType = new PyType(ct, env);
+            module->addType(currentType);
+        }
+    }
+    return true;
+}
+
+
+bool PyExtModuleGenerator::visitMember(Member *obj)
+{
+    if (obj->isMR_func()) {
+        // This fires for function bodies inside class declarations.
+        if (false) {
+            Function *f = obj->asMR_func()->f;
+            Variable *var = f->nameAndParams->var;
+            cout << "member function " << *(f->nameAndParams->getDeclaratorId()) << " (" << var->name << ")" << endl;
+            cout << "    " << var->toCString() << endl;
+            cout << "    " << var->toQualifiedString() << endl;
+        }
+    } else if (obj->isMR_access()) {
+    } else if (obj->isMR_decl()) {
+        if (false) {
+            cout << "member decl" << endl;
+            Declaration *d = obj->asMR_decl()->d;
+            d->debugPrint(cout, 0);
+        }
+    }
+    return true;
+}
+
+
+void PyExtModuleGenerator::postvisitTypeSpecifier(TypeSpecifier *ts)
+{
+    if (ts->kind() == TypeSpecifier::TS_CLASSSPEC) {
+        currentType = 0;
+    }
+}
+
+
 bool PyExtModuleGenerator::isDiscardedFunction(Variable *var)
 {
     FunctionType *t = var->type->asFunctionType();
@@ -717,45 +915,11 @@
 }
 
 
-std::string PyExtModuleGenerator::tpName(std::string funcName, CompoundType *ct)
-{
-    return this->mangledMemberFuncName(ct, funcName, "tp");
-}
+/**********************************************************************
+ * main                                                               *
+ **********************************************************************/
 
 
-std::string PyExtModuleGenerator::mangledMemberFuncName(Variable *var, std::string ns)
-{
-    return this->mangledMemberFuncName(var, var->name, ns);
-}
-
-
-std::string PyExtModuleGenerator::mangledMemberFuncName(Variable *var, std::string funcName, std::string ns)
-{
-    return this->mangledMemberFuncName(var->scope->curCompound, funcName, ns);
-}
-
-
-std::string PyExtModuleGenerator::mangledMemberFuncName(CompoundType *ct, std::string funcName, std::string ns)
-{
-    std::string className = ct->typedefVar->fullyQualifiedName0().c_str();
-    std::stringstream s;
-    s << "__babel_" << ns << "_" << className.length();
-    for (std::string::const_iterator i = className.begin(); i != className.end(); ++i) {
-        char c = *i;
-        if (c == ':') {
-            s << '_';
-            ++i;
-        } else {
-            s << *i;
-        }
-    }
-    s << "_" << funcName;
-    return s.str();
-}
-
-
-// ---------------------- main -------------------------
-
 void doit(int argc, char **argv)
 {
     xBase::logExceptions = false;
@@ -781,8 +945,7 @@
         SemanticValue treeTop;
         ParseTreeAndTokens tree(lang, treeTop, strTable, inputFname.c_str());
 
-        // grab the lexer so we can check it for errors (damn this
-        // 'tree' thing is stupid..)
+        // grab the lexer so we can check it for errors
         Lexer *lexer = dynamic_cast<Lexer*>(tree.lexer);
         xassert(lexer);
 
@@ -827,8 +990,10 @@
         unit->traverse(vis.loweredVisitor);
 
         // generate Python module
-        PyExtModuleGenerator visitor(argv[2], argv[1], env);
-        visitor.generate(unit);
+        PyExtModule module(argv[2], argv[1]);
+        PyExtModuleGenerator visitor(&module, env);
+        unit->traverse(visitor);
+        module.generateSource();
 
     }
 



More information about the cig-commits mailing list