From 7b53f64eae84070b705854448949eeded1ec341d 2010-02-21 14:44:57 From: florianlink Date: 2010-02-21 14:44:57 Subject: [PATCH] added builtin support for variants etc., this will replace the direct includes in PythonQt git-svn-id: svn://svn.code.sf.net/p/pythonqt/code/trunk@129 ea8d5007-eb21-0410-b261-ccb3ea6e24a9 --- diff --git a/generator/classgenerator.cpp b/generator/classgenerator.cpp deleted file mode 100644 index b0032b0..0000000 --- a/generator/classgenerator.cpp +++ /dev/null @@ -1,1842 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Script Generator project on Qt Labs. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "classgenerator.h" -#include "fileout.h" - -#include -#include - -#include - -#define GENERATOR_NO_PROTECTED_FUNCTIONS - -ClassGenerator::ClassGenerator(PriGenerator *pri, SetupGenerator *setup) : - priGenerator(pri), - setupGenerator(setup) -{} - -QString ClassGenerator::fileNameForClass(const AbstractMetaClass *meta_class) const -{ - return QString("qtscript_%1.cpp").arg(meta_class->name()); -} - -bool ClassGenerator::shouldGenerate(const AbstractMetaClass *meta_class) const -{ - return false; // DISABLED! - uint cg = meta_class->typeEntry()->codeGeneration(); - return (cg & TypeEntry::GenerateCode) != 0; -} - -static QString normalizedType(const AbstractMetaType *type) -{ - QString str = QString::fromLatin1(QMetaObject::normalizedType(type->cppSignature().toLatin1())); - if (str.endsWith(QLatin1Char('&'))) - str.chop(1); - else if (str.startsWith("const ")) { - if (str.endsWith('*') || type->hasInstantiations() || type->typeEntry()->isValue()) - str.remove(0, 6); - } - if (str == QLatin1String("QBool")) // ### hack - str = QLatin1String("bool"); - return str; -} - -/*! - Returns true if the class \a meta_class inherits from QObject, - otherwise returns false. -*/ -static bool isQObjectBased(const AbstractMetaClass *meta_class) -{ - while (meta_class) { - if (meta_class->name() == QLatin1String("QObject")) - return true; - meta_class = meta_class->baseClass(); - } - return false; -} - -/*! - Returns true if any of the given \a enums has been declared with - Q_ENUMS. -*/ -static bool hasQEnums(const AbstractMetaEnumList &enums) -{ - for (int i = 0; i < enums.size(); ++i) { - if (enums.at(i)->hasQEnumsDeclaration()) - return true; - } - return false; -} - -/*! - Returns true if any of the given \a enums has a QFlags class - associated with it. -*/ -static bool hasFlags(const AbstractMetaEnumList &enums) -{ - for (int i = 0; i < enums.size(); ++i) { - FlagsTypeEntry *flags = enums.at(i)->typeEntry()->flags(); - if (flags) - return true; - } - return false; -} - -static bool isSequenceType(const AbstractMetaType *tp) -{ - return tp->isContainer() && (tp->instantiations().size() == 1); -} - -static AbstractMetaFunction *findDefaultConstructor(const AbstractMetaFunctionList &ctors) -{ - for (int i = 0; i < ctors.size(); ++i) { - if (ctors.at(i)->actualMinimumArgumentCount() == 0) - return ctors.at(i); - } - return 0; -} - -static AbstractMetaFunctionList findConstructors(const AbstractMetaClass *meta_class) -{ - return meta_class->queryFunctions(AbstractMetaClass::Constructors - | AbstractMetaClass::WasPublic - | AbstractMetaClass::NotRemovedFromTargetLang); -} - -/*! - Returns true if \a meta_class has a default constructor, false - otherwise. -*/ -bool hasDefaultConstructor(const AbstractMetaClass *meta_class) -{ - return findDefaultConstructor(findConstructors(meta_class)) != 0; -} - -/*! - Given the list of \a functions, creates a mapping from # of - arguments to list of functions. -*/ -static QMap createArgcToFunctionsMap( - const AbstractMetaFunctionList &functions) -{ - QMap result; - for (int i = 0; i < functions.size(); ++i) { - AbstractMetaFunction *func = functions.at(i); - int argc = func->arguments().size(); - for (int k = argc; k > 0; --k) { - if (func->argumentRemoved(k)) - --argc; - } - for (int j = func->actualMinimumArgumentCount(); j <= argc; ++j) - result[j].append(func); - } - return result; -} - -/*! - Returns the name of the QScriptValue function to use to test if - a value is of the given \a typeName, or an empty string if there - is no such function. -*/ -static QString builtinTypeTesterFunction(const QString &typeName) -{ - if (typeName == QLatin1String("QString")) - return QLatin1String("isString"); - else if (typeName == QLatin1String("double")) - return QLatin1String("isNumber"); - else if (typeName == QLatin1String("float")) - return QLatin1String("isNumber"); - else if (typeName == QLatin1String("int")) - return QLatin1String("isNumber"); - else if (typeName == QLatin1String("uint")) - return QLatin1String("isNumber"); - else if (typeName == QLatin1String("short")) - return QLatin1String("isNumber"); - else if (typeName == QLatin1String("unsigned short")) - return QLatin1String("isNumber"); - else if (typeName == QLatin1String("bool")) - return QLatin1String("isBoolean"); - else if (typeName == QLatin1String("QVariant")) - return QLatin1String("isVariant"); -// else if (typeName == QLatin1String("QDateTime")) -// return QLatin1String("isDate"); - else if (typeName == QLatin1String("QRegExp")) - return QLatin1String("isRegExp"); - else if (typeName == QLatin1String("QObject*")) - return QLatin1String("isQObject"); - return QString(); -} - -/*! - Writes the code injections for the class \a meta_class that should - be injected at position \a pos. -*/ -static void writeInjectedCode(QTextStream &s, const AbstractMetaClass *meta_class, - CodeSnip::Position pos) -{ - CodeSnipList code_snips = meta_class->typeEntry()->codeSnips(); - foreach (const CodeSnip &cs, code_snips) { - if ((cs.language == TypeSystem::NativeCode) && (cs.position == pos)) { - s << cs.code() << endl; - } - } -} - -/*! - Writes the code injections for the function \a fun of the class \a - meta_class that should be injected at position \a pos. -*/ -static void writeInjectedCode(QTextStream &s, const AbstractMetaClass *meta_class, - const AbstractMetaFunction *fun, CodeSnip::Position pos) -{ - FunctionModificationList mods = fun->modifications(meta_class); - foreach (const FunctionModification &mod, mods) { - if (!mod.isCodeInjection()) - continue; - foreach (const CodeSnip &cs, mod.snips) { - if ((cs.language == TypeSystem::NativeCode) && (cs.position == pos)) { - s << cs.code() << endl; - } - } - } -} - -/*! - Writes a boolean expression that checks if the actual arguments are - compatible with what the function expects. This is used to resolve - ambiguous calls. -*/ -static void writeArgumentTypeTests(QTextStream &stream, const AbstractMetaFunction *fun, - const AbstractMetaArgumentList &arguments, int argc, int indent) -{ - QString indentStr(indent, QLatin1Char(' ')); - int j = 0; - for (int i = 0; i < argc; ++j) { - if (fun->argumentRemoved(j+1)) - continue; - if (i > 0) - stream << endl << indentStr << "&& "; - const AbstractMetaType *argType = 0; - QString typeName = fun->typeReplaced(j+1); - if (typeName.isEmpty()) { - AbstractMetaArgument *arg = arguments.at(j); - argType = arg->type(); - typeName = normalizedType(argType); - } - QString scriptArg = QString::fromLatin1("context->argument(%0)").arg(i); - if (argType && isSequenceType(argType)) { - stream << scriptArg << ".isArray()"; - } else if (typeName == "QVariant") { - stream << "true"; - } else { - QString tester = builtinTypeTesterFunction(typeName); - if (!tester.isEmpty()) { - stream << scriptArg << "." << tester << "()"; - } else if (typeName.endsWith('*')) { - stream << "qscriptvalue_cast<" << typeName << ">(" << scriptArg << ")"; - } else { - // typeid-based test - stream << "(qMetaTypeId<" << typeName; - if (typeName.endsWith(QLatin1Char('>'))) - stream << " "; - stream << ">() == " << scriptArg << ".toVariant().userType())"; - } - } - ++i; - } -} - -/*! - Returns the name of the QScriptValue function to use to convert a - value is of the given \a typeName, or an empty string if there is no - such function. -*/ -static QString builtinConversionFunction(const QString &typeName) -{ - if (typeName == QLatin1String("QString")) - return QLatin1String("toString"); - else if (typeName == QLatin1String("double")) - return QLatin1String("toNumber"); - else if (typeName == QLatin1String("int")) - return QLatin1String("toInt32"); - else if (typeName == QLatin1String("uint")) - return QLatin1String("toUInt32"); - else if (typeName == QLatin1String("bool")) - return QLatin1String("toBoolean"); - else if (typeName == QLatin1String("QVariant")) - return QLatin1String("toVariant"); - else if (typeName == QLatin1String("QDateTime")) - return QLatin1String("toDateTime"); - else if (typeName == QLatin1String("QRegExp")) - return QLatin1String("toRegExp"); - else if (typeName == QLatin1String("QObject*")) - return QLatin1String("toQObject"); - return QString(); -} - -/*! - Generates script arguments --> C++ types conversion, in preparation - for calling the native function we are binding. -*/ -static int writePrepareArguments(QTextStream &stream, const AbstractMetaFunction *fun, - const AbstractMetaArgumentList &arguments, - int scriptArgc, int indent) -{ - if (arguments.size() == 0) { - Q_ASSERT(scriptArgc == 0); - return 0; // nothing to do - } - QString indentStr(indent, QLatin1Char(' ')); - int j = 0; - for (int scriptArgIndex = 0; j < arguments.size(); ++j) { - const AbstractMetaArgument *arg = arguments.at(j); - bool isOptional = !arg->defaultValueExpression().isEmpty(); - if (isOptional && (scriptArgIndex == scriptArgc)) - break; - QString conv = fun->conversionRule(TypeSystem::NativeCode, j+1); - QString actualIn = QString::fromLatin1("context->argument(%0)").arg(scriptArgIndex); - QString actualOut = QString::fromLatin1("_q_arg%0").arg(j); - if (!conv.isEmpty()) { - // custom conversion - conv.replace(QString::fromLatin1("%in%"), actualIn); - conv.replace(QString::fromLatin1("%out%"), actualOut); - conv.replace(QString::fromLatin1("%this%"), QString::fromLatin1("_q_self")); - stream << conv; - } else { - const AbstractMetaType *argType = 0; - QString typeName = fun->typeReplaced(j+1); - if (typeName.isEmpty()) { - argType = arg->type(); - typeName = normalizedType(argType); - } - stream << indentStr << typeName << " " << actualOut; - QString converter; - // ### generalize the QSet check (we should check if the type has push_back()) - bool useToSequence = argType && isSequenceType(argType) && !argType->name().startsWith("Set"); - if (useToSequence) { - stream << ";" << endl; - stream << indentStr << "qScriptValueToSequence("; - } else { - stream << " = "; - converter = builtinConversionFunction(typeName); - if (converter.isEmpty()) { - // generic conversion - stream << "qscriptvalue_cast<" << typeName; - if (typeName.endsWith(QLatin1Char('>'))) - stream << " "; - stream << ">("; - } - } - stream << actualIn; - if (useToSequence) { - stream << ", " << actualOut << ")"; - } else { - if (converter.isEmpty()) { - stream << ")"; // close qscriptvalue_cast - } else { - stream << "." << converter << "()"; - } - } - stream << ";" << endl; - } - if (!fun->argumentRemoved(j+1)) - ++scriptArgIndex; - } - return j; -} - -/*! - Writes the arguments that are passed to the native function we are - binding. Those arguments must have been prepared already in variables - _q_arg0, _q_arg1, .. in the generated code. -*/ -static void writeArguments(QTextStream &stream, int count) -{ - for (int i = 0; i < count; ++i) { - if (i > 0) - stream << ", "; - stream << "_q_arg" << i; - } -} - -/*! - Writes a constructor call. -*/ -static void writeConstructorCallAndReturn(QTextStream &stream, const AbstractMetaFunction *fun, - int scriptArgc, const AbstractMetaClass *meta_class, - int indent) -{ - QString indentStr(indent, QLatin1Char(' ')); - - writeInjectedCode(stream, meta_class, fun, CodeSnip::Beginning); - - AbstractMetaArgumentList arguments = fun->arguments(); - Q_ASSERT(arguments.size() >= scriptArgc); - int nativeArgc = writePrepareArguments(stream, fun, arguments, scriptArgc, indent); - stream << indentStr; - if (meta_class->generateShellClass()) { - stream << "QtScriptShell_" << meta_class->name(); - } else { - stream << meta_class->qualifiedCppName(); - } - bool useNew = meta_class->typeEntry()->isObject() || !hasDefaultConstructor(meta_class); - if (useNew) - stream << "*"; - stream << " _q_cpp_result"; - if (useNew) { - stream << " = new "; - if (meta_class->generateShellClass()) - stream << "QtScriptShell_" << meta_class->name(); - else - stream << meta_class->qualifiedCppName(); - } - if (useNew || (nativeArgc != 0)) { - stream << "("; - writeArguments(stream, nativeArgc); - stream << ")"; - } - stream << ";" << endl; - - stream << indentStr << "QScriptValue _q_result = context->engine()->new"; - if (isQObjectBased(meta_class)) - stream << "QObject"; - else - stream << "Variant"; - stream << "(context->thisObject(), "; - if (!isQObjectBased(meta_class)) - stream << "qVariantFromValue("; - if (meta_class->generateShellClass()) { - stream << "(" << meta_class->qualifiedCppName(); - if (useNew) - stream << "*"; - stream << ")"; - } - stream << "_q_cpp_result"; - if (isQObjectBased(meta_class)) - stream << ", QScriptEngine::AutoOwnership"; - else - stream << ")"; - stream << ");" << endl; - if (meta_class->generateShellClass()) { - stream << indentStr << "_q_cpp_result"; - if (useNew) - stream << "->"; - else - stream << "."; - stream << "__qtscript_self = _q_result;" << endl; - } - - writeInjectedCode(stream, meta_class, fun, CodeSnip::End); - - stream << indentStr << "return _q_result;" << endl; -} - -/*! - Returns true if the given \a typeName has a QScriptValue constructor - we can use, false otherwise. -*/ -static bool hasScriptValueConstructor(const QString &typeName) -{ - return (typeName == QLatin1String("bool")) - || (typeName == QLatin1String("int")) - || (typeName == QLatin1String("uint")) - || (typeName == QLatin1String("double")) - || (typeName == QLatin1String("QString")); -} - -/*! - Writes a function call. -*/ -static void writeFunctionCallAndReturn(QTextStream &stream, const AbstractMetaFunction *fun, - int scriptArgc, const AbstractMetaClass *meta_class, - int indent) -{ - QString indentStr(indent, QLatin1Char(' ')); - AbstractMetaArgumentList arguments = fun->arguments(); - Q_ASSERT(arguments.size() >= scriptArgc); - - writeInjectedCode(stream, meta_class, fun, CodeSnip::Beginning); - - int nativeArgc = writePrepareArguments(stream, fun, arguments, scriptArgc, indent); - bool returnThisObject = fun->shouldReturnThisObject(); - bool ignoreReturnValue = returnThisObject || fun->shouldIgnoreReturnValue(); - stream << indentStr; - AbstractMetaType *retType = fun->type(); - bool constCastResult = false; - if (retType && !ignoreReturnValue) { - QString rsig = retType->cppSignature(); - QString typeName = normalizedType(retType); - stream << typeName << " _q_result = "; - constCastResult = rsig.endsWith('*') && rsig.startsWith("const "); - if (constCastResult) - stream << "const_cast<" << typeName << ">("; - } - - if (!fun->isStatic()) { - // ### the friendly check should be enough... - if (fun->isFriendly() - || ((fun->name() == QLatin1String("operator_equal")) - && ((meta_class->name() == QLatin1String("QPoint")) - || (meta_class->name() == QLatin1String("QPointF")) - || (meta_class->name() == QLatin1String("QRect")) - || (meta_class->name() == QLatin1String("QRectF")) - || (meta_class->name() == QLatin1String("QSize")) - || (meta_class->name() == QLatin1String("QSizeF"))))) { - stream << fun->originalName() << "("; - stream << "*_q_self, "; - } else { - stream << "_q_self->"; - stream << fun->originalName() << "("; - } - } else { - stream << meta_class->qualifiedCppName() << "::"; - stream << fun->originalName() << "("; - } - writeArguments(stream, nativeArgc); - if (constCastResult) - stream << ")"; - stream << ");" << endl; - - writeInjectedCode(stream, meta_class, fun, CodeSnip::End); - - // write return statement - stream << indentStr; - if (returnThisObject) { - stream << "return context->thisObject();"; - } else { - QString conv = fun->conversionRule(TypeSystem::NativeCode, 0); - if (!conv.isEmpty()) { - // custom conversion - conv.replace(QString::fromLatin1("%in%"), "_q_result"); - conv.replace(QString::fromLatin1("%out%"), "_q_convertedResult"); - stream << conv; - stream << "return qScriptValueFromValue(context->engine(), _q_convertedResult);"; - } else { - stream << "return "; - if (retType) { - if (isSequenceType(retType)) - stream << "qScriptValueFromSequence"; - else if (hasScriptValueConstructor(normalizedType(retType))) - stream << "QScriptValue"; - else - stream << "qScriptValueFromValue"; - stream << "(context->engine(), _q_result);"; - } else { - stream << "context->engine()->undefinedValue();"; - } - } - } - stream << endl; -} - -/*! - Returns true if the given function \a fun is operator>>() or - operator<<() that streams from/to a Q{Data,Text}Stream, false - otherwise. -*/ -bool ClassGenerator::isSpecialStreamingOperator(const AbstractMetaFunction *fun) -{ - return ((fun->functionType() == AbstractMetaFunction::GlobalScopeFunction) - && (fun->arguments().size() == 1) - && (((fun->originalName() == "operator>>") && (fun->modifiedName() == "readFrom")) - || ((fun->originalName() == "operator<<") && (fun->modifiedName() == "writeTo")))); -} - -/*! - Generates code that uses Q{Data,Text}Stream operator>>() or - operator<<() to read/write an instance of meta_class. -*/ -static void writeStreamingOperatorCall(QTextStream &stream, const AbstractMetaFunction *fun, - const AbstractMetaClass * /*meta_class*/, int indent) -{ - QString indentStr(indent, QLatin1Char(' ')); - QString streamClassName = fun->arguments().at(0)->type()->name(); - stream << indentStr << streamClassName << "* _q_arg0 = qscriptvalue_cast<" - << streamClassName << "*>(context->argument(0));" << endl; - stream << indentStr << "operator"; - if (fun->modifiedName() == "readFrom") - stream << ">>"; - else - stream << "<<"; - stream << "(*_q_arg0, *_q_self);" << endl; - stream << indentStr << "return context->engine()->undefinedValue();" << endl; -} - -/*! - Writes the constructor forwarding for \a meta_class. -*/ -static void writeConstructorForwarding(QTextStream &stream, - const AbstractMetaFunctionList &functions, - const AbstractMetaClass *meta_class) -{ -#if 0 - stream << "/** signatures:" << endl; - foreach (const AbstractMetaFunction *fun, functions) { - stream << " * " << fun->signature() << endl; - } - stream << " */" << endl; -#endif - - if (/*meta_class->isAbstract() ||*/ (functions.size() == 0)) { - stream << " return context->throwError(QScriptContext::TypeError," << endl - << " QString::fromLatin1(\"" << meta_class->name() - << " cannot be constructed\"));" << endl; - - } else { - stream << " if (context->thisObject().strictlyEquals(context->engine()->globalObject())) {" << endl - << " return context->throwError(QString::fromLatin1(\"" - << meta_class->name() << "(): Did you forget to construct with 'new'?\"));" << endl - << " }" << endl; - - writeInjectedCode(stream, meta_class, CodeSnip::Constructor); - - QMap argcToFunctions; - argcToFunctions = createArgcToFunctionsMap(functions); - - int argcMin = argcToFunctions.keys().first(); - int argcMax = argcToFunctions.keys().last(); - bool needElse = false; - for (int i = argcMin; i <= argcMax; ++i) { - AbstractMetaFunctionList funcs = argcToFunctions.value(i); - if (funcs.isEmpty()) - continue; - if (needElse) - stream << " else "; - else - stream << " "; - needElse = true; - stream << "if (context->argumentCount() == " << i << ") {" << endl; - if ((funcs.size() == 1) || (i == 0)) { - AbstractMetaFunction *fun = funcs.at(0); - const int indent = 8; - writeConstructorCallAndReturn(stream, fun, i, meta_class, indent); - } else { - // handle overloads - for (int j = 0; j < funcs.size(); ++j) { - AbstractMetaFunction *fun = funcs.at(j); - stream << " "; - if (j > 0) - stream << "} else "; - stream << "if ("; - AbstractMetaArgumentList arguments = fun->arguments(); - const int indent = 12; - writeArgumentTypeTests(stream, fun, arguments, i, indent); - stream << ") {" << endl; - writeConstructorCallAndReturn(stream, fun, i, meta_class, indent); - } - stream << " }" << endl; - } - stream << " }"; - } - stream << endl; -// writeThrowAmbiguityError(stream, meta_class, 0, signatures.toList()); - } -} - -/*! - Returns a list of enum \a values that are actually unique. - */ -QList uniqueEnumValueIndexes(const AbstractMetaEnumValueList &values) -{ - QMap map; - for (int i = 0; i < values.count(); ++i) { - AbstractMetaEnumValue *val = values.at(i); - if (!map.contains(val->value())) - map.insert(val->value(), i); - } - return map.values(); -} - -/*! - */ -static bool isContiguousEnum(const QList &indexes, const AbstractMetaEnumValueList &values) -{ - if (indexes.isEmpty()) - return false; - int prev = values.at(indexes.at(0))->value(); - for (int i = 1; i < indexes.size(); ++i) { - int curr = values.at(indexes.at(i))->value(); - if (curr != prev + 1) - return false; - prev = curr; - } - return true; -} - -static void writeCreateEnumClassHelper(QTextStream &stream) -{ - stream << "static QScriptValue qtscript_create_enum_class_helper(" << endl - << " QScriptEngine *engine," << endl - << " QScriptEngine::FunctionSignature construct," << endl - << " QScriptEngine::FunctionSignature valueOf," << endl - << " QScriptEngine::FunctionSignature toString)" << endl - << "{" << endl - << " QScriptValue proto = engine->newObject();" << endl - << " proto.setProperty(QString::fromLatin1(\"valueOf\")," << endl - << " engine->newFunction(valueOf), QScriptValue::SkipInEnumeration);" << endl - << " proto.setProperty(QString::fromLatin1(\"toString\")," << endl - << " engine->newFunction(toString), QScriptValue::SkipInEnumeration);" << endl - << " return engine->newFunction(construct, proto, 1);" << endl - << "}" << endl << endl; -} - -static void writeCreateFlagsClassHelper(QTextStream &stream) -{ - stream << "static QScriptValue qtscript_create_flags_class_helper(" << endl - << " QScriptEngine *engine," << endl - << " QScriptEngine::FunctionSignature construct," << endl - << " QScriptEngine::FunctionSignature valueOf," << endl - << " QScriptEngine::FunctionSignature toString," << endl - << " QScriptEngine::FunctionSignature equals)" << endl - << "{" << endl - << " QScriptValue proto = engine->newObject();" << endl - << " proto.setProperty(QString::fromLatin1(\"valueOf\")," << endl - << " engine->newFunction(valueOf), QScriptValue::SkipInEnumeration);" << endl - << " proto.setProperty(QString::fromLatin1(\"toString\")," << endl - << " engine->newFunction(toString), QScriptValue::SkipInEnumeration);" << endl - << " proto.setProperty(QString::fromLatin1(\"equals\")," << endl - << " engine->newFunction(equals), QScriptValue::SkipInEnumeration);" << endl - << " return engine->newFunction(construct, proto);" << endl - << "}" << endl << endl; -} - -/*! - Writes the enum \a enom belonging to the class \a meta_class to the - given \a stream. - */ -static void writeEnumClass(QTextStream &stream, const AbstractMetaClass *meta_class, - const AbstractMetaEnum *enom) -{ - QString qualifiedCppNameColons; - if (meta_class->name() != "Global") - qualifiedCppNameColons = meta_class->qualifiedCppName() + "::"; - QString qualifiedEnumName = qualifiedCppNameColons + enom->name(); - QString qtScriptEnumName = meta_class->name() + "_" + enom->name(); - - stream << "//" << endl; - stream << "// " << qualifiedEnumName << endl; - stream << "//" << endl << endl; - - // determine unique values (aliases will cause switch statement to not compile) - AbstractMetaEnumValueList values = enom->values(); - QList uniqueIndexes = uniqueEnumValueIndexes(values); - - bool contiguous = isContiguousEnum(uniqueIndexes, values); - - // write arrays of values and keys - stream << "static const " << qualifiedEnumName - << " qtscript_" << qtScriptEnumName << "_values[] = {" << endl; - for (int i = 0; i < uniqueIndexes.size(); ++i) { - stream << " "; - if (i > 0) - stream << ", "; - stream << qualifiedCppNameColons << values.at(uniqueIndexes.at(i))->name() << endl; - } - stream << "};" << endl << endl; - stream << "static const char * const qtscript_" << qtScriptEnumName << "_keys[] = {" << endl; - for (int i = 0; i < uniqueIndexes.size(); ++i) { - stream << " "; - if (i > 0) - stream << ", "; - stream << "\"" << values.at(uniqueIndexes.at(i))->name() << "\"" << endl; - } - stream << "};" << endl << endl; - - // write toString helper - stream << "static QString qtscript_" - << qtScriptEnumName << "_toStringHelper" - << "(" << qualifiedEnumName << " value)" << endl; - stream << "{" << endl; - if (enom->hasQEnumsDeclaration() && (meta_class->qualifiedCppName() != "QTransform")) { - stream << " const QMetaObject *meta = qtscript_" << meta_class->name() << "_metaObject();" << endl; - stream << " int idx = meta->indexOfEnumerator(\"" << enom->name() << "\");" << endl; - stream << " Q_ASSERT(idx != -1);" << endl; - stream << " QMetaEnum menum = meta->enumerator(idx);" << endl; - stream << " return QString::fromLatin1(menum.valueToKey(value));" << endl; - } else { - if (contiguous) { - stream << " if ((value >= " << qualifiedCppNameColons - << values.at(uniqueIndexes.first())->name() << ")" - << " && (value <= " << qualifiedCppNameColons - << values.at(uniqueIndexes.last())->name() << "))" << endl - << " return qtscript_" << qtScriptEnumName - << "_keys[static_cast(value)-static_cast(" - << qualifiedCppNameColons - << values.at(uniqueIndexes.first())->name() << ")];" << endl; - } else { - stream << " for (int i = 0; i < " << uniqueIndexes.size() << "; ++i) {" << endl - << " if (qtscript_" << qtScriptEnumName << "_values[i] == value)" << endl - << " return QString::fromLatin1(qtscript_" << qtScriptEnumName << "_keys[i]);" << endl - << " }" << endl; - } - stream << " return QString();" << endl; - } - stream << "}" << endl << endl; - - // write QScriptValue <--> C++ conversion functions - stream << "static QScriptValue qtscript_" - << qtScriptEnumName << "_toScriptValue(" - << "QScriptEngine *engine, const " << qualifiedEnumName << " &value)" << endl - << "{" << endl - << " QScriptValue clazz = engine->globalObject().property(QString::fromLatin1(\"" - << meta_class->name() << "\"));" << endl -// << " QScriptValue enumClazz = clazz.property(QString::fromLatin1(\"" -// << enom->name() << "\"));" << endl - << " return clazz.property(qtscript_" << qtScriptEnumName << "_toStringHelper(value));" << endl - << "}" << endl << endl; - stream << "static void qtscript_" - << qtScriptEnumName << "_fromScriptValue(" - << "const QScriptValue &value, " << qualifiedEnumName << " &out)" << endl - << "{" << endl - << " out = qvariant_cast<" << qualifiedEnumName << ">(value.toVariant());" << endl - << "}" << endl << endl; - - // write constructor - stream << "static QScriptValue qtscript_construct_" - << qtScriptEnumName - << "(QScriptContext *context, QScriptEngine *engine)" << endl; - stream << "{" << endl; - stream << " int arg = context->argument(0).toInt32();" << endl; - if (enom->hasQEnumsDeclaration() && (meta_class->qualifiedCppName() != "QTransform")) { - stream << " const QMetaObject *meta = qtscript_" << meta_class->name() << "_metaObject();" << endl; - stream << " int idx = meta->indexOfEnumerator(\"" << enom->name() << "\");" << endl; - stream << " Q_ASSERT(idx != -1);" << endl; - stream << " QMetaEnum menum = meta->enumerator(idx);" << endl; - stream << " if (menum.valueToKey(arg) != 0)" << endl; - stream << " return qScriptValueFromValue(engine, static_cast<" - << qualifiedEnumName << ">(arg));" << endl; - } else { - if (contiguous) { - stream << " if ((arg >= " << qualifiedCppNameColons - << values.at(uniqueIndexes.first())->name() << ")" - << " && (arg <= " << qualifiedCppNameColons - << values.at(uniqueIndexes.last())->name() << "))" << endl; - stream << " return qScriptValueFromValue(engine, static_cast<" - << qualifiedEnumName << ">(arg));" << endl; - } else { - stream << " for (int i = 0; i < " << uniqueIndexes.size() << "; ++i) {" << endl - << " if (qtscript_" << qtScriptEnumName << "_values[i] == arg)" << endl; - stream << " return qScriptValueFromValue(engine, static_cast<" - << qualifiedEnumName << ">(arg));" << endl; - stream << " }" << endl; - } - } - stream << " return context->throwError(QString::fromLatin1(\"" - << enom->name() << "(): invalid enum value (%0)\").arg(arg));" << endl; - stream << "}" << endl; - stream << endl; - - // write prototype.valueOf() - stream << "static QScriptValue qtscript_" << qtScriptEnumName - << "_valueOf(QScriptContext *context, QScriptEngine *engine)" << endl; - stream << "{" << endl; - stream << " " << qualifiedEnumName << " value = " - << "qscriptvalue_cast<" << qualifiedEnumName - << ">(context->thisObject());" << endl; - stream << " return QScriptValue(engine, static_cast(value));" << endl; - stream << "}" << endl; - stream << endl; - - // write prototype.toString() - stream << "static QScriptValue qtscript_" << qtScriptEnumName - << "_toString(QScriptContext *context, QScriptEngine *engine)" << endl; - stream << "{" << endl; - stream << " " << qualifiedEnumName << " value = " - << "qscriptvalue_cast<" << qualifiedEnumName - << ">(context->thisObject());" << endl; - stream << " return QScriptValue(engine, qtscript_" << qtScriptEnumName << "_toStringHelper(value));" << endl; - stream << "}" << endl; - stream << endl; - - // write class creation function - stream << "static QScriptValue qtscript_create_" - << qtScriptEnumName - << "_class(QScriptEngine *engine, QScriptValue &clazz)" << endl; - stream << "{" << endl; - - stream << " QScriptValue ctor = qtscript_create_enum_class_helper(" << endl - << " engine, qtscript_construct_" << qtScriptEnumName << "," << endl - << " qtscript_" << qtScriptEnumName << "_valueOf, qtscript_" - << qtScriptEnumName << "_toString);" << endl; - - stream << " qScriptRegisterMetaType<" << qualifiedEnumName << ">(engine, " - << "qtscript_" << qtScriptEnumName << "_toScriptValue," << endl - << " qtscript_" << qtScriptEnumName << "_fromScriptValue," - << " ctor.property(QString::fromLatin1(\"prototype\")));" << endl; - - // enum values are properties of the constructor - stream << " for (int i = 0; i < " << uniqueIndexes.size() << "; ++i) {" << endl - << " clazz.setProperty(QString::fromLatin1(qtscript_" - << qtScriptEnumName << "_keys[i])," << endl - << " engine->newVariant(qVariantFromValue(qtscript_" - << qtScriptEnumName << "_values[i]))," << endl - << " QScriptValue::ReadOnly | QScriptValue::Undeletable);" << endl - << " }" << endl; - - stream << " return ctor;" << endl; - stream << "}" << endl; - stream << endl; - - // write flags class too, if any - FlagsTypeEntry *flags = enom->typeEntry()->flags(); - if (!flags) - return; - - QString qualifiedFlagsName = qualifiedCppNameColons + flags->targetLangName(); - QString qtScriptFlagsName = meta_class->name() + "_" + flags->targetLangName(); - - stream << "//" << endl; - stream << "// " << qualifiedFlagsName << endl; - stream << "//" << endl << endl; - - // write QScriptValue <--> C++ conversion functions - stream << "static QScriptValue qtscript_" - << qtScriptFlagsName << "_toScriptValue(" - << "QScriptEngine *engine, const " << qualifiedFlagsName << " &value)" << endl - << "{" << endl - << " return engine->newVariant(qVariantFromValue(value));" << endl - << "}" << endl << endl; - stream << "static void qtscript_" - << qtScriptFlagsName << "_fromScriptValue(" - << "const QScriptValue &value, " << qualifiedFlagsName << " &out)" << endl - << "{" << endl - << " QVariant var = value.toVariant();" << endl - << " if (var.userType() == qMetaTypeId<" << qualifiedFlagsName << ">())" << endl - << " out = qvariant_cast<" << qualifiedFlagsName << ">(var);" << endl - << " else if (var.userType() == qMetaTypeId<" << qualifiedEnumName << ">())" << endl - << " out = qvariant_cast<" << qualifiedEnumName << ">(var);" << endl - << " else" << endl - << " out = 0;" << endl - << "}" << endl << endl; - - // write constructor - stream << "static QScriptValue qtscript_construct_" - << qtScriptFlagsName - << "(QScriptContext *context, QScriptEngine *engine)" << endl; - stream << "{" << endl; - stream << " " << qualifiedFlagsName << " result = 0;" << endl; - stream << " if ((context->argumentCount() == 1) && context->argument(0).isNumber()) {" << endl; - stream << " result = static_cast<" << qualifiedFlagsName << ">(context->argument(0).toInt32());" << endl; - stream << " } else {" << endl; - stream << " for (int i = 0; i < context->argumentCount(); ++i) {" << endl; - stream << " QVariant v = context->argument(i).toVariant();" << endl; - stream << " if (v.userType() != qMetaTypeId<" << qualifiedEnumName << ">()) {" << endl; - stream << " return context->throwError(QScriptContext::TypeError," << endl - << " QString::fromLatin1(\"" << flags->targetLangName() - << "(): argument %0 is not of type " << enom->name() << "\").arg(i));" << endl; - stream << " }" << endl; - stream << " result |= qvariant_cast<" << qualifiedEnumName - << ">(v);" << endl; - stream << " }" << endl; - stream << " }" << endl; - stream << " return engine->newVariant(qVariantFromValue(result));" << endl; - stream << "}" << endl; - stream << endl; - - // write prototype.valueOf() - stream << "static QScriptValue qtscript_" << qtScriptFlagsName - << "_valueOf(QScriptContext *context, QScriptEngine *engine)" << endl; - stream << "{" << endl; - stream << " " << qualifiedFlagsName << " value = " - << "qscriptvalue_cast<" << qualifiedFlagsName - << ">(context->thisObject());" << endl; - stream << " return QScriptValue(engine, static_cast(value));" << endl; - stream << "}" << endl; - stream << endl; - - // write prototype.toString() - stream << "static QScriptValue qtscript_" << qtScriptFlagsName - << "_toString(QScriptContext *context, QScriptEngine *engine)" << endl; - stream << "{" << endl; - stream << " " << qualifiedFlagsName << " value = " - << "qscriptvalue_cast<" << qualifiedFlagsName - << ">(context->thisObject());" << endl; - stream << " QString result;" << endl; - stream << " for (int i = 0; i < " << uniqueIndexes.size() << "; ++i) {" << endl - << " if ((value & qtscript_" << qtScriptEnumName << "_values[i])" - << " == qtscript_" << qtScriptEnumName << "_values[i]) {" << endl - << " if (!result.isEmpty())" << endl - << " result.append(QString::fromLatin1(\",\"));" << endl - << " result.append(QString::fromLatin1(qtscript_" << qtScriptEnumName << "_keys[i]));" << endl - << " }" << endl - << " }" << endl - << " return QScriptValue(engine, result);" << endl - << "}" << endl - << endl; - - // write prototype.equals() - stream << "static QScriptValue qtscript_" << qtScriptFlagsName - << "_equals(QScriptContext *context, QScriptEngine *engine)" << endl - << "{" << endl - << " QVariant thisObj = context->thisObject().toVariant();" << endl - << " QVariant otherObj = context->argument(0).toVariant();" << endl - - << " return QScriptValue(engine, ((thisObj.userType() == otherObj.userType()) &&" << endl - << " (thisObj.value<" << qualifiedFlagsName << ">() == otherObj.value<" << qualifiedFlagsName << ">())));" << endl - << "}" << endl << endl; - - // write class creation function - stream << "static QScriptValue qtscript_create_" << qtScriptFlagsName << "_class(QScriptEngine *engine)" << endl; - stream << "{" << endl; - stream << " QScriptValue ctor = qtscript_create_flags_class_helper(" << endl - << " engine, qtscript_construct_" << qtScriptFlagsName - << ", qtscript_" << qtScriptFlagsName << "_valueOf," << endl - << " qtscript_" << qtScriptFlagsName << "_toString, qtscript_" - << qtScriptFlagsName << "_equals);" << endl; - - stream << " qScriptRegisterMetaType<" << qualifiedFlagsName << ">(engine, " - << "qtscript_" << qtScriptFlagsName << "_toScriptValue," << endl - << " qtscript_" << qtScriptFlagsName << "_fromScriptValue," - << " ctor.property(QString::fromLatin1(\"prototype\")));" << endl; - - stream << " return ctor;" << endl; - stream << "}" << endl; - stream << endl; -} - -/*! - Declares the given \a typeName if it hasn't been declared already, - and adds it to the set of registered type names. -*/ -void maybeDeclareMetaType(QTextStream &stream, const QString &typeName, - QSet ®isteredTypeNames) -{ - QString name = typeName; - if (name.endsWith(QLatin1Char('&'))) - name.chop(1); - if (registeredTypeNames.contains(name) || (QMetaType::type(typeName.toLatin1()) != 0)) - return; - if (name.contains(QLatin1Char(','))) { - // need to expand the Q_DECLARE_METATYPE macro manually, - // otherwise the compiler will choke - stream << "template <> \\" << endl - << "struct QMetaTypeId< " << name << " > \\" << endl - << "{ \\" << endl - << " enum { Defined = 1 }; \\" << endl - << " static int qt_metatype_id() \\" << endl - << " { \\" << endl - << " static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \\" << endl - << " if (!metatype_id) \\" << endl - << " metatype_id = qRegisterMetaType< " << name << " >(\"" << name << "\"); \\" << endl - << " return metatype_id; \\" << endl - << " } \\" << endl - << "};" << endl; - } else { - stream << "Q_DECLARE_METATYPE(" << name << ")" << endl; - } - registeredTypeNames << name; -} - -/*! - Declares the given \a type recursively (i.e. subtypes of a composite - type are also declared). -*/ -static void declareTypeRecursive(QTextStream &stream, const AbstractMetaType *type, - QSet ®isteredTypeNames) -{ - if (!type) - return; - QList subTypes = type->instantiations(); - for (int i = 0; i < subTypes.size(); ++i) - declareTypeRecursive(stream, subTypes.at(i), registeredTypeNames); - QString typeName = normalizedType(type); - if (typeName == QLatin1String("QStringList")) - return; // ### wtf... - maybeDeclareMetaType(stream, typeName, registeredTypeNames); -} - -/*! - Declares the types associated with the given \a functions. -*/ -void declareFunctionMetaTypes(QTextStream &stream, const AbstractMetaFunctionList &functions, - QSet ®isteredTypeNames) -{ - for (int i = 0; i < functions.size(); ++i) { - AbstractMetaFunction *fun = functions.at(i); - if (ClassGenerator::isSpecialStreamingOperator(fun)) { - maybeDeclareMetaType(stream, fun->arguments().at(0)->type()->name() + "*", - registeredTypeNames); - continue; - } - AbstractMetaArgumentList arguments = fun->arguments(); - for (int j = 0; j < arguments.size(); ++j) { - if (fun->argumentRemoved(j+1)) - continue; - QString repl = fun->typeReplaced(j+1); - if (!repl.isEmpty()) { - maybeDeclareMetaType(stream, repl, registeredTypeNames); - } else { - const AbstractMetaArgument *arg = arguments.at(j); - declareTypeRecursive(stream, arg->type(), registeredTypeNames); - } - } - QString retRepl = fun->typeReplaced(0); - if (!retRepl.isEmpty()) - maybeDeclareMetaType(stream, retRepl, registeredTypeNames); - else - declareTypeRecursive(stream, fun->type(), registeredTypeNames); - } -} - -/*! - Returns true if we don't care about the given enum \a enom, - false otherwise. -*/ -static bool shouldIgnoreEnum(const AbstractMetaEnum *enom) -{ - return !enom->wasPublic() || (enom->name() == "enum_1"); -} - -/*! - Declares the types associated with the enums of the given \a - meta_class. -*/ -void declareEnumMetaTypes(QTextStream &stream, const AbstractMetaClass *meta_class, - QSet ®isteredTypeNames) -{ - AbstractMetaEnumList enums = meta_class->enums(); - for (int i = 0; i < enums.size(); ++i) { - const AbstractMetaEnum *enom = enums.at(i); - if (shouldIgnoreEnum(enom)) - continue; - if (meta_class->name() == "Global") - maybeDeclareMetaType(stream, enom->name(), registeredTypeNames); - else - maybeDeclareMetaType(stream, QString::fromLatin1("%0::%1") - .arg(meta_class->qualifiedCppName()).arg(enom->name()), - registeredTypeNames); - FlagsTypeEntry *flags = enom->typeEntry()->flags(); - if (flags) { - maybeDeclareMetaType(stream, QString::fromLatin1("QFlags<%0::%1>") - .arg(meta_class->qualifiedCppName()).arg(enom->name()), - registeredTypeNames); - } - } -} - -/*! - Returns the maximum function length among \a functions. -*/ -static int maxFunctionLength(const AbstractMetaFunctionList &functions) -{ - int result = 0; - for (int i = 0; i < functions.size(); ++i) - result = qMax(result, functions.at(i)->arguments().size()); - return result; -} - -/*! - Writes a prototype/static function. -*/ -static void writeFunctionForwarding(QTextStream &stream, const AbstractMetaClass *meta_class, - const AbstractMetaFunctionList &functions) -{ -#if 0 - stream << "/** signatures:" << endl; - foreach (const AbstractMetaFunction *fun, functions) { - stream << " * " << fun->signature() << endl; - } - stream << " */" << endl; -#endif - QMap argcToFunctions; - argcToFunctions = createArgcToFunctionsMap(functions); - QSet signatures; - int argcMin = argcToFunctions.keys().first(); - int argcMax = argcToFunctions.keys().last(); - for (int i = argcMin; i <= argcMax; ++i) { - AbstractMetaFunctionList funcs = argcToFunctions.value(i); - if (funcs.isEmpty()) - continue; - stream << " if (context->argumentCount() == " << i << ") {" << endl; - if (funcs.size() == 1) { - AbstractMetaFunction *fun = funcs.at(0); - const int indent = 8; - // special case for Q{Data,Text}Stream streaming operators - if (ClassGenerator::isSpecialStreamingOperator(fun)) - writeStreamingOperatorCall(stream, fun, meta_class, indent); - else - writeFunctionCallAndReturn(stream, fun, i, meta_class, indent); - signatures.insert(fun->targetLangSignature()); - } else { - // handle overloads - QStringList sigs; - for (int j = 0; j < funcs.size(); ++j) { - AbstractMetaFunction *fun = funcs.at(j); - sigs.append(fun->signature()); - stream << " "; - if (j > 0) - stream << "} else "; - stream << "if ("; - AbstractMetaArgumentList arguments = fun->arguments(); - const int indent = 12; - writeArgumentTypeTests(stream, fun, arguments, i, indent); - stream << ") {" << endl; - writeFunctionCallAndReturn(stream, fun, i, meta_class, indent); - signatures.insert(fun->targetLangSignature()); - } - stream << " }" << endl; - } - stream << " }" << endl; - } -} - -static void writePrototypeCall(QTextStream &s, const AbstractMetaClass *meta_class, - const QMap &nameToFunctions, - int prototypeFunctionsOffset) -{ - s << "static QScriptValue qtscript_" << meta_class->name() - << "_prototype_call(QScriptContext *context, QScriptEngine *)" << endl - << "{" << endl; - - s << "#if QT_VERSION > 0x040400" << endl; - - s << " Q_ASSERT(context->callee().isFunction());" << endl - << " uint _id = context->callee().data().toUInt32();" << endl; - - s << "#else" << endl - << " uint _id;" << endl - << " if (context->callee().isFunction())" << endl - << " _id = context->callee().data().toUInt32();" << endl - << " else" << endl - << " _id = 0xBABE0000 + " << nameToFunctions.size() << ";" << endl; - - s << "#endif" << endl; - - s << " Q_ASSERT((_id & 0xFFFF0000) == 0xBABE0000);" << endl - << " _id &= 0x0000FFFF;" << endl; - - // cast the thisObject to C++ type - s << " "; -#ifndef GENERATOR_NO_PROTECTED_FUNCTIONS - if (meta_class->hasProtectedFunctions()) - s << "qtscript_"; -#endif - s << meta_class->qualifiedCppName() << "* _q_self = "; -#ifndef GENERATOR_NO_PROTECTED_FUNCTIONS - if (meta_class->hasProtectedFunctions()) - s << "reinterpret_castname() << "*>("; -#endif - s << "qscriptvalue_cast<" << meta_class->qualifiedCppName() - << "*>(context->thisObject())"; -#ifndef GENERATOR_NO_PROTECTED_FUNCTIONS - if (meta_class->hasProtectedFunctions()) - s << ")"; -#endif - s << ";" << endl - << " if (!_q_self) {" << endl - << " return context->throwError(QScriptContext::TypeError," << endl - << " QString::fromLatin1(\"" << meta_class->name() - << ".%0(): this object is not a " << meta_class->name() << "\")" << endl - << " .arg(qtscript_" << meta_class->name() - << "_function_names[_id+" << prototypeFunctionsOffset <<"]));" << endl - << " }" << endl << endl; - - s << " switch (_id) {" << endl; - - QMap::const_iterator it; - int index = 0; - for (it = nameToFunctions.constBegin(); it != nameToFunctions.constEnd(); ++it) { - s << " case " << index << ":" << endl; - writeFunctionForwarding(s, meta_class, it.value()); - s << " break;" << endl << endl; - ++index; - } - - if (!meta_class->hasDefaultToStringFunction()) { - s << " case " << index << ": {" << endl; - s << " QString result"; - FunctionModelItem fun = meta_class->hasToStringCapability(); - if (fun) { - int indirections = fun->arguments().at(1)->type().indirections(); - QString deref = QLatin1String(indirections == 0 ? "*" : ""); - s << ";" << endl - << " QDebug d(&result);" << endl - << " d << " << deref << "_q_self;" << endl; - } else { - // ### FIXME: can cause compile error -// s << "=QString(\"" << meta_class->name() << "(0x%1)\").arg((int)_q_self, 0, 16);" << endl; - s << " = QString::fromLatin1(\"" << meta_class->name() << "\");" << endl; - } - s << " return QScriptValue(context->engine(), result);" << endl - << " }" << endl << endl; - } - - s << " default:" << endl - << " Q_ASSERT(false);" << endl - << " }" << endl; - - s << " return qtscript_" << meta_class->name() << "_throw_ambiguity_error_helper(context," << endl - << " qtscript_" << meta_class->name() - << "_function_names[_id+" << prototypeFunctionsOffset << "]," << endl - << " qtscript_" << meta_class->name() - << "_function_signatures[_id+" << prototypeFunctionsOffset << "]);" << endl; - - s << "}" << endl << endl; -} - -static void writeStaticCall(QTextStream &s, const AbstractMetaClass *meta_class, - const AbstractMetaFunctionList &constructors, - const QMap &nameToFunctions) -{ - s << "static QScriptValue qtscript_" << meta_class->name() - << "_static_call(QScriptContext *context, QScriptEngine *)" << endl - << "{" << endl; - - s << " uint _id = context->callee().data().toUInt32();" << endl - << " Q_ASSERT((_id & 0xFFFF0000) == 0xBABE0000);" << endl - << " _id &= 0x0000FFFF;" << endl; - - s << " switch (_id) {" << endl; - - s << " case 0:" << endl; - writeConstructorForwarding(s, constructors, meta_class); - s << " break;" << endl << endl; - - QMap::const_iterator it; - int index = 1; - for (it = nameToFunctions.constBegin(); it != nameToFunctions.constEnd(); ++it) { - s << " case " << index << ":" << endl; - writeFunctionForwarding(s, meta_class, it.value()); - s << " break;" << endl << endl; - ++index; - } - - s << " default:" << endl - << " Q_ASSERT(false);" << endl - << " }" << endl; - - s << " return qtscript_" << meta_class->name() << "_throw_ambiguity_error_helper(context," << endl - << " qtscript_" << meta_class->name() << "_function_names[_id]," << endl - << " qtscript_" << meta_class->name() << "_function_signatures[_id]);" << endl; - - s << "}" << endl << endl; -} - -/*! - Writes the include defined by \a inc to \a stream. -*/ -void ClassGenerator::writeInclude(QTextStream &stream, const Include &inc) -{ - if (inc.name.isEmpty()) - return; - if (inc.type == Include::TargetLangImport) - return; - stream << "#include "; - if (inc.type == Include::IncludePath) - stream << "<"; - else - stream << "\""; - stream << inc.name; - if (inc.type == Include::IncludePath) - stream << ">"; - else - stream << "\""; - stream << endl; -} - -static void writeHelperFunctions(QTextStream &stream, const AbstractMetaClass *meta_class) -{ - stream << "static QScriptValue qtscript_" << meta_class->name() << "_throw_ambiguity_error_helper(" << endl - << " QScriptContext *context, const char *functionName, const char *signatures)" << endl - << "{" << endl - << " QStringList lines = QString::fromLatin1(signatures).split(QLatin1Char('\\n'));" << endl - << " QStringList fullSignatures;" << endl - << " for (int i = 0; i < lines.size(); ++i)" << endl - << " fullSignatures.append(QString::fromLatin1(\"%0(%1)\").arg(functionName).arg(lines.at(i)));" << endl - << " return context->throwError(QString::fromLatin1(\"" << meta_class->name() - << "::%0(): could not find a function match; candidates are:\\n%1\")" << endl - << " .arg(functionName).arg(fullSignatures.join(QLatin1String(\"\\n\"))));" << endl - << "}" << endl << endl; -} - - -/*! - Finds the functions in \a meta_class that we actually want to - generate bindings for. -*/ -void findPrototypeAndStaticFunctions( - const AbstractMetaClass *meta_class, - QMap &nameToPrototypeFunctions, - QMap &nameToStaticFunctions) -{ - AbstractMetaFunctionList functions = meta_class->functionsInTargetLang(); - for (int i = 0; i < functions.size(); ++i) { - AbstractMetaFunction* func = functions.at(i); - if (!func->isNormal()) - continue; -#ifdef GENERATOR_NO_PROTECTED_FUNCTIONS - if (func->wasProtected()) - continue; -#endif - if (func->declaringClass() != meta_class) - continue; // function inherited through prototype - if (func->isPropertyReader() || func->isPropertyWriter()) - continue; // no point in including property accessors - if (func->isSlot() || func->isSignal() || func->isInvokable()) - continue; // no point in including signals and slots - QMap &map = - func->isStatic() ? nameToStaticFunctions : nameToPrototypeFunctions; - map[func->modifiedName()].append(func); - } -} - -static void writeFunctionSignaturesString(QTextStream &s, const AbstractMetaFunctionList &functions) -{ - s << "\""; - for (int i = 0; i < functions.size(); ++i) { - if (i > 0) - s << "\\n"; - QString sig = functions.at(i)->targetLangSignature(); - sig = sig.mid(sig.indexOf('(') + 1); - sig.chop(1); - s << sig; - } - s << "\""; -} - -/*! - Writes the whole native binding for the class \a meta_class. -*/ -void ClassGenerator::write(QTextStream &stream, const AbstractMetaClass *meta_class) -{ - // write common includes - stream << "#include " << endl; - stream << "#include " << endl; - stream << "#include " << endl; - stream << "#include " << endl; - stream << "#include " << endl; - stream << "#include " << endl; - stream << endl; - - // write class-specific includes - { - Include inc = meta_class->typeEntry()->include(); - writeInclude(stream, inc); - } - { - IncludeList includes = meta_class->typeEntry()->extraIncludes(); - qSort(includes.begin(), includes.end()); - - foreach (const Include &i, includes) { - writeInclude(stream, i); - } - } - stream << endl; - - if (meta_class->generateShellClass()) { - stream << "#include \"qtscriptshell_" << meta_class->name() << ".h\"" << endl; - stream << endl; - } - - AbstractMetaEnumList enums = meta_class->enums(); - { - // kill the enums we don't care about - AbstractMetaEnumList::iterator it; - for (it = enums.begin(); it != enums.end(); ) { - if (shouldIgnoreEnum(*it)) - it = enums.erase(it); - else - ++it; - } - } - - if (meta_class->isNamespace() || meta_class->name() == "Global") { - QMap includes; - foreach (AbstractMetaEnum *enom, enums) { - Include include = enom->typeEntry()->include(); - includes.insert(include.toString(), include); - } - - foreach (const Include &i, includes) { - writeInclude(stream, i); - } - - stream << endl; - } - - if (meta_class->name() == "Global") { - stream << "class Global {};" << endl; - stream << endl; - } - - // find constructors - AbstractMetaFunctionList ctors = findConstructors(meta_class); - bool hasDefaultCtor = findDefaultConstructor(ctors) != 0; - - // find interesting functions - QMap nameToPrototypeFunctions; - QMap nameToStaticFunctions; - findPrototypeAndStaticFunctions(meta_class, nameToPrototypeFunctions, nameToStaticFunctions); - - int staticFunctionsOffset = 1; - int prototypeFunctionsOffset = staticFunctionsOffset + nameToStaticFunctions.size(); - - // write table of function names - stream << "static const char * const qtscript_" - << meta_class->name() << "_function_names[] = {" << endl; - stream << " \"" << meta_class->name() << "\"" << endl; - { - QMap::const_iterator it; - stream << " // static" << endl; - for (it = nameToStaticFunctions.constBegin(); it != nameToStaticFunctions.constEnd(); ++it) { - stream << " , "; - stream << "\"" << it.key() << "\"" << endl; - } - stream << " // prototype" << endl; - for (it = nameToPrototypeFunctions.constBegin(); it != nameToPrototypeFunctions.constEnd(); ++it) { - QString functionName = it.key(); - QString scriptName = functionName; - if (functionName == QLatin1String("operator_equal")) - scriptName = QLatin1String("equals"); - stream << " , "; - stream << "\"" << scriptName << "\"" << endl; - } - if (!meta_class->hasDefaultToStringFunction()) - stream << " , \"toString\"" << endl; - } - stream << "};" << endl << endl; - - // write table of function signatures - stream << "static const char * const qtscript_" - << meta_class->name() << "_function_signatures[] = {" << endl; - stream << " "; - writeFunctionSignaturesString(stream, ctors); - stream << endl; - { - QMap::const_iterator it; - stream << " // static" << endl; - for (it = nameToStaticFunctions.constBegin(); it != nameToStaticFunctions.constEnd(); ++it) { - stream << " , "; - writeFunctionSignaturesString(stream, it.value()); - stream << endl; - } - stream << " // prototype" << endl; - for (it = nameToPrototypeFunctions.constBegin(); it != nameToPrototypeFunctions.constEnd(); ++it) { - stream << " , "; - writeFunctionSignaturesString(stream, it.value()); - stream << endl; - } - if (!meta_class->hasDefaultToStringFunction()) - stream << "\"\"" << endl; - } - stream << "};" << endl << endl; - - // write table of function lengths - stream << "static const int qtscript_" << meta_class->name() << "_function_lengths[] = {" << endl; - stream << " " << maxFunctionLength(ctors) << endl; - { - QMap::const_iterator it; - stream << " // static" << endl; - for (it = nameToStaticFunctions.constBegin(); it != nameToStaticFunctions.constEnd(); ++it) { - stream << " , " << maxFunctionLength(it.value()) << endl; - } - stream << " // prototype" << endl; - for (it = nameToPrototypeFunctions.constBegin(); it != nameToPrototypeFunctions.constEnd(); ++it) { - stream << " , " << maxFunctionLength(it.value()) << endl; - } - if (!meta_class->hasDefaultToStringFunction()) - stream << " , 0" << endl; - } - stream << "};" << endl << endl; - -#ifndef GENERATOR_NO_PROTECTED_FUNCTIONS - if (meta_class->hasProtectedFunctions()) { - // write a friendly class - stream << "class qtscript_" << meta_class->name() - << " : public " << meta_class->qualifiedCppName() << endl; - stream << "{" << endl; - for (int x = 0; x < 2; ++x) { - QMap &map = - x ? nameToStaticFunctions : nameToPrototypeFunctions; - QMap::const_iterator it; - for (it = map.constBegin(); it != map.constEnd(); ++it) { - AbstractMetaFunctionList functions = it.value(); - for (int i = 0; i < functions.size(); ++i) { - if (functions.at(i)->isProtected()) { - stream << " friend QScriptValue qtscript_" << meta_class->name() - << "_" << it.key(); - if (functions.at(i)->isStatic()) - stream << "_static"; - stream << "(QScriptContext *, QScriptEngine *);" << endl; - break; - } - } - } - } - stream << "};" << endl; - stream << endl; - } -#endif - - writeHelperFunctions(stream, meta_class); - - // write metaobject getter if we need it - if (hasQEnums(enums) && (meta_class->qualifiedCppName() != "QTransform")) { - if (meta_class->qualifiedCppName() == "Qt") { - stream << "struct qtscript_Qt_metaObject_helper : private QObject" << endl - << "{" << endl - << " static const QMetaObject *get()" << endl - << " { return &static_cast(0)->staticQtMetaObject; }" << endl - << "};" << endl << endl; - } - stream << "static const QMetaObject *qtscript_" << meta_class->name() << "_metaObject()" << endl - << "{" << endl - << " return "; - if (meta_class->qualifiedCppName() == "Qt") - stream << "qtscript_Qt_metaObject_helper::get()"; - else - stream << "&" << meta_class->qualifiedCppName() << "::staticMetaObject"; - stream << ";" << endl - << "}" << endl << endl; - } - - // write metatype declarations - { - QSet registeredTypeNames = m_qmetatype_declared_typenames; - - if (!meta_class->isNamespace()) { - if (meta_class->typeEntry()->isValue() && hasDefaultCtor) - maybeDeclareMetaType(stream, meta_class->qualifiedCppName(), registeredTypeNames); - else - registeredTypeNames << meta_class->qualifiedCppName(); - maybeDeclareMetaType(stream, meta_class->qualifiedCppName() + "*", registeredTypeNames); - } - if (meta_class->generateShellClass()) { - if (meta_class->typeEntry()->isValue()) { - maybeDeclareMetaType(stream, "QtScriptShell_" + meta_class->name(), - registeredTypeNames); - } - maybeDeclareMetaType(stream, "QtScriptShell_" + meta_class->name() + "*", - registeredTypeNames); - } - - declareEnumMetaTypes(stream, meta_class, registeredTypeNames); - - for (int x = 0; x < 2; ++x) { - QMap &map = - x ? nameToStaticFunctions : nameToPrototypeFunctions; - QMap::const_iterator it; - for (it = map.constBegin(); it != map.constEnd(); ++it) { - declareFunctionMetaTypes(stream, it.value(), registeredTypeNames); - } - } - - declareFunctionMetaTypes(stream, ctors, registeredTypeNames); - - if (meta_class->baseClass() != 0) { - maybeDeclareMetaType(stream, meta_class->baseClass()->qualifiedCppName() - + QLatin1String("*"), registeredTypeNames); - } - foreach (AbstractMetaClass *iface, meta_class->interfaces()) { - AbstractMetaClass *impl = iface->primaryInterfaceImplementor(); - maybeDeclareMetaType(stream, impl->qualifiedCppName() + QLatin1String("*"), - registeredTypeNames); - } - - // ### hackety hack - if (meta_class->name().endsWith("Gradient")) - maybeDeclareMetaType(stream, "QGradient", registeredTypeNames); - - stream << endl; - } - - writeInjectedCode(stream, meta_class, CodeSnip::Beginning); - - // write enum classes - if (!enums.isEmpty()) { - writeCreateEnumClassHelper(stream); - if (hasFlags(enums)) - writeCreateFlagsClassHelper(stream); - - for (int i = 0; i < enums.size(); ++i) { - const AbstractMetaEnum *enom = enums.at(i); - writeEnumClass(stream, meta_class, enom); - } - } - - stream << "//" << endl; - stream << "// " << meta_class->name() << endl; - stream << "//" << endl << endl; - - if (!meta_class->isNamespace()) { - if (!nameToPrototypeFunctions.isEmpty() || !meta_class->hasDefaultToStringFunction()) - writePrototypeCall(stream, meta_class, nameToPrototypeFunctions, prototypeFunctionsOffset); - } - - writeStaticCall(stream, meta_class, ctors, nameToStaticFunctions); - - if (isQObjectBased(meta_class)) { - // write C++ <--> script conversion functions - stream << "static QScriptValue qtscript_" << meta_class->name() << "_toScriptValue(QScriptEngine *engine, " - << meta_class->qualifiedCppName() << "* const &in)" << endl - << "{" << endl - << " return engine->newQObject(in, QScriptEngine::QtOwnership, QScriptEngine::PreferExistingWrapperObject);" << endl - << "}" << endl << endl; - stream << "static void qtscript_" << meta_class->name() << "_fromScriptValue(const QScriptValue &value, " - << meta_class->qualifiedCppName() << "* &out)" << endl - << "{" << endl - << " out = qobject_cast<" << meta_class->qualifiedCppName() << "*>(value.toQObject());" << endl - << "}" << endl << endl; - } - - // - // write exported function that creates the QtScript class - // - stream << "QScriptValue qtscript_create_" << meta_class->name() - << "_class(QScriptEngine *engine)" << endl; - stream << "{" << endl; - - // setup prototype - if (!meta_class->isNamespace()) { - stream << " engine->setDefaultPrototype(qMetaTypeId<" - << meta_class->qualifiedCppName() << "*>(), QScriptValue());" << endl; - stream << " QScriptValue proto = engine->newVariant(qVariantFromValue((" - << meta_class->qualifiedCppName() << "*)0));" << endl; - bool havePrototypePrototype = false; - if (meta_class->baseClass() != 0) { - stream << " proto.setPrototype(engine->defaultPrototype(qMetaTypeId<" - << meta_class->baseClass()->qualifiedCppName() << "*>()));" << endl; - havePrototypePrototype = true; - } - foreach (AbstractMetaClass *iface, meta_class->interfaces()) { - AbstractMetaClass *impl = iface->primaryInterfaceImplementor(); - if (impl == meta_class) - continue; - if (!havePrototypePrototype) { - stream << " proto.setPrototype(engine->defaultPrototype(qMetaTypeId<" - << impl->qualifiedCppName() << "*>()));" << endl; - havePrototypePrototype = true; - } else { - // alternative would be to copy the properties from the secondary - // prototype to the primary prototype. - stream << " proto.setProperty(QString::fromLatin1(\"__" - << impl->name() << "__\")," << endl - << " engine->defaultPrototype(qMetaTypeId<" - << impl->qualifiedCppName() << "*>())," << endl - << " QScriptValue::SkipInEnumeration);" << endl; - } - } - if (!nameToPrototypeFunctions.isEmpty()) { - QMap::const_iterator it; - int count = nameToPrototypeFunctions.size(); - if (!meta_class->hasDefaultToStringFunction()) - ++count; - stream << " for (int i = 0; i < " << count << "; ++i) {" << endl - << " QScriptValue fun = engine->newFunction(qtscript_" - << meta_class->name() << "_prototype_call, qtscript_" - << meta_class->name() << "_function_lengths[i+" - << prototypeFunctionsOffset << "]);" << endl - << " fun.setData(QScriptValue(engine, uint(0xBABE0000 + i)));" << endl - << " proto.setProperty(QString::fromLatin1(qtscript_" - << meta_class->name() << "_function_names[i+" << prototypeFunctionsOffset << "])," << endl - << " fun, QScriptValue::SkipInEnumeration);" << endl - << " }" << endl; - } - writeInjectedCode(stream, meta_class, CodeSnip::PrototypeInitialization); - stream << endl; - - // register the prototype -// stream << " qDebug() << \"registering " << meta_class->name() << " prototype\";" << endl; - if (meta_class->typeEntry()->isValue() && hasDefaultCtor) { - stream << " engine->setDefaultPrototype(qMetaTypeId<" - << meta_class->qualifiedCppName() << ">(), proto);" << endl; - } - if (isQObjectBased(meta_class)) { - stream << " qScriptRegisterMetaType<" << meta_class->qualifiedCppName() << "*>(engine, qtscript_" - << meta_class->name() << "_toScriptValue, " << endl << " qtscript_" - << meta_class->name() << "_fromScriptValue, proto);" << endl; - } else { - stream << " engine->setDefaultPrototype(qMetaTypeId<" - << meta_class->qualifiedCppName() << "*>(), proto);" << endl; - } - stream << endl; - } else { - stream << " QScriptValue proto = QScriptValue();" << endl; - } - - // setup constructor - stream << " QScriptValue ctor = engine->newFunction(qtscript_" << meta_class->name() - << "_static_call, proto, qtscript_" << meta_class->name() << "_function_lengths[0]);" << endl; - stream << " ctor.setData(QScriptValue(engine, uint(0xBABE0000 + 0)));" << endl; - if (!nameToStaticFunctions.isEmpty()) { - // static functions - QMap::const_iterator it; - stream << " for (int i = 0; i < " << nameToStaticFunctions.size() << "; ++i) {" << endl - << " QScriptValue fun = engine->newFunction(qtscript_" << meta_class->name() - << "_static_call," << endl - << " qtscript_" << meta_class->name() << "_function_lengths[i+" << staticFunctionsOffset << "]);" << endl - << " fun.setData(QScriptValue(engine, uint(0xBABE0000 + i+1)));" << endl - << " ctor.setProperty(QString::fromLatin1(qtscript_" - << meta_class->name() << "_function_names[i+" << staticFunctionsOffset << "])," << endl - << " fun, QScriptValue::SkipInEnumeration);" << endl - << " }" << endl; - } - stream << endl; - // enums and flags classes - { - for (int i = 0; i < enums.size(); ++i) { - const AbstractMetaEnum *enom = enums.at(i); - stream << " ctor.setProperty(QString::fromLatin1(\"" - << enom->name() << "\")," << endl - << " qtscript_create_" << meta_class->name() - << "_" << enom->name() << "_class(engine, ctor));" << endl; - FlagsTypeEntry *flags = enom->typeEntry()->flags(); - if (flags) { - stream << " ctor.setProperty(QString::fromLatin1(\"" - << flags->targetLangName() << "\")," << endl - << " qtscript_create_" << meta_class->name() - << "_" << flags->targetLangName() << "_class(engine));" << endl; - } - } - } - - writeInjectedCode(stream, meta_class, CodeSnip::ConstructorInitialization); - - stream << " return ctor;" << endl; - stream << "}" << endl; - - writeInjectedCode(stream, meta_class, CodeSnip::End); - - QString packName = meta_class->package().replace(".", "_"); - priGenerator->addSource(packName, fileNameForClass(meta_class)); - setupGenerator->addClass(meta_class); -} diff --git a/generator/classgenerator.h b/generator/classgenerator.h deleted file mode 100644 index 51bfe78..0000000 --- a/generator/classgenerator.h +++ /dev/null @@ -1,75 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Script Generator project on Qt Labs. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef CLASS_GENERATOR -#define CLASS_GENERATOR - -#include "generator.h" -#include "metaqtscript.h" -#include "prigenerator.h" -#include "setupgenerator.h" - -class ClassGenerator : public Generator -{ - Q_OBJECT - - public: - ClassGenerator(PriGenerator *pri, SetupGenerator *setup); - - virtual QString fileNameForClass(const AbstractMetaClass *meta_class) const; - virtual QString subDirectoryForClass(const AbstractMetaClass *cls) const - { - return "generated_cpp/" + cls->package().replace(".", "_") + "/"; - } - virtual bool shouldGenerate(const AbstractMetaClass *meta_class) const; - void write(QTextStream &s, const AbstractMetaClass *meta_class); - - static void writeInclude(QTextStream &stream, const Include &inc); - - static bool isSpecialStreamingOperator(const AbstractMetaFunction *fun); - - private: - PriGenerator *priGenerator; - SetupGenerator *setupGenerator; - QStringList describeFunctons; -}; - -#endif // CLASS_GENERATOR diff --git a/generator/docgenerator.cpp b/generator/docgenerator.cpp deleted file mode 100644 index aa8b842..0000000 --- a/generator/docgenerator.cpp +++ /dev/null @@ -1,347 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Script Generator project on Qt Labs. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "docgenerator.h" -#include "fileout.h" - -DocGenerator::DocGenerator() -{ -} - -QString DocGenerator::fileNameForClass(const AbstractMetaClass *meta_class) const -{ - return QString::fromLatin1("%0.html").arg(meta_class->name().toLower()); -} - -QString DocGenerator::subDirectoryForClass(const AbstractMetaClass *) const -{ - return QString::fromLatin1("doc"); -} - -static void writeDocumentHeader(QTextStream &s, const QString &title) -{ - s << "" << endl - << "" << endl - << "" << endl - << "" << endl - << " " << title << "" << endl - << " " << endl - << "" << endl - << "" << endl; -} - -static void writeDocumentFooter(QTextStream &s) -{ - s << "" << endl - << "" << endl; -} - -static bool classLessThan(const AbstractMetaClass *c1, const AbstractMetaClass *c2) -{ - return c1->name() < c2->name(); -} - -bool DocGenerator::shouldGenerate(const AbstractMetaClass *meta_class) const -{ - uint cg = meta_class->typeEntry()->codeGeneration(); - return (cg & TypeEntry::GenerateCode) != 0; -} - -void DocGenerator::generate() -{ - Generator::generate(); - - QHash > packHash; - for (int i = 0; i < m_classes.size(); ++i) { - const AbstractMetaClass *cls = m_classes.at(i); - packHash[cls->package()].append(cls); - } - - // package pages - QHash >::const_iterator it; - for (it = packHash.constBegin(); it != packHash.constEnd(); ++it) { - QString package = it.key(); - QList classesInPackage = it.value(); - qSort(classesInPackage.begin(), classesInPackage.end(), classLessThan); - - FileOut file(m_out_dir + "/doc/" + package.split(".").join("_") + ".html"); - - writeDocumentHeader(file.stream, package + " Package"); - - file.stream << "

" << package << " Package

" << endl; - - file.stream << "

Classes

" << endl - << "

" << endl; - - for (int i = 0; i < classesInPackage.size(); ++i) { - const AbstractMetaClass *cls = classesInPackage.at(i); - if (cls->name() == "Global") - continue; /// ### fixme - file.stream << "" << endl; - } - - file.stream << "
" << cls->name() - << "

" << endl; - - writeDocumentFooter(file.stream); - } - - // all classes page - { - FileOut file(m_out_dir + "/doc/classes.html"); - - writeDocumentHeader(file.stream, "Classes"); - - file.stream << "

Classes

" << endl - << "

" << endl; - - AbstractMetaClassList sortedClasses = m_classes; - qSort(sortedClasses.begin(), sortedClasses.end(), classLessThan); - - for (int i = 0; i < sortedClasses.size(); ++i) { - const AbstractMetaClass *cls = sortedClasses.at(i); - if (cls->name() == "Global") - continue; /// ### fixme - file.stream << "" << endl; - } - - file.stream << "
" << cls->name() - << "

" << endl; - - writeDocumentFooter(file.stream); - } - - // index.html - { - FileOut file(m_out_dir + "/doc/index.html"); - - writeDocumentHeader(file.stream, "Qt Bindings Reference Documentation"); - - file.stream << "

Qt Script Qt Bindings Reference Documentation

" << endl; - - file.stream << "

Packages

" << endl; - file.stream << "
    " << endl; - QStringList sortedPackages = packHash.keys(); - qSort(sortedPackages.begin(), sortedPackages.end()); - for (int i = 0; i < sortedPackages.size(); ++i) { - QString pkg = sortedPackages.at(i); - file.stream << "
  • " - << pkg << "
  • " << endl; - } - file.stream << "
" << endl; - - file.stream << "

All Classes

" << endl; - - file.stream << "

Examples

" << endl; - - file.stream << "

Getting Started

" << endl - << "

Using the Qt API in Qt Script is very similar to C++." << endl - << "

var f = new QFile(\"foo.txt\");
" << endl - << "C++ enum values are mapped to properties of the script constructor function; e.g. " << endl - << "QIODevice::ReadOnly becomes QIODevice.ReadOnly.

" << endl - << "
f.open(new QIODevice.OpenMode(QIODevice.ReadOnly));
" << endl - << "

Each C++ flag type is mapped to a property of the script constructor function; e.g. " << endl - << "QIODevice::OpenMode becomes QIODevice.OpenMode. Such a property is a constructor function " << endl - << "that takes one or more enum values and constructs a flags instance by OR'ing the arguments " << endl - << "together.

" << endl - << "
var ts = new QTextStream(f);" << endl
-                    << "ts.writeString(\"Boo\");
" << endl - << "

C++ streaming operators are normally mapped to readT() and writeT() functions.

" << endl - << "
f.close();
" << endl - << "

In Qt Script, all objects are allocated on the heap; objects that are no longer " << endl - << "referenced are garbage collected sometime in the future; therefore, make sure to " << endl - << "explicitly free up resources if you can. (Without the call to close(), the underlying " << endl - << "file would remain open until the file object is garbage collected.)

" << endl - ; - - file.stream << "

Qt Reference Documentation

" << endl; - - writeDocumentFooter(file.stream); - } -} - -static bool shouldIgnoreEnum(const AbstractMetaEnum *enom) -{ - return !enom->wasPublic() || (enom->name() == "enum_1"); -} - -// in classgenerator.cpp -void findPrototypeAndStaticFunctions( - const AbstractMetaClass *meta_class, - QMap &nameToPrototypeFunctions, - QMap &nameToStaticFunctions); -QList uniqueEnumValueIndexes(const AbstractMetaEnumValueList &values); - -static void writeFunction(QTextStream &s, const AbstractMetaFunction *fun) -{ - s << "
  • " << fun->targetLangSignature() << "
  • " << endl; -} - -void DocGenerator::write(QTextStream &s, const AbstractMetaClass *meta_class) -{ - QString title = meta_class->name(); - title.append(" "); - if (meta_class->isNamespace()) - title.append("Namespace"); - else - title.append("Class"); - title.append(" Reference"); - writeDocumentHeader(s, title); - - s << "

    " << title << "

    " << endl; - - s << "

    [package().split(".").join("_") << ".html"; - s << "\">"; - s << meta_class->package(); - s << " package]

    " << endl; - - if (meta_class->baseClass()) { - s << "

    Inherits baseClass()) << "\">" - << meta_class->baseClass()->name() << ".

    " << endl; - } else if (!meta_class->interfaces().isEmpty()) { - AbstractMetaClass *iface = meta_class->interfaces().first(); - AbstractMetaClass *impl = iface->primaryInterfaceImplementor(); - if (impl != meta_class) { - s << "

    Inherits " - << impl->name() << ".

    " << endl; - } - } - - AbstractMetaFunctionList ctors; - ctors = meta_class->queryFunctions(AbstractMetaClass::Constructors - | AbstractMetaClass::WasPublic - | AbstractMetaClass::NotRemovedFromTargetLang); - QMap nameToPrototypeFunctions; - QMap nameToStaticFunctions; - findPrototypeAndStaticFunctions(meta_class, nameToPrototypeFunctions, nameToStaticFunctions); - - s << "

    Constructor

    " << endl; - if (!ctors.isEmpty()) { - s << "
      " << endl; - for (int i = 0; i < ctors.size(); ++i) { - writeFunction(s, ctors.at(i)); - } - s << "
    " << endl; - } else { - s << "

    This class has no public constructors. Calling the constructor function will cause a TypeError.

    "; - } - - s << "

    Constructor Properties

    " << endl; - s << "
      " << endl; - s << "
    • prototype: The " << meta_class->name() << " prototype object
    • " << endl; - if (!nameToStaticFunctions.isEmpty()) { - QMap::const_iterator it; - for (it = nameToStaticFunctions.constBegin(); it != nameToStaticFunctions.constEnd(); ++it) { - writeFunction(s, it.value().first()); - } - } - { - AbstractMetaEnumList enums = meta_class->enums(); - for (int i = 0; i < enums.size(); ++i) { - const AbstractMetaEnum *enom = enums.at(i); - if (shouldIgnoreEnum(enom)) - continue; - AbstractMetaEnumValueList values = enom->values(); - QList indexes = uniqueEnumValueIndexes(values); - for (int j = 0; j < indexes.size(); ++j) { - AbstractMetaEnumValue *val = values.at(indexes.at(j)); - s << "
    • " << val->name(); - if (!val->stringValue().isEmpty()) - s << " = " << val->stringValue(); - s << "
    • " << endl; - } - s << "
    • " << enom->name() << "( value )
    • " << endl; - FlagsTypeEntry *flags = enom->typeEntry()->flags(); - if (flags) - s << "
    • " << flags->flagsName() << "( value1, value2, ... )
    • " << endl; - } - } - s << "
    " << endl; - - if (!nameToPrototypeFunctions.isEmpty()) { - s << "

    Prototype Object Properties

    " << endl; - if (meta_class->baseClass()) { - s << "

    The " << meta_class->name() << " prototype object inherits properties from the " - << "baseClass()) << "\">" - << meta_class->baseClass()->name() << " prototype object and " - << "also has the following properties.

    " << endl; - } - s << "
      " << endl; - QMap::const_iterator it; - for (it = nameToPrototypeFunctions.constBegin(); it != nameToPrototypeFunctions.constEnd(); ++it) { - writeFunction(s, it.value().first()); - } - s << "
    " << endl; - } - - if (!meta_class->isNamespace()) { - s << "

    Instance Properties

    " << endl; - { - QList props = meta_class->propertySpecs(); - if (!props.isEmpty()) { - s << "

    " << meta_class->name() << " objects inherit properties from the " - << meta_class->name() << " prototype object and also have the following properties.

    " << endl; - s << "
      " << endl; - for (int i = 0; i < props.size(); ++i) { - s << "
    • " << props.at(i)->name() << "
    • " << endl; - } - s << "
    " << endl; - } else { - s << "

    " << meta_class->name() << " objects have no special properties beyond those " - << "inherited from the " << meta_class->name() << " prototype object.

    " << endl; - } - } - } - - writeDocumentFooter(s); -} diff --git a/generator/docgenerator.h b/generator/docgenerator.h deleted file mode 100644 index f36ef43..0000000 --- a/generator/docgenerator.h +++ /dev/null @@ -1,59 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Script Generator project on Qt Labs. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef DOCGENERATOR_H -#define DOCGENERATOR_H - -#include "generator.h" - -class DocGenerator : public Generator -{ -public: - DocGenerator(); - - virtual bool shouldGenerate(const AbstractMetaClass *meta_class) const; - virtual void generate(); - virtual QString fileNameForClass(const AbstractMetaClass *meta_class) const; - virtual QString subDirectoryForClass(const AbstractMetaClass *cls) const; - virtual void write(QTextStream &s, const AbstractMetaClass *meta_class); -}; - -#endif diff --git a/generator/generator.pro b/generator/generator.pro index 0671164..9e2ae50 100644 --- a/generator/generator.pro +++ b/generator/generator.pro @@ -11,20 +11,16 @@ HEADERS += \ generatorsetqtscript.h \ metaqtscriptbuilder.h \ metaqtscript.h \ - classgenerator.h \ shellgenerator.h \ shellimplgenerator.h \ shellheadergenerator.h \ - setupgenerator.h \ - docgenerator.h + setupgenerator.h SOURCES += \ generatorsetqtscript.cpp \ metaqtscriptbuilder.cpp \ metaqtscript.cpp \ - classgenerator.cpp \ shellgenerator.cpp \ shellimplgenerator.cpp \ shellheadergenerator.cpp \ - setupgenerator.cpp \ - docgenerator.cpp + setupgenerator.cpp diff --git a/generator/generatorsetqtscript.cpp b/generator/generatorsetqtscript.cpp index 52b8f2c..abedf34 100644 --- a/generator/generatorsetqtscript.cpp +++ b/generator/generatorsetqtscript.cpp @@ -41,10 +41,8 @@ #include "generatorsetqtscript.h" #include "reporthandler.h" -#include "classgenerator.h" #include "shellheadergenerator.h" #include "shellimplgenerator.h" -#include "docgenerator.h" GeneratorSet *GeneratorSet::getInstance() { return new GeneratorSetQtScript(); @@ -88,13 +86,6 @@ QString GeneratorSetQtScript::generate() { setupGenerator.setQtMetaTypeDeclaredTypeNames(declaredTypeNames); setupGenerator.setClasses(classes); - /* - ClassGenerator classGenerator(&priGenerator, &setupGenerator); - classGenerator.setOutputDirectory(outDir); - classGenerator.setClasses(classes); - classGenerator.setQtMetaTypeDeclaredTypeNames(declaredTypeNames); - classGenerator.generate(); -*/ ShellImplGenerator shellImplGenerator(&priGenerator); shellImplGenerator.setOutputDirectory(outDir); shellImplGenerator.setClasses(classes); @@ -106,11 +97,6 @@ QString GeneratorSetQtScript::generate() { shellHeaderGenerator.setClasses(classes); shellHeaderGenerator.generate(); - //DocGenerator docGenerator; - //docGenerator.setOutputDirectory(outDir); - //docGenerator.setClasses(classes); - //docGenerator.generate(); - priGenerator.generate(); setupGenerator.generate(); diff --git a/generator/prigenerator.cpp b/generator/prigenerator.cpp index a726227..a225602 100644 --- a/generator/prigenerator.cpp +++ b/generator/prigenerator.cpp @@ -91,6 +91,10 @@ static QStringList compactFiles(const QStringList& list, const QString& ext, con QStringList outList; int count = list.count(); int fileNum = 0; + QString srcDir = dir; + if (dir.endsWith("_builtin")) { + srcDir = dir.left(dir.length()-strlen("_builtin")); + } while (count>0) { QString outFileName = prefix + QString::number(fileNum) + ext; FileOut file(dir + "/" + outFileName); @@ -101,7 +105,7 @@ static QStringList compactFiles(const QStringList& list, const QString& ext, con QString allText; QTextStream ts(&allText); for (int i = 0; i0; i++) { - collectAndRemoveFile(ts, dir + "/" + list.at(list.length()-count)); + collectAndRemoveFile(ts, srcDir + "/" + list.at(list.length()-count)); count--; } allText = combineIncludes(allText); @@ -122,7 +126,8 @@ void PriGenerator::generate() QString folder = pri.key(); folder.replace('\\','/'); - folder = folder.left(folder.indexOf('/')); + int idx = folder.indexOf('/'); + folder = folder.left(idx); qSort(list.begin(), list.end()); FileOut file(m_out_dir + "/generated_cpp/" + pri.key()); diff --git a/generator/setupgenerator.cpp b/generator/setupgenerator.cpp index 49a14f4..875362c 100644 --- a/generator/setupgenerator.cpp +++ b/generator/setupgenerator.cpp @@ -46,9 +46,9 @@ //#define Q_SCRIPT_LAZY_GENERATOR -void SetupGenerator::addClass(const AbstractMetaClass *cls) +void SetupGenerator::addClass(const QString& package, const AbstractMetaClass *cls) { - packHash[cls->package()].append(cls); + packHash[package].append(cls); } void maybeDeclareMetaType(QTextStream &stream, const QString &typeName, @@ -80,15 +80,13 @@ void SetupGenerator::generate() QString packKey = pack.key(); QString packName = pack.key(); - QStringList components = packName.split("."); + QStringList components = packName.split("_"); if ((components.size() > 2) && (components.at(0) == "com") && (components.at(1) == "trolltech")) { // kill com.trolltech in key components.removeAt(0); components.removeAt(0); } - packName.replace(".", "_"); - packKey.replace(".", "_"); QString shortPackName; foreach (QString comp, components) { @@ -118,14 +116,21 @@ void SetupGenerator::generate() } s << endl; - QStringList polymorphicHandlers = writePolymorphicHandler(s, list.at(0)->package(), classes_with_polymorphic_id); - s << endl; - + QStringList polymorphicHandlers; + if (!packName.endsWith("_builtin")) { + polymorphicHandlers = writePolymorphicHandler(s, list.at(0)->package(), classes_with_polymorphic_id); + s << endl; + } + // declare individual class creation functions s << "void PythonQt_init_" << shortPackName << "() {" << endl; + + if (shortPackName.endsWith("Builtin")) { + shortPackName = shortPackName.mid(shortPackName.length()-strlen("builtin")); + } + QStringList cppClassNames; foreach (const AbstractMetaClass *cls, list) { - if (ShellGenerator::isBuiltIn(cls->name())) { continue; } QString shellCreator; if (cls->generateShellClass()) { diff --git a/generator/setupgenerator.h b/generator/setupgenerator.h index 7d57e0e..5c7eff2 100644 --- a/generator/setupgenerator.h +++ b/generator/setupgenerator.h @@ -52,7 +52,7 @@ class SetupGenerator : public Generator public: virtual void generate(); - void addClass(const AbstractMetaClass *cls); + void addClass(const QString& package, const AbstractMetaClass *cls); static void writeInclude(QTextStream &stream, const Include &inc); diff --git a/generator/shellgenerator.h b/generator/shellgenerator.h index 2fa67ca..49fa7ee 100644 --- a/generator/shellgenerator.h +++ b/generator/shellgenerator.h @@ -46,7 +46,7 @@ #include "metaqtscript.h" #include "prigenerator.h" -#define MAX_CLASSES_PER_FILE 20 +#define MAX_CLASSES_PER_FILE 30 class ShellGenerator : public Generator { diff --git a/generator/shellheadergenerator.cpp b/generator/shellheadergenerator.cpp index 3db4f4f..ef1fc5a 100644 --- a/generator/shellheadergenerator.cpp +++ b/generator/shellheadergenerator.cpp @@ -53,9 +53,10 @@ QString ShellHeaderGenerator::fileNameForClass(const AbstractMetaClass *meta_cla void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_class) { - if (!ShellGenerator::isBuiltIn(meta_class->name())) { - setupGenerator->addClass(meta_class); - } + QString builtIn = ShellGenerator::isBuiltIn(meta_class->name())?"_builtin":""; + QString pro_file_name = meta_class->package().replace(".", "_") + builtIn + "/" + meta_class->package().replace(".", "_") + builtIn + ".pri"; + priGenerator->addHeader(pro_file_name, fileNameForClass(meta_class)); + setupGenerator->addClass(meta_class->package().replace(".", "_") + builtIn, meta_class); QString include_block = "PYTHONQTWRAPPER_" + meta_class->name().toUpper() + "_H"; @@ -75,14 +76,6 @@ void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_c } s << endl; - QString pro_file_name = meta_class->package().replace(".", "_") + "/" + meta_class->package().replace(".", "_") + ".pri"; - - // if (!meta_class->generateShellClass()) { - // s << "#endif" << endl << endl; - // priGenerator->addHeader(pro_file_name, fileNameForClass(meta_class)); - // return ; - // } - AbstractMetaFunctionList ctors = meta_class->queryFunctions(AbstractMetaClass::Constructors | AbstractMetaClass::WasVisible | AbstractMetaClass::NotRemovedFromTargetLang); @@ -273,9 +266,6 @@ void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_c s << "};" << endl << endl << "#endif // " << include_block << endl; - if (!ShellGenerator::isBuiltIn(meta_class->name())) { - priGenerator->addHeader(pro_file_name, fileNameForClass(meta_class)); - } } void ShellHeaderGenerator::writeInjectedCode(QTextStream &s, const AbstractMetaClass *meta_class) diff --git a/generator/shellimplgenerator.cpp b/generator/shellimplgenerator.cpp index 88f71dc..d2d9158 100644 --- a/generator/shellimplgenerator.cpp +++ b/generator/shellimplgenerator.cpp @@ -63,12 +63,9 @@ static void writeHelperCode(QTextStream &s, const AbstractMetaClass *) void ShellImplGenerator::write(QTextStream &s, const AbstractMetaClass *meta_class) { - - QString pro_file_name = meta_class->package().replace(".", "_") + "/" + meta_class->package().replace(".", "_") + ".pri"; - - if (!ShellGenerator::isBuiltIn(meta_class->name())) { - priGenerator->addSource(pro_file_name, fileNameForClass(meta_class)); - } + QString builtIn = ShellGenerator::isBuiltIn(meta_class->name())?"_builtin":""; + QString pro_file_name = meta_class->package().replace(".", "_") + builtIn + "/" + meta_class->package().replace(".", "_") + builtIn + ".pri"; + priGenerator->addSource(pro_file_name, fileNameForClass(meta_class)); s << "#include \"PythonQtWrapper_" << meta_class->name() << ".h\"" << endl << endl;