[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