Mercurial > projects > qtd
diff generator/containergenerator.cpp @ 1:e78566595089
initial import
author | mandel |
---|---|
date | Mon, 11 May 2009 16:01:50 +0000 |
parents | |
children | 5917a613d118 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/generator/containergenerator.cpp Mon May 11 16:01:50 2009 +0000 @@ -0,0 +1,396 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2008 Nokia. All rights reserved. +** +** This file is part of Qt Jambi. +** +** * Commercial Usage +* Licensees holding valid Qt Commercial licenses may use this file in +* accordance with the Qt Commercial License Agreement provided with the +* Software or, alternatively, in accordance with the terms contained in +* a written agreement between you and Nokia. +* +* +* GNU General Public License Usage +* Alternatively, this file may be used under the terms of the GNU +* General Public License versions 2.0 or 3.0 as published by the Free +* Software Foundation and appearing in the file LICENSE.GPL included in +* the packaging of this file. Please review the following information +* to ensure GNU General Public Licensing requirements will be met: +* http://www.fsf.org/licensing/licenses/info/GPLv2.html and +* http://www.gnu.org/copyleft/gpl.html. In addition, as a special +* exception, Nokia gives you certain additional rights. These rights +* are described in the Nokia Qt GPL Exception version 1.2, included in +* the file GPL_EXCEPTION.txt in this package. +* +* Qt for Windows(R) Licensees +* As a special exception, Nokia, as the sole copyright holder for Qt +* Designer, grants users of the Qt/Eclipse Integration plug-in the +* right for the Qt/Eclipse Integration to link to functionality +* provided by Qt Designer and its related libraries. +* +* +* If you are unsure which license is appropriate for your use, please +* contact the sales department at qt-sales@nokia.com. + +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#include "containergenerator.h" +#include "cppimplgenerator.h" +#include "fileout.h" + +static Indentor INDENT; + +ContainerGenerator::ContainerGenerator(): + DGenerator() + +{ + setFilenameStub("ArrayOps"); + excludedTypes.clear(); + + // qtd2 + excludedTypes << "QFuture"; +} + +QString ContainerGenerator::subDirectoryForPackage(const QString &package, OutputDirectoryType type) const +{ + switch (type) { + case CppDirectory: + return "cpp/" + QString(package).replace(".", "_") + "/"; + case DDirectory: + return QString(package).replace(".", "/"); + case HDirectory: + return "include/"; + default: + return QString(); // kill nonsense warnings + } +} + +void ContainerGenerator::write(QTextStream &, const AbstractMetaClass *) +{ + // not used +} + +void ContainerGenerator::addTypeEntry(const TypeEntry* te) +{ + if (!excludedTypes.contains(te->name())) + containerTypes << te; +} + +void ContainerGenerator::processType(AbstractMetaType *d_type) +{ + if (d_type->isContainer()) { + QList<AbstractMetaType *> args = d_type->instantiations(); + + if (args.size() == 1) // QVector or QList + if (args.at(0)->typeEntry()->isComplex() + && !args.at(0)->isContainer() + && !args.at(0)->isTargetLangString()) + addTypeEntry(args.at(0)->typeEntry()); // qMakePair(args.at(0)->typeEntry(), m_class); + } +} + +void ContainerGenerator::processFunction(const AbstractMetaFunction *d_function) +{ + if (notWrappedYet(d_function)) // qtd2 + return; + + if (d_function->type()) { + AbstractMetaType *d_type = d_function->type(); + if (d_type->isContainer()) { + processType(d_type); + } + } + + AbstractMetaArgumentList arguments = d_function->arguments(); + for (int i=0; i<arguments.count(); ++i) { + const AbstractMetaArgument *arg = arguments.at(i); + processType(arg->type()); + } +} + +void ContainerGenerator::buildTypeList() +{ + foreach (AbstractMetaClass *d_class, classes()) { +m_class = d_class; + AbstractMetaFunctionList d_funcs = d_class->functionsInTargetLang(); + for (int i=0; i<d_funcs.size(); ++i) { + AbstractMetaFunction *function = d_funcs.at(i); + + // If a method in an interface class is modified to be private, this should + // not be present in the interface at all, only in the implementation. + if (d_class->isInterface()) { + uint includedAttributes = 0; + uint excludedAttributes = 0; + retrieveModifications(function, d_class, &excludedAttributes, &includedAttributes); + if (includedAttributes & AbstractMetaAttributes::Private) + continue; + } + + processFunction(function); + } + AbstractMetaFieldList fields = d_class->fields(); + foreach (const AbstractMetaField *field, fields) { + if (field->wasPublic() || (field->wasProtected() && !d_class->isFinal())) { + processFunction(field->setter()); + processFunction(field->getter()); + } + } + + } +} + +void ContainerGenerator::generate() +{ + buildTypeList(); + + writeFile(cppFilename(), CppDirectory, &ContainerGenerator::writeCppContent); // cpp file + writeFile("ArrayOps_%1.h", HDirectory, &ContainerGenerator::writeHeaderContent); // header file + writeFile(dFilename(), DDirectory, &ContainerGenerator::writeDContent); // d file +} + +void ContainerGenerator::writeFile(const QString& fileName, OutputDirectoryType dirType, WriteOut writeOut) +{ + AbstractMetaClassList classList = classes(); + QHash<QString, FileOut *> fileHash; + + // Seems continue is not supported by our foreach loop, so + foreach (AbstractMetaClass *cls, classList) { + + FileOut *f = fileHash.value(cls->package(), 0); + if (f == 0) { + f = new FileOut(outputDirectory() + "/" + subDirectoryForPackage(cls->package(), dirType) + "/" + + fileName.arg(cls->package().replace(".", "_"))); + writeNotice(f->stream); + + (this->*writeOut)(f->stream, cls); + + fileHash.insert(cls->package(), f); + +// QString pro_file_name = cls->package().replace(".", "_") + "/" + cls->package().replace(".", "_") + ".pri"; +// priGenerator->addSource(pro_file_name, cppFilename()); + } + } + + foreach (QString package, fileHash.keys()) { + FileOut *f = fileHash.value(package, 0); + if (f != 0) { + if( f->done() ) + ++m_num_generated_written; + ++m_num_generated; + + delete f; + } + } +} + +void ContainerGenerator::writeCppContent(QTextStream &s, AbstractMetaClass *cls) +{ + QString package = cls->package().replace(".", "_"); + + s << "// stuff for passing D function pointers" << endl << endl + << "#ifdef CPP_SHARED" << endl << endl + << "#include \"ArrayOps_" << package << ".h\"" << endl << endl; + + foreach (const TypeEntry *te, containerTypes) { + if (te->javaPackage() == cls->package()) { + const ComplexTypeEntry *centry = static_cast<const ComplexTypeEntry *>(te); + QString cls_name = centry->name(); + + setFuncNames(cls_name); + s << "QTD_EXPORT_VAR(" << all_name << ")" << endl + << "QTD_EXPORT_VAR(" << ass_name << ")" << endl + << "QTD_EXPORT_VAR(" << get_name << ")" << endl << endl; + } + } + + s << endl + << "extern \"C\" DLL_PUBLIC void qtd_" << cls->package().replace(".", "_") << "_ArrayOps_initCallBacks(pfunc_abstr *callbacks)" << endl + << "{" << endl; + + int num_funcs = 0; + foreach (const TypeEntry *te, containerTypes) { + if (te->javaPackage() == cls->package()) { + const ComplexTypeEntry *centry = static_cast<const ComplexTypeEntry *>(te); + QString cls_name = centry->name(); + + setFuncNames(cls_name); + s << " QTD_EXPORT_VAR_SET(" << all_name << ", callbacks[" << num_funcs + 0 << "]);" << endl + << " QTD_EXPORT_VAR_SET(" << ass_name << ", callbacks[" << num_funcs + 1 << "]);" << endl + << " QTD_EXPORT_VAR_SET(" << get_name << ", callbacks[" << num_funcs + 2 << "]);" << endl << endl; + + num_funcs += NUM_ARRAY_FUNCS; + } + } + s << "}" << endl + << "#endif" << endl; +} + +void ContainerGenerator::writeHeaderContent(QTextStream &s, AbstractMetaClass *cls) +{ + s << "#include <cstring>" << endl + << "#include \"qtd_core.h\"" << endl << endl; + + foreach (const TypeEntry *te, containerTypes) { + if (te->javaPackage() == cls->package()) { + const ComplexTypeEntry *typeEntry = static_cast<const ComplexTypeEntry *>(te); + s << "// " << typeEntry->name() << endl; // " in " << it.second->name() << endl; + + Indentation indent(INDENT); + writeHeaderArrayFunctions(s, typeEntry); + } + } +} + +void ContainerGenerator::setFuncNames(const QString& cls_name) +{ + all_name = QString("qtd_allocate_%1_array").arg(cls_name); + ass_name = QString("qtd_assign_%1_array_element").arg(cls_name); + get_name = QString("qtd_get_%1_from_array").arg(cls_name); +} + +void ContainerGenerator::writeHeaderArrayFunctions(QTextStream &s, const ComplexTypeEntry *centry) +{ + QString cls_name = centry->name(); + bool d_export = true; + QString d_type, cpp_type, cpp_type_assign; + + if (centry->name() == "QModelIndex") { + cpp_type = "QModelIndexAccessor*"; + } else if (centry->isStructInD()) { + cpp_type = centry->qualifiedCppName() + "*"; + } else if (centry->isObject() || centry->isQObject() || centry->isValue() || centry->isInterface() || centry->isVariant()) { + cpp_type = "void*"; + } + + setFuncNames(cls_name); + + s << "QTD_EXPORT(void, " << all_name << ", (void* arr, size_t len))" << endl + << "QTD_EXPORT(void, " << ass_name << ", (void* arr, size_t pos, " << cpp_type << " elem))" << endl + << "QTD_EXPORT(void, " << get_name << ", (void* arr, size_t pos, " << cpp_type << " elem))" << endl; + + s << "#ifdef CPP_SHARED" << endl + << "#define " << all_name << " qtd_get_" << all_name << "()" << endl + << "#define " << ass_name << " qtd_get_" << ass_name << "()" << endl + << "#define " << get_name << " qtd_get_" << get_name << "()" << endl + << "#endif" << endl; + + s << endl; +} + +void ContainerGenerator::writeDContent(QTextStream &s, AbstractMetaClass *cls) +{ + s << "module " << cls->package() << ".ArrayOps;" << endl << endl; + + int num_funcs = 0; + foreach (const TypeEntry *te, containerTypes) { + if (te->javaPackage() == cls->package()) { + const ComplexTypeEntry *typeEntry = static_cast<const ComplexTypeEntry *>(te); + s << "// " << typeEntry->name() << endl; + writeImportString(s, typeEntry); + s << endl; + + Indentation indent(INDENT); + + writeArrayFunctions(s, typeEntry); + s << endl; + num_funcs += NUM_ARRAY_FUNCS; + } + } + if (num_funcs == 0) + return; + + s << "version (Windows) {" << endl + << " private extern (C) void qtd_" << cls->package().replace(".", "_") << "_ArrayOps_initCallBacks(void* callbacks);" << endl << endl + << " static this() {" << endl + << " void*[" << num_funcs << "] callbacks; " << endl << endl; + + num_funcs = 0; + foreach (const TypeEntry *te, containerTypes) { + if (te->javaPackage() == cls->package()) { + const ComplexTypeEntry *centry = static_cast<const ComplexTypeEntry *>(te); + + QString cls_name = centry->name(); + setFuncNames(cls_name); + + s << " callbacks[" << num_funcs + 0 << "] = &" << all_name << ";" << endl + << " callbacks[" << num_funcs + 1 << "] = &" << ass_name << ";" << endl + << " callbacks[" << num_funcs + 2 << "] = &" << get_name << ";" << endl; + + s << endl; + num_funcs += NUM_ARRAY_FUNCS; + } + } + s << " qtd_" << cls->package().replace(".", "_") << "_ArrayOps_initCallBacks(callbacks.ptr);" << endl + << " }" << endl + << "}" << endl; +} + +void ContainerGenerator::writeNotice(QTextStream &s) +{ + s << "/****************************************************************************" << endl + << "**" << endl + << "** This is a generated file, please don't touch." << endl + << "**" << endl + << "****************************************************************************/" << endl << endl; +} + +void ContainerGenerator::writeArrayFunctions(QTextStream &s, const ComplexTypeEntry *centry) +{ + QString cls_name = centry->name(); + QString type_name = cls_name; + + bool d_export = true; + QString d_type, cpp_type, cpp_assign_type, convert, nativeId; + + convert = "qtd_" + cls_name + "_cpp_to_d(elem)"; + nativeId = ""; + + if (centry->name() == "QModelIndex") { + cpp_type = "QModelIndexAccessor*"; + cpp_assign_type = cpp_type; + d_type = cpp_type; + convert = "*elem"; + } else if (centry->isStructInD()) { + cpp_type = centry->qualifiedCppName() + "*"; + cpp_assign_type = cpp_type; + d_type = cpp_type; + convert = "*elem"; + } else if (centry->isObject() || centry->isQObject() || centry->isValue() || centry->isInterface() || centry->isVariant()) { + cpp_type = "void*"; + cpp_assign_type = cpp_type + "*"; + d_type = cls_name; + nativeId = ".nativeId"; + } + + if (centry->designatedInterface()) { + type_name = centry->designatedInterface()->name(); + nativeId = ".__ptr_" + type_name; + } + + s << "private extern(C) void qtd_allocate_" << cls_name << "_array(" << type_name << "[]* arr, size_t len)" << endl + << "{" << endl + << INDENT << "*arr = new " << type_name << "[len];" << endl + << "}" << endl << endl; + + s << "private extern(C) void qtd_assign_" << cls_name << "_array_element(" << type_name << "[]* arr, size_t pos, " << cpp_type << " elem)" << endl + << "{" << endl + << INDENT << "(*arr)[pos] = " << convert << ";" << endl + << "}" << endl << endl + + << "private extern(C) void qtd_get_" << cls_name << "_from_array(" << type_name << "* arr, size_t pos, " << cpp_assign_type << " elem)" << endl + << "{" << endl + << INDENT << "*elem = arr[pos]" << nativeId << ";" << endl + << "}" << endl << endl + + << "package " << d_type << " qtd_" << cls_name << "_cpp_to_d(" << cpp_type << " __qt_return_value)" << endl + << "{" << endl; + + marshallFromCppToD(s, centry); + + s << "}" << endl; +}