Alien-SmokeQt
view release on metacpan or search on metacpan
generator/generators/smoke/writeClasses.cpp view on Meta::CPAN
includes.insert(klass->fileName());
writeClass(classOut, klass, str, includes);
}
// create the file
QFile file(Options::outputDir.filePath("x_" + QString::number(i + 1) + ".cpp"));
file.open(QFile::ReadWrite | QFile::Truncate);
QTextStream fileOut(&file);
// write out the header
fileOut << "//Auto-generated by " << QCoreApplication::arguments()[0] << ". DO NOT EDIT.\n";
// ... and the #includes
QList<QString> sortedIncludes = includes.toList();
qSort(sortedIncludes.begin(), sortedIncludes.end());
foreach (const QString& str, sortedIncludes) {
if (str.isEmpty())
continue;
fileOut << "#include <" << str << ">\n";
}
fileOut << "\n#include <smoke.h>\n#include <" << Options::module << "_smoke.h>\n";
fileOut << "\nclass __internal_SmokeClass {};\n";
fileOut << "\nnamespace __smoke" << Options::module << " {\n\n";
// now the class code
fileOut << classCode;
fileOut << "\n}\n";
file.close();
}
}
QString SmokeClassFiles::generateMethodBody(const QString& indent, const QString& className, const QString& smokeClassName, const Method& meth,
int index, bool dynamicDispatch, QSet<QString>& includes)
{
QString methodBody;
QTextStream out(&methodBody);
out << indent;
if (meth.isConstructor()) {
out << smokeClassName << "* xret = new " << smokeClassName << "(";
} else {
const Function* func = Util::globalFunctionMap[&meth];
if (func)
includes.insert(func->fileName());
if (meth.type()->getClass())
includes.insert(meth.type()->getClass()->fileName());
if (meth.type()->isFunctionPointer() || meth.type()->isArray())
out << meth.type()->toString("xret") << " = ";
else if (meth.type() != Type::Void)
out << meth.type()->toString() << " xret = ";
if (!(meth.flags() & Method::Static)) {
if (meth.isConst()) {
out << "((const " << smokeClassName << "*)this)->";
} else {
out << "this->";
}
}
if (!dynamicDispatch && !func) {
// dynamic dispatch not wanted, call with 'this->Foo::method()'
out << className << "::";
} else if (func) {
if (!func->nameSpace().isEmpty())
out << func->nameSpace() << "::";
}
out << meth.name() << "(";
}
for (int j = 0; j < meth.parameters().count(); j++) {
const Parameter& param = meth.parameters()[j];
if (param.type()->getClass())
includes.insert(param.type()->getClass()->fileName());
if (j > 0) out << ",";
QString field = Util::stackItemField(param.type());
QString typeName = param.type()->toString();
if (param.type()->isArray()) {
Type t = *param.type();
t.setPointerDepth(t.pointerDepth() + 1);
t.setIsRef(false);
typeName = t.toString();
out << '*';
} else if (field == "s_class" && (param.type()->pointerDepth() == 0 || param.type()->isRef()) && !param.type()->isFunctionPointer()) {
// references and classes are passed in s_class
typeName.append('*');
out << '*';
}
// casting to a reference doesn't make sense in this case
if (param.type()->isRef() && !param.type()->isFunctionPointer()) typeName.replace('&', "");
out << "(" << typeName << ")" << "x[" << j + 1 << "]." << field;
}
// if the method has any other default parameters, append them here as values
if (!meth.remainingDefaultValues().isEmpty()) {
const QStringList& defaultParams = meth.remainingDefaultValues();
if (meth.parameters().count() > 0)
out << "," ;
out << defaultParams.join(",");
}
out << ");\n";
if (meth.type() != Type::Void) {
out << indent << "x[0]." << Util::stackItemField(meth.type()) << " = " << Util::assignmentString(meth.type(), "xret") << ";\n";
} else {
out << indent << "(void)x; // noop (for compiler warning)\n";
}
return methodBody;
}
void SmokeClassFiles::generateMethod(QTextStream& out, const QString& className, const QString& smokeClassName,
const Method& meth, int index, QSet<QString>& includes)
{
out << " ";
if ((meth.flags() & Method::Static) || meth.isConstructor())
out << "static ";
out << QString("void x_%1(Smoke::Stack x) {\n").arg(index);
out << " // " << meth.toString() << "\n";
bool dynamicDispatch = ((meth.flags() & Method::PureVirtual) || (meth.flags() & Method::DynamicDispatch));
if (dynamicDispatch || !Util::virtualMethodsForClass(meth.getClass()).contains(&meth)) {
// This is either already flagged as dynamic dispatch or just a normal method. We can generate a normal method call for it.
out << generateMethodBody(" ", // indent
className, smokeClassName, meth, index, dynamicDispatch, includes);
} else {
// This is a virtual method. To know whether we should call with dynamic dispatch, we need a bit of RTTI magic.
includes.insert("typeinfo");
out << " if (dynamic_cast<__internal_SmokeClass*>(static_cast<" << className << "*>(this))) {\n"; //
out << generateMethodBody(" ", // indent
className, smokeClassName, meth, index, false, includes);
out << " } else {\n";
out << generateMethodBody(" ", // indent
className, smokeClassName, meth, index, true, includes);
out << " }\n";
}
out << " }\n";
// If the constructor was generated from another one with default parameteres, we don't need to explicitly create
// it here again. The x_* call will append the default parameters at the end and thus choose the right constructor.
if (meth.isConstructor() && meth.remainingDefaultValues().isEmpty()) {
out << " explicit " << smokeClassName << '(';
QStringList x_list;
for (int i = 0; i < meth.parameters().count(); i++) {
if (i > 0) out << ", ";
out << meth.parameters()[i].type()->toString() << " x" << QString::number(i + 1);
x_list << "x" + QString::number(i + 1);
}
out << ") : " << meth.getClass()->name() << '(' << x_list.join(", ") << ") {}\n";
}
}
void SmokeClassFiles::generateGetAccessor(QTextStream& out, const QString& className, const Field& field,
const Type* type, int index)
{
out << " ";
QString fieldName;
if (field.flags() & Field::Static) {
out << "static ";
} else {
fieldName = "this->";
}
fieldName += className + "::" + field.name();
out << "void x_" << index << "(Smoke::Stack x) {\n"
<< " // " << field.toString() << "\n"
<< " x[0]." << Util::stackItemField(type) << " = "
<< Util::assignmentString(type, fieldName) << ";\n"
<< " }\n";
}
void SmokeClassFiles::generateSetAccessor(QTextStream& out, const QString& className, const Field& field,
const Type* type, int index)
{
out << " ";
QString fieldName;
if (field.flags() & Field::Static) {
out << "static ";
} else {
fieldName = "this->";
}
fieldName += className + "::" + field.name();
out << "void x_" << index << "(Smoke::Stack x) {\n"
<< " // " << field.toString() << "=\n"
<< " " << fieldName << " = ";
QString unionField = Util::stackItemField(type);
QString cast = type->toString();
cast.replace("&", "");
if (unionField == "s_class" && type->pointerDepth() == 0) {
out << '*';
cast += '*';
}
out << '(' << cast << ')' << "x[1]." << unionField << ";\n";
out << " }\n";
}
void SmokeClassFiles::generateEnumMemberCall(QTextStream& out, const QString& className, const QString& member, int index)
{
out << " static void x_" << index << "(Smoke::Stack x) {\n"
<< " x[0].s_enum = (long)";
if (!className.isEmpty())
out << className << "::";
out << member << ";\n"
<< " }\n";
}
void SmokeClassFiles::generateVirtualMethod(QTextStream& out, const Method& meth, QSet<QString>& includes)
{
QString x_params, x_list;
QString type = meth.type()->toString();
if (meth.type()->getClass())
includes.insert(meth.type()->getClass()->fileName());
out << " virtual " << type << " " << meth.name() << "(";
for (int i = 0; i < meth.parameters().count(); i++) {
if (i > 0) { out << ", "; x_list.append(", "); }
const Parameter& param = meth.parameters()[i];
if (param.type()->getClass())
includes.insert(param.type()->getClass()->fileName());
out << param.type()->toString() << " x" << i + 1;
x_params += QString(" x[%1].%2 = %3;\n")
.arg(QString::number(i + 1)).arg(Util::stackItemField(param.type()))
.arg(Util::assignmentString(param.type(), "x" + QString::number(i + 1)));
x_list += "x" + QString::number(i + 1);
}
out << ") ";
if (meth.isConst())
out << "const ";
if (meth.hasExceptionSpec()) {
out << "throw(";
for (int i = 0; i < meth.exceptionTypes().count(); i++) {
if (i > 0) out << ", ";
out << meth.exceptionTypes()[i].toString();
}
out << ") ";
}
out << "{\n";
out << QString(" Smoke::StackItem x[%1];\n").arg(meth.parameters().count() + 1);
out << x_params;
if (meth.flags() & Method::PureVirtual) {
out << QString(" this->_binding->callMethod(%1, (void*)this, x, true /*pure virtual*/);\n").arg(m_smokeData->methodIdx[&meth]);
if (meth.type() != Type::Void) {
QString field = Util::stackItemField(meth.type());
if (meth.type()->pointerDepth() == 0 && field == "s_class") {
QString tmpType = type;
if (meth.type()->isRef()) tmpType.replace('&', "");
tmpType.append('*');
out << " " << tmpType << " xptr = (" << tmpType << ")x[0].s_class;\n";
out << " " << type << " xret(*xptr);\n";
out << " delete xptr;\n";
out << " return xret;\n";
} else {
out << QString(" return (%1)x[0].%2;\n").arg(type, Util::stackItemField(meth.type()));
}
}
} else {
out << QString(" if (this->_binding->callMethod(%1, (void*)this, x)) ").arg(m_smokeData->methodIdx[&meth]);
if (meth.type() == Type::Void) {
out << "return;\n";
} else {
QString field = Util::stackItemField(meth.type());
if (meth.type()->pointerDepth() == 0 && field == "s_class") {
QString tmpType = type;
if (meth.type()->isRef()) tmpType.replace('&', "");
tmpType.append('*');
out << "{\n";
out << " " << tmpType << " xptr = (" << tmpType << ")x[0].s_class;\n";
out << " " << type << " xret(*xptr);\n";
out << " delete xptr;\n";
out << " return xret;\n";
out << " }\n";
} else {
out << QString("return (%1)x[0].%2;\n").arg(type, Util::stackItemField(meth.type()));
}
}
out << " ";
if (meth.type() != Type::Void)
out << "return ";
out << QString("this->%1::%2(%3);\n").arg(meth.getClass()->toString()).arg(meth.name()).arg(x_list);
}
out << " }\n";
}
void SmokeClassFiles::writeClass(QTextStream& out, const Class* klass, const QString& className, QSet<QString>& includes)
{
const QString underscoreName = QString(className).replace("::", "__");
const QString smokeClassName = "x_" + underscoreName;
QString switchCode;
QTextStream switchOut(&switchCode);
out << QString("class %1").arg(smokeClassName);
if (!klass->isNameSpace()) {
out << QString(" : public %1").arg(className);
if (Util::hasClassVirtualDestructor(klass) && Util::hasClassPublicDestructor(klass)) {
out << ", public __internal_SmokeClass";
}
}
out << " {\n";
if (Util::canClassBeInstanciated(klass)) {
out << " SmokeBinding* _binding;\n";
out << "public:\n";
out << " void x_0(Smoke::Stack x) {\n";
out << " // set the smoke binding\n";
out << " _binding = (SmokeBinding*)x[1].s_class;\n";
out << " }\n";
switchOut << " case 0: xself->x_0(args);\tbreak;\n";
} else {
out << "public:\n";
}
int xcall_index = 1;
const Method *destructor = 0;
foreach (const Method& meth, klass->methods()) {
if (meth.access() == Access_private)
continue;
if (meth.isDestructor()) {
destructor = &meth;
continue;
}
switchOut << " case " << xcall_index << ": "
<< (((meth.flags() & Method::Static) || meth.isConstructor()) ? smokeClassName + "::" : "xself->")
<< "x_" << xcall_index << "(args);\tbreak;\n";
if (Util::fieldAccessors.contains(&meth)) {
// accessor method?
const Field* field = Util::fieldAccessors[&meth];
if (meth.name().startsWith("set")) {
generateSetAccessor(out, className, *field, meth.parameters()[0].type(), xcall_index);
} else {
generateGetAccessor(out, className, *field, meth.type(), xcall_index);
}
} else {
generateMethod(out, className, smokeClassName, meth, xcall_index, includes);
}
xcall_index++;
}
QString enumCode;
QTextStream enumOut(&enumCode);
const Enum* e = 0;
bool enumFound = false;
foreach (const BasicTypeDeclaration* decl, klass->children()) {
if (!(e = dynamic_cast<const Enum*>(decl)))
continue;
if (e->access() == Access_private)
continue;
foreach (const EnumMember& member, e->members()) {
switchOut << " case " << xcall_index << ": " << smokeClassName << "::x_" << xcall_index << "(args);\tbreak;\n";
if (e->parent())
generateEnumMemberCall(out, className, member.name(), xcall_index++);
else
generateEnumMemberCall(out, e->nameSpace(), member.name(), xcall_index++);
}
// only generate the xenum_call if the enum has a valid name
if (e->name().isEmpty())
continue;
enumFound = true;
// xenum_operation method code
QString enumString = e->toString();
enumOut << " case " << m_smokeData->typeIndex[&types[enumString]] << ": //" << enumString << '\n';
enumOut << " switch(xop) {\n";
enumOut << " case Smoke::EnumNew:\n";
enumOut << " xdata = (void*)new " << enumString << ";\n";
enumOut << " break;\n";
enumOut << " case Smoke::EnumDelete:\n";
enumOut << " delete (" << enumString << "*)xdata;\n";
enumOut << " break;\n";
enumOut << " case Smoke::EnumFromLong:\n";
enumOut << " *(" << enumString << "*)xdata = (" << enumString << ")xvalue;\n";
enumOut << " break;\n";
enumOut << " case Smoke::EnumToLong:\n";
enumOut << " xvalue = (long)*(" << enumString << "*)xdata;\n";
enumOut << " break;\n";
enumOut << " }\n";
enumOut << " break;\n";
}
foreach (const Method* meth, Util::virtualMethodsForClass(klass)) {
( run in 0.482 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )