Remove qmltc prototype code (2/N)
- Migrate to the newer output ir classes (with adjustments) - Deduplicate code writer and remove now-unused output helpers from the prototype version - Remove old output ir Change-Id: Ie7fe5e6d47e18477c65af02cabd89a890628442c Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
parent
3c680af4e9
commit
44b95b3fb2
|
@ -71,15 +71,15 @@ class HelloWorld : public QObject
|
|||
public:
|
||||
HelloWorld(QQmlEngine * engine, QObject * parent = nullptr);
|
||||
|
||||
Q_SIGNALS:
|
||||
void created();
|
||||
|
||||
public:
|
||||
void setHello(const QString& hello_);
|
||||
QString hello();
|
||||
QBindable<QString> bindableHello();
|
||||
Q_INVOKABLE void printHello(QString prefix, QString suffix);
|
||||
|
||||
signals:
|
||||
void created();
|
||||
|
||||
// ...
|
||||
};
|
||||
//! [qmltc-hello-world-generated]
|
||||
|
|
|
@ -14,13 +14,10 @@ qt_internal_add_tool(${target_name}
|
|||
qmltccompilerpieces.h
|
||||
qmltcpropertyutils.h
|
||||
|
||||
prototype/generatedcodeprimitives.h
|
||||
prototype/qml2cppcontext.h
|
||||
prototype/qml2cppdefaultpasses.cpp prototype/qml2cppdefaultpasses.h
|
||||
prototype/codegenerator.cpp prototype/codegenerator.h
|
||||
prototype/codegeneratorutil.cpp prototype/codegeneratorutil.h
|
||||
prototype/codegeneratorwriter.cpp prototype/codegeneratorwriter.h
|
||||
prototype/qmlcompiler.h
|
||||
DEFINES
|
||||
QT_NO_CAST_FROM_ASCII
|
||||
QT_NO_CAST_TO_ASCII
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include "prototype/qml2cppdefaultpasses.h"
|
||||
#include "prototype/qml2cpppropertyutils.h"
|
||||
#include "prototype/codegeneratorutil.h"
|
||||
#include "prototype/codegeneratorwriter.h"
|
||||
#include "qmltccodewriter.h"
|
||||
|
||||
#include "qmltccompiler.h"
|
||||
|
||||
|
@ -88,12 +88,12 @@ static QString figureReturnType(const QQmlJSMetaMethod &m)
|
|||
return type;
|
||||
}
|
||||
|
||||
static QList<QQmlJSAotVariable>
|
||||
static QList<QmltcVariable>
|
||||
compileMethodParameters(const QStringList &names,
|
||||
const QList<QSharedPointer<const QQmlJSScope>> &types,
|
||||
bool allowUnnamed = false)
|
||||
{
|
||||
QList<QQmlJSAotVariable> paramList;
|
||||
QList<QmltcVariable> paramList;
|
||||
const auto size = names.size();
|
||||
paramList.reserve(size);
|
||||
for (qsizetype i = 0; i < size; ++i) {
|
||||
|
@ -102,8 +102,7 @@ compileMethodParameters(const QStringList &names,
|
|||
Q_ASSERT(allowUnnamed || !name.isEmpty()); // assume verified
|
||||
if (name.isEmpty() && allowUnnamed)
|
||||
name = u"unnamed_" + QString::number(i);
|
||||
paramList.emplaceBack(
|
||||
QQmlJSAotVariable { types[i]->augmentedInternalName(), name, QString() });
|
||||
paramList.emplaceBack(QmltcVariable { types[i]->augmentedInternalName(), name, QString() });
|
||||
}
|
||||
return paramList;
|
||||
}
|
||||
|
@ -295,7 +294,6 @@ void CodeGenerator::constructObjects(QSet<QString> &requiredCppIncludes)
|
|||
|
||||
void CodeGenerator::generate()
|
||||
{
|
||||
GeneratedCode code;
|
||||
const QString rootClassName = QFileInfo(m_url).baseName();
|
||||
Q_ASSERT(!rootClassName.isEmpty());
|
||||
const QString hPath = m_info->outputHFile;
|
||||
|
@ -323,16 +321,16 @@ void CodeGenerator::generate()
|
|||
};
|
||||
const auto &root = m_objects.at(0).type;
|
||||
|
||||
QList<QQmlJSAotObject> compiledObjects;
|
||||
QList<QmltcType> compiledObjects;
|
||||
if (isComponent(root)) {
|
||||
compiledObjects.reserve(1);
|
||||
compiledObjects.emplaceBack(); // create new object
|
||||
const auto compile = [this](QQmlJSAotObject ¤t, const CodeGenObject &object) {
|
||||
const auto compile = [this](QmltcType ¤t, const CodeGenObject &object) {
|
||||
this->compileQQmlComponentElements(current, object);
|
||||
};
|
||||
compileObject(compiledObjects.back(), m_objects.at(0), compile);
|
||||
} else {
|
||||
const auto compile = [this](QQmlJSAotObject ¤t, const CodeGenObject &object) {
|
||||
const auto compile = [this](QmltcType ¤t, const CodeGenObject &object) {
|
||||
this->compileObjectElements(current, object);
|
||||
};
|
||||
|
||||
|
@ -359,15 +357,18 @@ void CodeGenerator::generate()
|
|||
if (m_logger->hasErrors())
|
||||
return;
|
||||
|
||||
QQmlJSProgram program { compiledObjects, m_urlMethod, url, hPath, cppPath,
|
||||
m_info->outputNamespace, requiredCppIncludes };
|
||||
QmltcProgram program {
|
||||
url, cppPath, hPath, m_info->outputNamespace, requiredCppIncludes,
|
||||
m_urlMethod, compiledObjects
|
||||
};
|
||||
|
||||
// write everything
|
||||
GeneratedCodeUtils codeUtils(code);
|
||||
CodeGeneratorWriter::write(codeUtils, program);
|
||||
QmltcOutput code;
|
||||
QmltcOutputWrapper codeUtils(code);
|
||||
QmltcCodeWriter::write(codeUtils, program);
|
||||
|
||||
writeToFile(hPath, code.header.toUtf8());
|
||||
writeToFile(cppPath, code.implementation.toUtf8());
|
||||
writeToFile(cppPath, code.cpp.toUtf8());
|
||||
}
|
||||
|
||||
QString buildCallSpecialMethodValue(bool documentRoot, const QString &outerFlagName,
|
||||
|
@ -382,8 +383,8 @@ QString buildCallSpecialMethodValue(bool documentRoot, const QString &outerFlagN
|
|||
}
|
||||
|
||||
void CodeGenerator::compileObject(
|
||||
QQmlJSAotObject &compiled, const CodeGenObject &object,
|
||||
std::function<void(QQmlJSAotObject &, const CodeGenObject &)> compileElements)
|
||||
QmltcType &compiled, const CodeGenObject &object,
|
||||
std::function<void(QmltcType &, const CodeGenObject &)> compileElements)
|
||||
{
|
||||
if (object.type->isSingleton()) {
|
||||
recordError(object.type->sourceLocation(), u"Singleton types are not supported"_qs);
|
||||
|
@ -427,14 +428,14 @@ void CodeGenerator::compileObject(
|
|||
compiled.handleOnCompleted.name = u"QML_handleOnCompleted"_qs;
|
||||
compiled.handleOnCompleted.returnType = u"void"_qs;
|
||||
|
||||
QQmlJSAotVariable engine(u"QQmlEngine *"_qs, u"engine"_qs, QString());
|
||||
QQmlJSAotVariable parent(u"QObject *"_qs, u"parent"_qs, u"nullptr"_qs);
|
||||
QmltcVariable engine(u"QQmlEngine *"_qs, u"engine"_qs, QString());
|
||||
QmltcVariable parent(u"QObject *"_qs, u"parent"_qs, u"nullptr"_qs);
|
||||
compiled.baselineCtor.parameterList = { parent };
|
||||
compiled.externalCtor.parameterList = { engine, parent };
|
||||
QQmlJSAotVariable ctxtdata(u"const QQmlRefPointer<QQmlContextData> &"_qs, u"parentContext"_qs,
|
||||
QString());
|
||||
QQmlJSAotVariable finalizeFlag(u"bool"_qs, u"canFinalize"_qs, QString());
|
||||
QQmlJSAotVariable callSpecialMethodFlag(u"bool"_qs, u"callSpecialMethodNow"_qs, QString());
|
||||
QmltcVariable ctxtdata(u"const QQmlRefPointer<QQmlContextData> &"_qs, u"parentContext"_qs,
|
||||
QString());
|
||||
QmltcVariable finalizeFlag(u"bool"_qs, u"canFinalize"_qs, QString());
|
||||
QmltcVariable callSpecialMethodFlag(u"bool"_qs, u"callSpecialMethodNow"_qs, QString());
|
||||
if (documentRoot) {
|
||||
compiled.init.parameterList = { engine, ctxtdata, finalizeFlag, callSpecialMethodFlag };
|
||||
compiled.endInit.parameterList = { engine, finalizeFlag };
|
||||
|
@ -692,7 +693,7 @@ void CodeGenerator::compileObject(
|
|||
// compiled.endInit.body << u"Qt::endPropertyUpdateGroup();"_qs;
|
||||
}
|
||||
|
||||
void CodeGenerator::compileObjectElements(QQmlJSAotObject &compiled, const CodeGenObject &object)
|
||||
void CodeGenerator::compileObjectElements(QmltcType &compiled, const CodeGenObject &object)
|
||||
{
|
||||
// compile enums
|
||||
const auto enums = object.type->ownEnumerations();
|
||||
|
@ -785,8 +786,7 @@ void CodeGenerator::compileObjectElements(QQmlJSAotObject &compiled, const CodeG
|
|||
compileBinding(compiled, **it, object, { object.type, u"this"_qs, u""_qs, false });
|
||||
}
|
||||
|
||||
void CodeGenerator::compileQQmlComponentElements(QQmlJSAotObject &compiled,
|
||||
const CodeGenObject &object)
|
||||
void CodeGenerator::compileQQmlComponentElements(QmltcType &compiled, const CodeGenObject &object)
|
||||
{
|
||||
Q_UNUSED(object);
|
||||
|
||||
|
@ -820,7 +820,7 @@ void CodeGenerator::compileQQmlComponentElements(QQmlJSAotObject &compiled,
|
|||
compiled.init.body << u"}"_qs;
|
||||
}
|
||||
|
||||
void CodeGenerator::compileEnum(QQmlJSAotObject ¤t, const QQmlJSMetaEnum &e)
|
||||
void CodeGenerator::compileEnum(QmltcType ¤t, const QQmlJSMetaEnum &e)
|
||||
{
|
||||
const auto intValues = e.values();
|
||||
QStringList values;
|
||||
|
@ -833,7 +833,7 @@ void CodeGenerator::compileEnum(QQmlJSAotObject ¤t, const QQmlJSMetaEnum &
|
|||
u"Q_ENUM(%1)"_qs.arg(e.name()));
|
||||
}
|
||||
|
||||
void CodeGenerator::compileProperty(QQmlJSAotObject ¤t, const QQmlJSMetaProperty &p,
|
||||
void CodeGenerator::compileProperty(QmltcType ¤t, const QQmlJSMetaProperty &p,
|
||||
const QQmlJSScope::ConstPtr &owner)
|
||||
{
|
||||
Q_ASSERT(!p.isAlias()); // will be handled separately
|
||||
|
@ -865,10 +865,10 @@ void CodeGenerator::compileProperty(QQmlJSAotObject ¤t, const QQmlJSMetaPr
|
|||
// If p.isList(), it's a QQmlListProperty. Then you can write the underlying list through
|
||||
// the QQmlListProperty object retrieved with the getter. Setting it would make no sense.
|
||||
if (p.isWritable() && !p.isList()) {
|
||||
QQmlJSAotMethod setter {};
|
||||
QmltcMethod setter {};
|
||||
setter.returnType = u"void"_qs;
|
||||
setter.name = compilationData.write;
|
||||
// QQmlJSAotVariable
|
||||
// QmltcVariable
|
||||
setter.parameterList.emplaceBack(QQmlJSUtils::constRefify(underlyingType), name + u"_",
|
||||
u""_qs);
|
||||
setter.body << variableName + u".setValue(" + name + u"_);";
|
||||
|
@ -878,7 +878,7 @@ void CodeGenerator::compileProperty(QQmlJSAotObject ¤t, const QQmlJSMetaPr
|
|||
mocPieces << u"WRITE"_qs << setter.name;
|
||||
}
|
||||
|
||||
QQmlJSAotMethod getter {};
|
||||
QmltcMethod getter {};
|
||||
getter.returnType = underlyingType;
|
||||
getter.name = compilationData.read;
|
||||
getter.body << u"return " + variableName + u".value();";
|
||||
|
@ -888,7 +888,7 @@ void CodeGenerator::compileProperty(QQmlJSAotObject ¤t, const QQmlJSMetaPr
|
|||
|
||||
// 2. add bindable
|
||||
if (!p.isList()) {
|
||||
QQmlJSAotMethod bindable {};
|
||||
QmltcMethod bindable {};
|
||||
bindable.returnType = u"QBindable<" + underlyingType + u">";
|
||||
bindable.name = compilationData.bindable;
|
||||
bindable.body << u"return QBindable<" + underlyingType + u">(std::addressof(" + variableName
|
||||
|
@ -916,7 +916,7 @@ void CodeGenerator::compileProperty(QQmlJSAotObject ¤t, const QQmlJSMetaPr
|
|||
compilationData.notify);
|
||||
}
|
||||
|
||||
void CodeGenerator::compileAlias(QQmlJSAotObject ¤t, const QQmlJSMetaProperty &alias,
|
||||
void CodeGenerator::compileAlias(QmltcType ¤t, const QQmlJSMetaProperty &alias,
|
||||
const QQmlJSScope::ConstPtr &owner)
|
||||
{
|
||||
const QString aliasName = alias.propertyName();
|
||||
|
@ -1040,7 +1040,7 @@ void CodeGenerator::compileAlias(QQmlJSAotObject ¤t, const QQmlJSMetaPrope
|
|||
Qml2CppPropertyData compilationData(aliasName);
|
||||
// 1. add setter and getter
|
||||
if (!info.readLine.isEmpty()) {
|
||||
QQmlJSAotMethod getter {};
|
||||
QmltcMethod getter {};
|
||||
getter.returnType = info.underlyingType;
|
||||
getter.name = compilationData.read;
|
||||
getter.body += prologue;
|
||||
|
@ -1052,13 +1052,13 @@ void CodeGenerator::compileAlias(QQmlJSAotObject ¤t, const QQmlJSMetaPrope
|
|||
} // else always an error?
|
||||
|
||||
if (!info.writeLine.isEmpty()) {
|
||||
QQmlJSAotMethod setter {};
|
||||
QmltcMethod setter {};
|
||||
setter.returnType = u"void"_qs;
|
||||
setter.name = compilationData.write;
|
||||
|
||||
QList<QQmlJSMetaMethod> methods = type->methods(resultingProperty.write());
|
||||
if (methods.isEmpty()) {
|
||||
// QQmlJSAotVariable
|
||||
// QmltcVariable
|
||||
setter.parameterList.emplaceBack(QQmlJSUtils::constRefify(info.underlyingType),
|
||||
aliasName + u"_", u""_qs);
|
||||
} else {
|
||||
|
@ -1072,7 +1072,7 @@ void CodeGenerator::compileAlias(QQmlJSAotObject ¤t, const QQmlJSMetaPrope
|
|||
parameterNames.reserve(setter.parameterList.size());
|
||||
std::transform(setter.parameterList.cbegin(), setter.parameterList.cend(),
|
||||
std::back_inserter(parameterNames),
|
||||
[](const QQmlJSAotVariable &x) { return x.name; });
|
||||
[](const QmltcVariable &x) { return x.name; });
|
||||
QString commaSeparatedParameterNames = parameterNames.join(u", "_qs);
|
||||
setter.body << info.writeLine.arg(commaSeparatedParameterNames) + u";";
|
||||
} else {
|
||||
|
@ -1086,7 +1086,7 @@ void CodeGenerator::compileAlias(QQmlJSAotObject ¤t, const QQmlJSMetaPrope
|
|||
|
||||
// 2. add bindable
|
||||
if (!info.bindableLine.isEmpty()) {
|
||||
QQmlJSAotMethod bindable {};
|
||||
QmltcMethod bindable {};
|
||||
bindable.returnType = u"QBindable<" + info.underlyingType + u">";
|
||||
bindable.name = compilationData.bindable;
|
||||
bindable.body += prologue;
|
||||
|
@ -1122,7 +1122,7 @@ void CodeGenerator::compileAlias(QQmlJSAotObject ¤t, const QQmlJSMetaPrope
|
|||
}
|
||||
}
|
||||
|
||||
void CodeGenerator::compileMethod(QQmlJSAotObject ¤t, const QQmlJSMetaMethod &m,
|
||||
void CodeGenerator::compileMethod(QmltcType ¤t, const QQmlJSMetaMethod &m,
|
||||
const QmlIR::Function *f, const CodeGenObject &object)
|
||||
{
|
||||
Q_UNUSED(object);
|
||||
|
@ -1131,7 +1131,7 @@ void CodeGenerator::compileMethod(QQmlJSAotObject ¤t, const QQmlJSMetaMeth
|
|||
const auto paramNames = m.parameterNames();
|
||||
const auto paramTypes = m.parameterTypes();
|
||||
Q_ASSERT(paramNames.size() == paramTypes.size());
|
||||
const QList<QQmlJSAotVariable> paramList = compileMethodParameters(paramNames, paramTypes);
|
||||
const QList<QmltcVariable> paramList = compileMethodParameters(paramNames, paramTypes);
|
||||
|
||||
const auto methodType = QQmlJSMetaMethod::Type(m.methodType());
|
||||
|
||||
|
@ -1146,7 +1146,7 @@ void CodeGenerator::compileMethod(QQmlJSAotObject ¤t, const QQmlJSMetaMeth
|
|||
returnType, paramList);
|
||||
}
|
||||
|
||||
QQmlJSAotMethod compiled {};
|
||||
QmltcMethod compiled {};
|
||||
compiled.returnType = returnType;
|
||||
compiled.name = m.methodName();
|
||||
compiled.parameterList = std::move(paramList);
|
||||
|
@ -1154,7 +1154,7 @@ void CodeGenerator::compileMethod(QQmlJSAotObject ¤t, const QQmlJSMetaMeth
|
|||
compiled.type = methodType;
|
||||
compiled.access = m.access();
|
||||
if (methodType != QQmlJSMetaMethod::Signal) {
|
||||
compiled.declPreambles << u"Q_INVOKABLE"_qs; // TODO: do we need this for signals as well?
|
||||
compiled.declarationPrefixes << u"Q_INVOKABLE"_qs;
|
||||
compiled.userVisible = m.access() == QQmlJSMetaMethod::Public;
|
||||
} else {
|
||||
compiled.userVisible = !m.isImplicitQmlPropertyChangeSignal();
|
||||
|
@ -1169,7 +1169,7 @@ static QString getPropertyOrAliasNameFromIr(const QmlIR::Document *doc, Iterator
|
|||
return doc->stringAt(first->nameIndex);
|
||||
}
|
||||
|
||||
void CodeGenerator::compileBinding(QQmlJSAotObject ¤t, const QmlIR::Binding &binding,
|
||||
void CodeGenerator::compileBinding(QmltcType ¤t, const QmlIR::Binding &binding,
|
||||
const CodeGenObject &object,
|
||||
const CodeGenerator::AccessorData &accessor)
|
||||
{
|
||||
|
@ -1579,26 +1579,26 @@ QString CodeGenerator::makeGensym(const QString &base)
|
|||
}
|
||||
|
||||
// returns compiled script binding for "property changed" handler in a form of object type
|
||||
static QQmlJSAotObject compileScriptBindingPropertyChangeHandler(
|
||||
static QmltcType compileScriptBindingPropertyChangeHandler(
|
||||
const QmlIR::Document *doc, const QmlIR::Binding &binding, const QmlIR::Object *irObject,
|
||||
const QQmlJSAotMethod &urlMethod, const QString &functorCppType,
|
||||
const QString &objectCppType, const QList<QQmlJSAotVariable> &slotParameters)
|
||||
const QmltcMethod &urlMethod, const QString &functorCppType, const QString &objectCppType,
|
||||
const QList<QmltcVariable> &slotParameters)
|
||||
{
|
||||
QQmlJSAotObject bindingFunctor {};
|
||||
QmltcType bindingFunctor {};
|
||||
bindingFunctor.cppType = functorCppType;
|
||||
bindingFunctor.ignoreInit = true;
|
||||
|
||||
// default member variable and ctor:
|
||||
const QString pointerToObject = objectCppType + u" *";
|
||||
bindingFunctor.variables.emplaceBack(
|
||||
QQmlJSAotVariable { pointerToObject, u"m_self"_qs, u"nullptr"_qs });
|
||||
QmltcVariable { pointerToObject, u"m_self"_qs, u"nullptr"_qs });
|
||||
bindingFunctor.baselineCtor.name = functorCppType;
|
||||
bindingFunctor.baselineCtor.parameterList.emplaceBack(
|
||||
QQmlJSAotVariable { pointerToObject, u"self"_qs, QString() });
|
||||
QmltcVariable { pointerToObject, u"self"_qs, QString() });
|
||||
bindingFunctor.baselineCtor.initializerList.emplaceBack(u"m_self(self)"_qs);
|
||||
|
||||
// call operator:
|
||||
QQmlJSAotMethod callOperator {};
|
||||
QmltcMethod callOperator {};
|
||||
callOperator.returnType = u"void"_qs;
|
||||
callOperator.name = u"operator()"_qs;
|
||||
callOperator.parameterList = slotParameters;
|
||||
|
@ -1628,7 +1628,7 @@ propertyForChangeHandler(const QQmlJSScope::ConstPtr &scope, QString name)
|
|||
return {};
|
||||
}
|
||||
|
||||
void CodeGenerator::compileScriptBinding(QQmlJSAotObject ¤t, const QmlIR::Binding &binding,
|
||||
void CodeGenerator::compileScriptBinding(QmltcType ¤t, const QmlIR::Binding &binding,
|
||||
const QString &bindingSymbolName,
|
||||
const CodeGenObject &object, const QString &propertyName,
|
||||
const QQmlJSScope::ConstPtr &propertyType,
|
||||
|
@ -1667,7 +1667,7 @@ void CodeGenerator::compileScriptBinding(QQmlJSAotObject ¤t, const QmlIR::
|
|||
};
|
||||
|
||||
// these only make sense when binding is on signal handler
|
||||
QList<QQmlJSAotVariable> slotParameters;
|
||||
QList<QmltcVariable> slotParameters;
|
||||
QString signalName;
|
||||
QString signalReturnType;
|
||||
|
||||
|
@ -1755,7 +1755,7 @@ void CodeGenerator::compileScriptBinding(QQmlJSAotObject ¤t, const QmlIR::
|
|||
const QString slotName = makeGensym(signalName + u"_slot");
|
||||
|
||||
// SignalHander specific:
|
||||
QQmlJSAotMethod slotMethod {};
|
||||
QmltcMethod slotMethod {};
|
||||
slotMethod.returnType = signalReturnType;
|
||||
slotMethod.name = slotName;
|
||||
slotMethod.parameterList = slotParameters;
|
||||
|
@ -1832,7 +1832,7 @@ void CodeGenerator::compileScriptBinding(QQmlJSAotObject ¤t, const QmlIR::
|
|||
+ accessor.name + u"))));";
|
||||
|
||||
current.variables.emplaceBack(
|
||||
QQmlJSAotVariable { typeOfQmlBinding, bindingSymbolName, QString() });
|
||||
QmltcVariable { typeOfQmlBinding, bindingSymbolName, QString() });
|
||||
// current.ctor.initializerList << bindingSymbolName + u"()";
|
||||
break;
|
||||
}
|
||||
|
@ -1840,7 +1840,7 @@ void CodeGenerator::compileScriptBinding(QQmlJSAotObject ¤t, const QmlIR::
|
|||
}
|
||||
|
||||
// TODO: should use "compileScriptBinding" instead of custom code
|
||||
void CodeGenerator::compileScriptBindingOfComponent(QQmlJSAotObject ¤t,
|
||||
void CodeGenerator::compileScriptBindingOfComponent(QmltcType ¤t,
|
||||
const QmlIR::Object *irObject,
|
||||
const QQmlJSScope::ConstPtr objectType,
|
||||
const QmlIR::Binding &binding,
|
||||
|
@ -1880,7 +1880,7 @@ void CodeGenerator::compileScriptBindingOfComponent(QQmlJSAotObject ¤t,
|
|||
const QString slotName = makeGensym(signalName + u"_slot");
|
||||
|
||||
// SignalHander specific:
|
||||
QQmlJSAotMethod slotMethod {};
|
||||
QmltcMethod slotMethod {};
|
||||
slotMethod.returnType = signalReturnType;
|
||||
slotMethod.name = slotName;
|
||||
|
||||
|
@ -1898,7 +1898,8 @@ void CodeGenerator::compileScriptBindingOfComponent(QQmlJSAotObject ¤t,
|
|||
current.handleOnCompleted.body << slotName + u"();";
|
||||
} else if (signalName == u"destruction"_qs) {
|
||||
if (!current.dtor) {
|
||||
current.dtor = QQmlJSAotSpecialMethod {};
|
||||
// TODO: double-check that this stuff is actually correct now:
|
||||
current.dtor = QmltcDtor {};
|
||||
current.dtor->name = u"~" + current.cppType;
|
||||
}
|
||||
current.dtor->firstLines << slotName + u"();";
|
||||
|
@ -1913,7 +1914,7 @@ void CodeGenerator::compileUrlMethod()
|
|||
m_urlMethod.body << u"static QUrl docUrl = %1;"_qs.arg(
|
||||
CodeGeneratorUtility::toResourcePath(m_info->resourcePath));
|
||||
m_urlMethod.body << u"return docUrl;"_qs;
|
||||
m_urlMethod.declPreambles << u"static"_qs;
|
||||
m_urlMethod.declarationPrefixes << u"static"_qs;
|
||||
m_urlMethod.modifiers << u"noexcept"_qs;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,8 +30,7 @@
|
|||
#define CODEGENERATOR_H
|
||||
|
||||
#include "qmltctyperesolver.h"
|
||||
#include "prototype/qmlcompiler.h"
|
||||
#include "prototype/generatedcodeprimitives.h"
|
||||
#include "qmltcoutputir.h"
|
||||
#include "prototype/qml2cppcontext.h"
|
||||
|
||||
#include <QtCore/qlist.h>
|
||||
|
@ -80,13 +79,13 @@ private:
|
|||
// types ignored by the code generator
|
||||
QSet<QQmlJSScope::ConstPtr> m_ignoredTypes;
|
||||
|
||||
QQmlJSAotMethod m_urlMethod;
|
||||
QmltcMethod m_urlMethod;
|
||||
|
||||
// helper struct used for unique string generation
|
||||
struct UniqueStringId
|
||||
{
|
||||
QString combined;
|
||||
UniqueStringId(const QQmlJSAotObject &compiled, const QString &value)
|
||||
UniqueStringId(const QmltcType &compiled, const QString &value)
|
||||
: combined(compiled.cppType + u"_" + value)
|
||||
{
|
||||
Q_ASSERT(!compiled.cppType.isEmpty());
|
||||
|
@ -141,19 +140,18 @@ private:
|
|||
bool m_isAnonymous = false; // crutch to distinguish QML_ELEMENT from QML_ANONYMOUS
|
||||
|
||||
// code compilation functions that produce "compiled" entities
|
||||
void
|
||||
compileObject(QQmlJSAotObject ¤t, const CodeGenObject &object,
|
||||
std::function<void(QQmlJSAotObject &, const CodeGenObject &)> compileElements);
|
||||
void compileObjectElements(QQmlJSAotObject ¤t, const CodeGenObject &object);
|
||||
void compileQQmlComponentElements(QQmlJSAotObject ¤t, const CodeGenObject &object);
|
||||
void compileObject(QmltcType ¤t, const CodeGenObject &object,
|
||||
std::function<void(QmltcType &, const CodeGenObject &)> compileElements);
|
||||
void compileObjectElements(QmltcType ¤t, const CodeGenObject &object);
|
||||
void compileQQmlComponentElements(QmltcType ¤t, const CodeGenObject &object);
|
||||
|
||||
void compileEnum(QQmlJSAotObject ¤t, const QQmlJSMetaEnum &e);
|
||||
void compileProperty(QQmlJSAotObject ¤t, const QQmlJSMetaProperty &p,
|
||||
void compileEnum(QmltcType ¤t, const QQmlJSMetaEnum &e);
|
||||
void compileProperty(QmltcType ¤t, const QQmlJSMetaProperty &p,
|
||||
const QQmlJSScope::ConstPtr &owner);
|
||||
void compileAlias(QQmlJSAotObject ¤t, const QQmlJSMetaProperty &alias,
|
||||
void compileAlias(QmltcType ¤t, const QQmlJSMetaProperty &alias,
|
||||
const QQmlJSScope::ConstPtr &owner);
|
||||
void compileMethod(QQmlJSAotObject ¤t, const QQmlJSMetaMethod &m,
|
||||
const QmlIR::Function *f, const CodeGenObject &object);
|
||||
void compileMethod(QmltcType ¤t, const QQmlJSMetaMethod &m, const QmlIR::Function *f,
|
||||
const CodeGenObject &object);
|
||||
void compileUrlMethod(); // special case
|
||||
|
||||
// helper structure that holds the information necessary for most bindings,
|
||||
|
@ -167,17 +165,17 @@ private:
|
|||
QString propertyName; // usually empty
|
||||
bool isValueType = false; // usually false
|
||||
};
|
||||
void compileBinding(QQmlJSAotObject ¤t, const QmlIR::Binding &binding,
|
||||
void compileBinding(QmltcType ¤t, const QmlIR::Binding &binding,
|
||||
const CodeGenObject &object, const AccessorData &accessor);
|
||||
// special case (for simplicity)
|
||||
void compileScriptBinding(QQmlJSAotObject ¤t, const QmlIR::Binding &binding,
|
||||
void compileScriptBinding(QmltcType ¤t, const QmlIR::Binding &binding,
|
||||
const QString &bindingSymbolName, const CodeGenObject &object,
|
||||
const QString &propertyName,
|
||||
const QQmlJSScope::ConstPtr &propertyType,
|
||||
const AccessorData &accessor);
|
||||
|
||||
// TODO: remove this special case
|
||||
void compileScriptBindingOfComponent(QQmlJSAotObject ¤t, const QmlIR::Object *object,
|
||||
void compileScriptBindingOfComponent(QmltcType ¤t, const QmlIR::Object *object,
|
||||
const QQmlJSScope::ConstPtr objectType,
|
||||
const QmlIR::Binding &binding,
|
||||
const QString &propertyName);
|
||||
|
|
|
@ -37,11 +37,10 @@ QT_BEGIN_NAMESPACE
|
|||
|
||||
// NB: this variable would behave correctly as long as QML init and QML finalize
|
||||
// are non-virtual functions
|
||||
const QQmlJSAotVariable CodeGeneratorUtility::childrenOffsetVariable = { u"qsizetype"_qs,
|
||||
u"QML_choffset"_qs,
|
||||
QString() };
|
||||
const QmltcVariable CodeGeneratorUtility::childrenOffsetVariable { u"qsizetype"_qs,
|
||||
u"QML_choffset"_qs, QString() };
|
||||
|
||||
const QQmlJSAotVariable CodeGeneratorUtility::compilationUnitVariable = {
|
||||
const QmltcVariable CodeGeneratorUtility::compilationUnitVariable {
|
||||
u"QV4::ExecutableCompilationUnit *"_qs, u"QML_cu"_qs, QString()
|
||||
};
|
||||
|
||||
|
@ -143,7 +142,7 @@ QStringList CodeGeneratorUtility::generate_assignToSpecialAlias(
|
|||
|
||||
QStringList CodeGeneratorUtility::generate_callExecuteRuntimeFunction(
|
||||
const QString &url, qsizetype index, const QString &accessor, const QString &returnType,
|
||||
const QList<QQmlJSAotVariable> ¶meters)
|
||||
const QList<QmltcVariable> ¶meters)
|
||||
{
|
||||
QStringList code;
|
||||
code.reserve(12); // should always be enough
|
||||
|
@ -165,7 +164,7 @@ QStringList CodeGeneratorUtility::generate_callExecuteRuntimeFunction(
|
|||
types << u"QMetaType::fromType<std::decay_t<" + returnType + u">>()";
|
||||
}
|
||||
|
||||
for (const QQmlJSAotVariable &p : parameters) {
|
||||
for (const QmltcVariable &p : parameters) {
|
||||
args << u"const_cast<void *>(reinterpret_cast<const void *>(std::addressof(" + p.name
|
||||
+ u")))";
|
||||
types << u"QMetaType::fromType<std::decay_t<" + p.cppType + u">>()";
|
||||
|
@ -214,12 +213,12 @@ QStringList CodeGeneratorUtility::generate_createBindingOnProperty(
|
|||
return code;
|
||||
}
|
||||
|
||||
QString CodeGeneratorUtility::generate_qOverload(const QList<QQmlJSAotVariable> ¶ms,
|
||||
QString CodeGeneratorUtility::generate_qOverload(const QList<QmltcVariable> ¶ms,
|
||||
const QString &overloaded)
|
||||
{
|
||||
QStringList types;
|
||||
types.reserve(params.size());
|
||||
for (const QQmlJSAotVariable &p : params)
|
||||
for (const QmltcVariable &p : params)
|
||||
types.emplaceBack(p.cppType);
|
||||
return u"qOverload<" + types.join(u", "_qs) + u">(" + overloaded + u")";
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#ifndef CODEGENERATORUTIL_H
|
||||
#define CODEGENERATORUTIL_H
|
||||
|
||||
#include "prototype/qmlcompiler.h"
|
||||
#include "qmltcoutputir.h"
|
||||
|
||||
#include <private/qqmljsscope_p.h>
|
||||
#include <private/qqmljsmetatypes_p.h>
|
||||
|
@ -53,10 +53,10 @@ struct CodeGeneratorUtility
|
|||
// reference any object in the document by id, which automatically means
|
||||
// that all ids have to be set up before we get to finalization (and the
|
||||
// only place for it is init)
|
||||
static const QQmlJSAotVariable childrenOffsetVariable;
|
||||
static const QmltcVariable childrenOffsetVariable;
|
||||
|
||||
// represents QV4::ExecutableCompilationUnit
|
||||
static const QQmlJSAotVariable compilationUnitVariable;
|
||||
static const QmltcVariable compilationUnitVariable;
|
||||
|
||||
// helper functions:
|
||||
static QString toResourcePath(const QString &s)
|
||||
|
@ -84,13 +84,13 @@ struct CodeGeneratorUtility
|
|||
static QStringList
|
||||
generate_callExecuteRuntimeFunction(const QString &url, qsizetype index,
|
||||
const QString &accessor, const QString &returnType,
|
||||
const QList<QQmlJSAotVariable> ¶meters = {});
|
||||
const QList<QmltcVariable> ¶meters = {});
|
||||
static QStringList
|
||||
generate_createBindingOnProperty(const QString &unitVarName, const QString &scope,
|
||||
qsizetype functionIndex, const QString &target,
|
||||
int propertyIndex, const QQmlJSMetaProperty &p,
|
||||
int valueTypeIndex, const QString &subTarget);
|
||||
static QString generate_qOverload(const QList<QQmlJSAotVariable> ¶meters,
|
||||
static QString generate_qOverload(const QList<QmltcVariable> ¶meters,
|
||||
const QString &overloaded);
|
||||
static QString generate_addressof(const QString &addressed);
|
||||
static QString generate_getPrivateClass(const QString &accessor, const QQmlJSMetaProperty &p);
|
||||
|
|
|
@ -1,480 +0,0 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the tools applications of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
#include "codegeneratorwriter.h"
|
||||
|
||||
#include <private/qqmljsmetatypes_p.h>
|
||||
|
||||
#include <QtCore/qfileinfo.h>
|
||||
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
static constexpr char16_t newLine[] =
|
||||
#ifdef Q_OS_WIN32
|
||||
u"\r\n";
|
||||
#else
|
||||
u"\n";
|
||||
#endif
|
||||
static constexpr char newLineLatin1[] =
|
||||
#ifdef Q_OS_WIN32
|
||||
"\r\n";
|
||||
#else
|
||||
"\n";
|
||||
#endif
|
||||
|
||||
static QString urlToMacro(const QString &url)
|
||||
{
|
||||
QFileInfo fi(url);
|
||||
return u"Q_QMLTC_" + fi.baseName().toUpper();
|
||||
}
|
||||
|
||||
static QString getFunctionCategory(const QQmlJSAotMethodBase &compiled)
|
||||
{
|
||||
QString category;
|
||||
switch (compiled.access) {
|
||||
case QQmlJSMetaMethod::Private:
|
||||
category = u"private"_qs;
|
||||
break;
|
||||
case QQmlJSMetaMethod::Protected:
|
||||
category = u"protected"_qs;
|
||||
break;
|
||||
case QQmlJSMetaMethod::Public:
|
||||
category = u"public"_qs;
|
||||
break;
|
||||
}
|
||||
return category;
|
||||
}
|
||||
|
||||
static QString getFunctionCategory(const QQmlJSAotMethod &compiled)
|
||||
{
|
||||
QString category = getFunctionCategory(static_cast<const QQmlJSAotMethodBase &>(compiled));
|
||||
switch (compiled.type) {
|
||||
case QQmlJSMetaMethod::Signal:
|
||||
category = u"signals"_qs;
|
||||
break;
|
||||
case QQmlJSMetaMethod::Slot:
|
||||
category += u" slots"_qs;
|
||||
break;
|
||||
case QQmlJSMetaMethod::Method:
|
||||
break;
|
||||
}
|
||||
return category;
|
||||
}
|
||||
|
||||
void CodeGeneratorWriter::writeGlobalHeader(GeneratedCodeUtils &code, const QString &sourceName,
|
||||
const QString &hPath, const QString &cppPath,
|
||||
const QString &outNamespace,
|
||||
const QSet<QString> &requiredCppIncludes)
|
||||
{
|
||||
Q_UNUSED(newLineLatin1);
|
||||
|
||||
Q_UNUSED(cppPath);
|
||||
const QString preamble =
|
||||
u"// This code is auto-generated by the qmlcompiler tool from the file '" + sourceName
|
||||
+ u"'" + newLine + u"// WARNING! All changes made in this file will be lost!" + newLine;
|
||||
code.appendToHeader(preamble);
|
||||
code.appendToImpl(preamble);
|
||||
code.appendToHeader(u"// NOTE: This generated API is to be considered implementation detail.");
|
||||
code.appendToHeader(
|
||||
u"// It may change from version to version and should not be relied upon.");
|
||||
|
||||
const QString headerMacro = urlToMacro(sourceName);
|
||||
code.appendToHeader(u"#ifndef %1_H"_qs.arg(headerMacro));
|
||||
code.appendToHeader(u"#define %1_H"_qs.arg(headerMacro));
|
||||
|
||||
code.appendToHeader(u"#include <QtCore/qproperty.h>");
|
||||
code.appendToHeader(u"#include <QtCore/qobject.h>");
|
||||
code.appendToHeader(u"#include <QtCore/qcoreapplication.h>");
|
||||
code.appendToHeader(u"#include <QtQml/qqmlengine.h>");
|
||||
code.appendToHeader(u"#include <QtCore/qurl.h>"); // used in engine execution
|
||||
code.appendToHeader(u"#include <QtQml/qqml.h>"); // used for attached properties
|
||||
|
||||
code.appendToHeader(u"#include <private/qqmlengine_p.h>"); // NB: private header
|
||||
|
||||
code.appendToHeader(u"#include <QQmlListProperty>"); // required by list properties
|
||||
|
||||
// include custom C++ includes required by used types
|
||||
code.appendToHeader(u"// BEGIN(custom_cpp_includes)");
|
||||
for (const auto &requiredInclude : requiredCppIncludes) {
|
||||
code.appendToHeader(u"#include \"" + requiredInclude + u"\"");
|
||||
}
|
||||
code.appendToHeader(u"// END(custom_cpp_includes)");
|
||||
|
||||
code.appendToImpl(u"#include \"" + hPath + u"\""); // include own .h file
|
||||
code.appendToImpl(u"#include <private/qqmlcppbinding_p.h>"); // QmltcSupportLib
|
||||
code.appendToImpl(u"#include <private/qqmlcpponassignment_p.h>"); // QmltcSupportLib
|
||||
|
||||
code.appendToImpl(u"#include <private/qqmlobjectcreator_p.h>"); // createComponent()
|
||||
code.appendToImpl(u"#include <private/qqmlcomponent_p.h>"); // QQmlComponentPrivate::get()
|
||||
|
||||
code.appendToImpl(u"");
|
||||
code.appendToImpl(u"#include <private/qobject_p.h>"); // NB: for private properties
|
||||
code.appendToImpl(u"#include <private/qqmlobjectcreator_p.h>"); // for finalize callbacks
|
||||
|
||||
code.appendToImpl(u""); // blank line
|
||||
if (!outNamespace.isEmpty()) {
|
||||
code.appendToHeader(u""); // blank line
|
||||
code.appendToHeader(u"namespace %1 {"_qs.arg(outNamespace));
|
||||
code.appendToImpl(u""); // blank line
|
||||
code.appendToImpl(u"namespace %1 {"_qs.arg(outNamespace));
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGeneratorWriter::writeGlobalFooter(GeneratedCodeUtils &code, const QString &sourceName,
|
||||
const QString &hPath, const QString &cppPath,
|
||||
const QString &outNamespace)
|
||||
{
|
||||
Q_UNUSED(code);
|
||||
Q_UNUSED(hPath);
|
||||
Q_UNUSED(cppPath);
|
||||
|
||||
if (!outNamespace.isEmpty()) {
|
||||
code.appendToImpl(u"} // namespace %1"_qs.arg(outNamespace));
|
||||
code.appendToImpl(u""); // blank line
|
||||
code.appendToHeader(u"} // namespace %1"_qs.arg(outNamespace));
|
||||
code.appendToHeader(u""); // blank line
|
||||
}
|
||||
|
||||
code.appendToHeader(u"#endif // %1_H"_qs.arg(urlToMacro(sourceName)));
|
||||
code.appendToHeader(u""); // blank line
|
||||
}
|
||||
|
||||
static QString classString(const QQmlJSAotObject &compiled)
|
||||
{
|
||||
QString str = u"class " + compiled.cppType;
|
||||
QStringList nonEmptyBaseClasses;
|
||||
nonEmptyBaseClasses.reserve(compiled.baseClasses.size());
|
||||
std::copy_if(compiled.baseClasses.cbegin(), compiled.baseClasses.cend(),
|
||||
std::back_inserter(nonEmptyBaseClasses),
|
||||
[](const QString &entry) { return !entry.isEmpty(); });
|
||||
if (!nonEmptyBaseClasses.isEmpty())
|
||||
str += u" : public " + nonEmptyBaseClasses.join(u", public "_qs);
|
||||
return str;
|
||||
}
|
||||
|
||||
template<typename Predicate>
|
||||
static void dumpFunctions(GeneratedCodeUtils &code, const QList<QQmlJSAotMethod> &functions,
|
||||
Predicate pred)
|
||||
{
|
||||
// functions are _ordered_ by access and kind. ordering is important to
|
||||
// provide consistent output
|
||||
QMap<QString, QList<const QQmlJSAotMethod *>> orderedFunctions;
|
||||
for (const auto &function : functions) {
|
||||
if (pred(function))
|
||||
orderedFunctions[getFunctionCategory(function)].append(std::addressof(function));
|
||||
}
|
||||
|
||||
for (auto it = orderedFunctions.cbegin(); it != orderedFunctions.cend(); ++it) {
|
||||
code.appendToHeader(it.key() + u":", -1);
|
||||
for (const QQmlJSAotMethod *function : qAsConst(it.value()))
|
||||
CodeGeneratorWriter::write(code, *function);
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGeneratorWriter::write(GeneratedCodeUtils &code, const QQmlJSAotObject &compiled)
|
||||
{
|
||||
code.appendToHeader(u""); // just new line
|
||||
code.appendToImpl(u""); // just new line
|
||||
|
||||
// generate class preamble
|
||||
code.appendToHeader(classString(compiled));
|
||||
code.appendToHeader(u"{");
|
||||
for (const QString &mocLine : qAsConst(compiled.mocCode))
|
||||
code.appendToHeader(mocLine, 1);
|
||||
|
||||
for (const QString &otherLine : qAsConst(compiled.otherCode))
|
||||
code.appendToHeader(otherLine, 1);
|
||||
|
||||
GeneratedCodeUtils::MemberNamespaceScope thisObjectScope(code, compiled.cppType);
|
||||
Q_UNUSED(thisObjectScope);
|
||||
{
|
||||
GeneratedCodeUtils::HeaderIndentationScope headerIndentScope(code);
|
||||
Q_UNUSED(headerIndentScope);
|
||||
|
||||
// first, write user-visible code, then everything else. someone might
|
||||
// want to look at the generated code, so let's make an effort when
|
||||
// writing it down
|
||||
|
||||
code.appendToHeader(u"// -----------------");
|
||||
code.appendToHeader(u"// External C++ API:");
|
||||
code.appendToHeader(u"public:", -1);
|
||||
|
||||
// NB: when non-document root, the externalCtor won't be public - but we
|
||||
// really don't care about the output format of such types
|
||||
if (!compiled.ignoreInit && compiled.externalCtor.access == QQmlJSMetaMethod::Public) {
|
||||
// TODO: ignoreInit must be eliminated
|
||||
|
||||
CodeGeneratorWriter::write(code, compiled.externalCtor);
|
||||
}
|
||||
// generate dtor
|
||||
if (compiled.dtor)
|
||||
CodeGeneratorWriter::write(code, *compiled.dtor);
|
||||
|
||||
// generate enums
|
||||
for (const auto &enumeration : qAsConst(compiled.enums))
|
||||
CodeGeneratorWriter::write(code, enumeration);
|
||||
|
||||
// generate (visible) functions
|
||||
const auto isUserVisibleFunction = [](const QQmlJSAotMethod &function) {
|
||||
return function.userVisible;
|
||||
};
|
||||
dumpFunctions(code, compiled.functions, isUserVisibleFunction);
|
||||
|
||||
code.appendToHeader(u"// -----------------");
|
||||
code.appendToHeader(u""); // blank line
|
||||
code.appendToHeader(u"// Internal functionality (do NOT use it!):");
|
||||
|
||||
// below are the hidden parts of the class
|
||||
|
||||
// generate (rest of the) ctors
|
||||
if (compiled.ignoreInit) { // TODO: this branch should be eliminated
|
||||
Q_ASSERT(compiled.baselineCtor.access == QQmlJSMetaMethod::Public);
|
||||
code.appendToHeader(u"public:", -1);
|
||||
CodeGeneratorWriter::write(code, compiled.baselineCtor);
|
||||
} else {
|
||||
code.appendToHeader(u"protected:", -1);
|
||||
if (compiled.externalCtor.access != QQmlJSMetaMethod::Public) {
|
||||
Q_ASSERT(compiled.externalCtor.access == QQmlJSMetaMethod::Protected);
|
||||
CodeGeneratorWriter::write(code, compiled.externalCtor);
|
||||
}
|
||||
CodeGeneratorWriter::write(code, compiled.baselineCtor);
|
||||
CodeGeneratorWriter::write(code, compiled.init);
|
||||
CodeGeneratorWriter::write(code, compiled.endInit);
|
||||
CodeGeneratorWriter::write(code, compiled.completeComponent);
|
||||
CodeGeneratorWriter::write(code, compiled.finalizeComponent);
|
||||
CodeGeneratorWriter::write(code, compiled.handleOnCompleted);
|
||||
|
||||
// code.appendToHeader(u"public:", -1);
|
||||
}
|
||||
|
||||
// generate child types
|
||||
code.appendToHeader(u"// BEGIN(children)");
|
||||
for (const auto &child : qAsConst(compiled.children))
|
||||
CodeGeneratorWriter::write(code, child);
|
||||
code.appendToHeader(u"// END(children)");
|
||||
|
||||
// generate functions
|
||||
code.appendToHeader(u"// BEGIN(hidden_functions)");
|
||||
dumpFunctions(code, compiled.functions, std::not_fn(isUserVisibleFunction));
|
||||
code.appendToHeader(u"// END(hidden_functions)");
|
||||
|
||||
if (!compiled.variables.isEmpty() || !compiled.properties.isEmpty()) {
|
||||
code.appendToHeader(u""); // blank line
|
||||
code.appendToHeader(u"protected:", -1);
|
||||
}
|
||||
// generate variables
|
||||
if (!compiled.variables.isEmpty()) {
|
||||
code.appendToHeader(u"// BEGIN(variables)");
|
||||
for (const auto &variable : qAsConst(compiled.variables))
|
||||
CodeGeneratorWriter::write(code, variable);
|
||||
code.appendToHeader(u"// END(variables)");
|
||||
}
|
||||
|
||||
// generate properties
|
||||
if (!compiled.properties.isEmpty()) {
|
||||
code.appendToHeader(u"// BEGIN(properties)");
|
||||
for (const auto &property : qAsConst(compiled.properties))
|
||||
CodeGeneratorWriter::write(code, property);
|
||||
code.appendToHeader(u"// END(properties)");
|
||||
}
|
||||
}
|
||||
|
||||
code.appendToHeader(u"};");
|
||||
}
|
||||
|
||||
void CodeGeneratorWriter::write(GeneratedCodeUtils &code, const QQmlJSAotEnum &compiled)
|
||||
{
|
||||
code.appendToHeader(u"enum " + compiled.cppType + u" {");
|
||||
for (qsizetype i = 0; i < compiled.keys.size(); ++i) {
|
||||
QString str;
|
||||
if (compiled.values.isEmpty()) {
|
||||
str += compiled.keys.at(i) + u",";
|
||||
} else {
|
||||
str += compiled.keys.at(i) + u" = " + compiled.values.at(i) + u",";
|
||||
}
|
||||
code.appendToHeader(str, 1);
|
||||
}
|
||||
code.appendToHeader(u"};");
|
||||
code.appendToHeader(compiled.ownMocLine);
|
||||
}
|
||||
|
||||
// NB: property generation is only concerned with property declaration in the header
|
||||
void CodeGeneratorWriter::write(GeneratedCodeUtils &code, const QQmlJSAotVariable &compiled)
|
||||
{
|
||||
if (compiled.defaultValue.isEmpty()) {
|
||||
code.appendToHeader(compiled.cppType + u" " + compiled.name + u";");
|
||||
} else {
|
||||
code.appendToHeader(compiled.cppType + u" " + compiled.name + u" = " + compiled.defaultValue
|
||||
+ u";");
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGeneratorWriter::write(GeneratedCodeUtils &code, const QQmlJSAotProperty &prop)
|
||||
{
|
||||
Q_ASSERT(prop.defaultValue.isEmpty()); // we don't support it yet
|
||||
code.appendToHeader(u"Q_OBJECT_BINDABLE_PROPERTY(%1, %2, %3, &%1::%4)"_qs.arg(
|
||||
prop.containingClass, prop.cppType, prop.name, prop.signalName));
|
||||
}
|
||||
|
||||
static QString appendSpace(const QString &s)
|
||||
{
|
||||
if (s.isEmpty())
|
||||
return s;
|
||||
return s + u" ";
|
||||
}
|
||||
|
||||
static QString prependSpace(const QString &s)
|
||||
{
|
||||
if (s.isEmpty())
|
||||
return s;
|
||||
return u" " + s;
|
||||
}
|
||||
|
||||
static std::pair<QString, QString> functionSignatures(const QQmlJSAotMethodBase &m)
|
||||
{
|
||||
const QString name = m.name;
|
||||
const QList<QQmlJSAotVariable> ¶meterList = m.parameterList;
|
||||
QStringList headerParamList;
|
||||
QStringList implParamList;
|
||||
for (const QQmlJSAotVariable &variable : parameterList) {
|
||||
const QString commonPart = variable.cppType + u" " + variable.name;
|
||||
implParamList << commonPart;
|
||||
headerParamList << commonPart;
|
||||
if (!variable.defaultValue.isEmpty())
|
||||
headerParamList.back() += u" = " + variable.defaultValue;
|
||||
}
|
||||
const QString headerSignature = name + u"(" + headerParamList.join(u", "_qs) + u")"
|
||||
+ prependSpace(m.modifiers.join(u" "));
|
||||
const QString implSignature = name + u"(" + implParamList.join(u", "_qs) + u")"
|
||||
+ prependSpace(m.modifiers.join(u" "));
|
||||
return { headerSignature, implSignature };
|
||||
}
|
||||
|
||||
static QString functionReturnType(const QQmlJSAotMethodBase &m)
|
||||
{
|
||||
return appendSpace(m.declPreambles.join(u" "_qs)) + m.returnType;
|
||||
}
|
||||
|
||||
void CodeGeneratorWriter::write(GeneratedCodeUtils &code, const QQmlJSAotMethod &compiled)
|
||||
{
|
||||
const auto [hSignature, cppSignature] = functionSignatures(compiled);
|
||||
// Note: augment return type with preambles in declaration
|
||||
code.appendToHeader(functionReturnType(compiled) + u" " + hSignature + u";");
|
||||
|
||||
// do not generate method implementation if it is a signal
|
||||
const auto methodType = compiled.type;
|
||||
if (methodType != QQmlJSMetaMethod::Signal) {
|
||||
code.appendToImpl(u""); // just new line
|
||||
code.appendToImpl(compiled.returnType);
|
||||
code.appendSignatureToImpl(cppSignature);
|
||||
code.appendToImpl(u"{");
|
||||
{
|
||||
GeneratedCodeUtils::ImplIndentationScope indentScope(code);
|
||||
Q_UNUSED(indentScope);
|
||||
for (const QString &line : qAsConst(compiled.firstLines))
|
||||
code.appendToImpl(line);
|
||||
for (const QString &line : qAsConst(compiled.body))
|
||||
code.appendToImpl(line);
|
||||
for (const QString &line : qAsConst(compiled.lastLines))
|
||||
code.appendToImpl(line);
|
||||
}
|
||||
code.appendToImpl(u"}");
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGeneratorWriter::write(GeneratedCodeUtils &code, const QQmlJSAotSpecialMethod &compiled)
|
||||
{
|
||||
const auto [hSignature, cppSignature] = functionSignatures(compiled);
|
||||
const QString returnTypeWithSpace =
|
||||
compiled.returnType.isEmpty() ? u""_qs : compiled.returnType + u" ";
|
||||
|
||||
code.appendToHeader(returnTypeWithSpace + hSignature + u";");
|
||||
|
||||
code.appendToImpl(u""); // just new line
|
||||
if (!returnTypeWithSpace.isEmpty())
|
||||
code.appendToImpl(returnTypeWithSpace);
|
||||
code.appendSignatureToImpl(cppSignature);
|
||||
if (!compiled.initializerList.isEmpty()) {
|
||||
code.appendToImpl(u":", 1);
|
||||
code.appendToImpl(compiled.initializerList.join(u","_qs + newLine + newLine
|
||||
+ u" "_qs.repeated(code.implIndent + 1)),
|
||||
1);
|
||||
}
|
||||
code.appendToImpl(u"{");
|
||||
{
|
||||
GeneratedCodeUtils::ImplIndentationScope indentScope(code);
|
||||
Q_UNUSED(indentScope);
|
||||
for (const QString &line : qAsConst(compiled.firstLines))
|
||||
code.appendToImpl(line);
|
||||
for (const QString &line : qAsConst(compiled.body))
|
||||
code.appendToImpl(line);
|
||||
for (const QString &line : qAsConst(compiled.lastLines))
|
||||
code.appendToImpl(line);
|
||||
}
|
||||
code.appendToImpl(u"}");
|
||||
}
|
||||
|
||||
void CodeGeneratorWriter::writeUrl(GeneratedCodeUtils &code, const QQmlJSAotMethod &urlMethod)
|
||||
{
|
||||
const auto [hSignature, _] = functionSignatures(urlMethod);
|
||||
Q_UNUSED(_);
|
||||
Q_ASSERT(!urlMethod.returnType.isEmpty());
|
||||
code.appendToImpl(functionReturnType(urlMethod) + hSignature);
|
||||
code.appendToImpl(u"{");
|
||||
{
|
||||
GeneratedCodeUtils::ImplIndentationScope indentScope(code);
|
||||
Q_UNUSED(indentScope);
|
||||
Q_ASSERT(urlMethod.firstLines.isEmpty() && urlMethod.lastLines.isEmpty());
|
||||
for (const QString &line : qAsConst(urlMethod.body))
|
||||
code.appendToImpl(line);
|
||||
}
|
||||
code.appendToImpl(u"}");
|
||||
}
|
||||
|
||||
void CodeGeneratorWriter::write(GeneratedCodeUtils &code, const QQmlJSProgram &compiled)
|
||||
{
|
||||
writeGlobalHeader(code, compiled.url, compiled.hPath, compiled.cppPath, compiled.outNamespace,
|
||||
compiled.includes);
|
||||
|
||||
code.appendToImpl(u""); // just new line
|
||||
writeUrl(code, compiled.urlMethod);
|
||||
|
||||
// forward declare objects before writing them
|
||||
for (const QQmlJSAotObject &compiled : qAsConst(compiled.compiledObjects))
|
||||
code.appendToHeader(u"class " + compiled.cppType + u";");
|
||||
|
||||
// write all the objects
|
||||
for (const QQmlJSAotObject &compiled : qAsConst(compiled.compiledObjects))
|
||||
write(code, compiled);
|
||||
|
||||
writeGlobalFooter(code, compiled.url, compiled.hPath, compiled.cppPath, compiled.outNamespace);
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
|
@ -1,61 +0,0 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the tools applications of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CODEGENERATORWRITER_H
|
||||
#define CODEGENERATORWRITER_H
|
||||
|
||||
#include "generatedcodeprimitives.h"
|
||||
#include "qmlcompiler.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
// writes compiled code into the GeneratedCode structure
|
||||
struct CodeGeneratorWriter
|
||||
{
|
||||
static void writeGlobalHeader(GeneratedCodeUtils &code, const QString &sourceName,
|
||||
const QString &hPath, const QString &cppPath,
|
||||
const QString &outNamespace,
|
||||
const QSet<QString> &requiredCppIncludes);
|
||||
static void writeGlobalFooter(GeneratedCodeUtils &code, const QString &sourceName,
|
||||
const QString &hPath, const QString &cppPath,
|
||||
const QString &outNamespace);
|
||||
static void write(GeneratedCodeUtils &code, const QQmlJSAotObject &compiled);
|
||||
static void write(GeneratedCodeUtils &code, const QQmlJSAotEnum &compiled);
|
||||
static void write(GeneratedCodeUtils &code, const QQmlJSAotVariable &compiled);
|
||||
static void write(GeneratedCodeUtils &code, const QQmlJSAotProperty &compiled);
|
||||
static void write(GeneratedCodeUtils &code, const QQmlJSAotMethod &compiled);
|
||||
static void write(GeneratedCodeUtils &code, const QQmlJSAotSpecialMethod &compiled);
|
||||
static void write(GeneratedCodeUtils &code, const QQmlJSProgram &compiled);
|
||||
|
||||
private:
|
||||
static void writeUrl(GeneratedCodeUtils &code, const QQmlJSAotMethod &urlMethod);
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // CODEGENERATORWRITER_H
|
|
@ -1,130 +0,0 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the tools applications of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef GENERATEDCODEPRIMITIVES_H
|
||||
#define GENERATEDCODEPRIMITIVES_H
|
||||
|
||||
#include <QtCore/qstring.h>
|
||||
#include <QtCore/qstack.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
// holds generated code for header and implementation files
|
||||
struct GeneratedCode
|
||||
{
|
||||
QString header;
|
||||
QString implementation;
|
||||
};
|
||||
|
||||
// utility class that provides pretty-printing of the generated code into the
|
||||
// GeneratedCode buffer
|
||||
struct GeneratedCodeUtils
|
||||
{
|
||||
GeneratedCode &m_code; // buffer
|
||||
|
||||
QStack<QString> memberNamespaceStack; // member names scopes e.g. MyClass::MySubclass::
|
||||
int headerIndent = 0; // header indentation level
|
||||
int implIndent = 0; // implementation indentation level
|
||||
|
||||
GeneratedCodeUtils(GeneratedCode &code) : m_code(code) { }
|
||||
|
||||
// manages current scope of the generated code, which is necessary for
|
||||
// implementation file generation. Example:
|
||||
// class MyClass { MyClass(); }; - in header
|
||||
// MyClass::MyClass() {} - in implementation file
|
||||
// MemberNamespaceScope exists to be able to record and use "MyClass::"
|
||||
struct MemberNamespaceScope
|
||||
{
|
||||
GeneratedCodeUtils &m_code;
|
||||
MemberNamespaceScope(GeneratedCodeUtils &code, const QString &str) : m_code(code)
|
||||
{
|
||||
m_code.memberNamespaceStack.push(str);
|
||||
}
|
||||
~MemberNamespaceScope() { m_code.memberNamespaceStack.pop(); }
|
||||
};
|
||||
|
||||
// manages current indentation scope: upon creation, increases current
|
||||
// scope, which is decreased back upon deletion. this is used by append*
|
||||
// functions that work with GeneratedCode::header to correctly indent the
|
||||
// input
|
||||
struct HeaderIndentationScope
|
||||
{
|
||||
GeneratedCodeUtils &m_code;
|
||||
HeaderIndentationScope(GeneratedCodeUtils &code) : m_code(code) { ++m_code.headerIndent; }
|
||||
~HeaderIndentationScope() { --m_code.headerIndent; }
|
||||
};
|
||||
|
||||
// manages current indentation scope: upon creation, increases current
|
||||
// scope, which is decreased back upon deletion. this is used by append*
|
||||
// functions that work with GeneratedCode::implementation to correctly
|
||||
// indent the input
|
||||
struct ImplIndentationScope
|
||||
{
|
||||
GeneratedCodeUtils &m_code;
|
||||
ImplIndentationScope(GeneratedCodeUtils &code) : m_code(code) { ++m_code.implIndent; }
|
||||
~ImplIndentationScope() { --m_code.implIndent; }
|
||||
};
|
||||
|
||||
// appends string \a what with extra indentation \a extraIndent to current
|
||||
// GeneratedCode::header string
|
||||
template<typename String>
|
||||
void appendToHeader(const String &what, int extraIndent = 0)
|
||||
{
|
||||
constexpr char16_t newLine[] = u"\n";
|
||||
m_code.header += QString((headerIndent + extraIndent) * 4, u' ') + what + newLine;
|
||||
}
|
||||
|
||||
// appends string \a what with extra indentation \a extraIndent to current
|
||||
// GeneratedCode::implementation string
|
||||
template<typename String>
|
||||
void appendToImpl(const String &what, int extraIndent = 0)
|
||||
{
|
||||
constexpr char16_t newLine[] = u"\n";
|
||||
m_code.implementation += QString((implIndent + extraIndent) * 4, u' ') + what + newLine;
|
||||
}
|
||||
|
||||
// appends string \a what with extra indentation \a extraIndent to current
|
||||
// GeneratedCode::implementation string. this is a special case function
|
||||
// that expects \a what to be a function signature as \a what is prepended
|
||||
// with member scope related text. for example, string "foo()" is converted
|
||||
// to string "MyClass::foo()" before append
|
||||
template<typename String>
|
||||
void appendSignatureToImpl(const String &what, int extraIndent = 0)
|
||||
{
|
||||
constexpr char16_t newLine[] = u"\n";
|
||||
QString signatureScope;
|
||||
for (const auto &subScope : memberNamespaceStack)
|
||||
signatureScope += subScope + u"::";
|
||||
m_code.implementation +=
|
||||
signatureScope + QString((implIndent + extraIndent) * 4, u' ') + what + newLine;
|
||||
}
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // GENERATEDCODEPRIMITIVES_H
|
|
@ -29,7 +29,6 @@
|
|||
#ifndef QML2CPPCONTEXT_H
|
||||
#define QML2CPPCONTEXT_H
|
||||
|
||||
#include "prototype/qmlcompiler.h"
|
||||
#include "qmltctyperesolver.h"
|
||||
|
||||
#include <private/qqmljsdiagnosticmessage_p.h>
|
||||
|
|
|
@ -1,173 +0,0 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the tools applications of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QMLCOMPILER_H
|
||||
#define QMLCOMPILER_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists purely as an
|
||||
// implementation detail. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include <QtCore/qstring.h>
|
||||
#include <QtCore/qstringlist.h>
|
||||
|
||||
#include <private/qqmljscompiler_p.h>
|
||||
#include <private/qqmljsmetatypes_p.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
// TODO: rename the classes into Qmltc* pattern
|
||||
|
||||
// Below are the classes that represent a compiled QML types in a string data
|
||||
// form. These classes should be used to generate C++ code.
|
||||
|
||||
// Represents QML->C++ compiled enumeration type
|
||||
struct QQmlJSAotEnum
|
||||
{
|
||||
QString cppType; // C++ type of enum
|
||||
QStringList keys; // enumerator
|
||||
QStringList values; // enumerator value
|
||||
QString ownMocLine; // special MOC line that follows enum declaration
|
||||
|
||||
QQmlJSAotEnum() = default;
|
||||
QQmlJSAotEnum(const QString &t, const QStringList &ks, const QStringList &vs, const QString &l)
|
||||
: cppType(t), keys(ks), values(vs), ownMocLine(l)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Represents C++ member variable
|
||||
struct QQmlJSAotVariable
|
||||
{
|
||||
QString cppType; // C++ type of a variable
|
||||
QString name; // variable name
|
||||
QString defaultValue; // optional default value
|
||||
|
||||
QQmlJSAotVariable() = default;
|
||||
QQmlJSAotVariable(const QString &t, const QString &n, const QString &v)
|
||||
: cppType(t), name(n), defaultValue(v)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct QQmlJSAotProperty : QQmlJSAotVariable
|
||||
{
|
||||
QString containingClass;
|
||||
QString signalName;
|
||||
|
||||
QQmlJSAotProperty() = default;
|
||||
QQmlJSAotProperty(const QString t, const QString &n, const QString &c, const QString &s)
|
||||
: QQmlJSAotVariable(t, n, QString()), containingClass(c), signalName(s)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct QQmlJSAotMethodBase
|
||||
{
|
||||
QString returnType; // C++ return type
|
||||
QString name; // C++ function name
|
||||
QList<QQmlJSAotVariable> parameterList; // C++ function parameter list
|
||||
QStringList body; // C++ code of function body by line
|
||||
QStringList declPreambles; // e.g. "static" keyword
|
||||
QStringList modifiers; // e.g. cv-qualifiers, ref-qualifier, noexcept, attributes
|
||||
|
||||
// TODO: these are only needed for Component.onCompleted -- any better way?
|
||||
QStringList firstLines; // C++ to run at the very beginning of a function
|
||||
QStringList lastLines; // C++ to run at the very end of a function
|
||||
|
||||
QQmlJSMetaMethod::Access access = QQmlJSMetaMethod::Public; // access specifier
|
||||
};
|
||||
|
||||
// Represents QML->C++ compiled member function
|
||||
struct QQmlJSAotMethod : QQmlJSAotMethodBase
|
||||
{
|
||||
QQmlJSMetaMethod::Type type = QQmlJSMetaMethod::Method; // Qt function type
|
||||
bool userVisible = false; // tells if a function is prioritized during the output generation
|
||||
};
|
||||
|
||||
// Represents C++ special member function
|
||||
struct QQmlJSAotSpecialMethod : QQmlJSAotMethodBase
|
||||
{
|
||||
QStringList initializerList; // C++ ctor initializer list
|
||||
};
|
||||
|
||||
// Represents QML->C++ compiled class type that is used for C++ code generation
|
||||
struct QQmlJSAotObject
|
||||
{
|
||||
QString cppType; // C++ class name of the QML object
|
||||
QStringList baseClasses; // C++ class names of base classes
|
||||
// TODO: also add "creation string"?
|
||||
QStringList mocCode;
|
||||
QStringList otherCode; // code that doesn't fit any category, e.g. friend declarations
|
||||
|
||||
// TODO: does it really need to be QHash and not QList?
|
||||
|
||||
// member types: enumerations and child types
|
||||
QList<QQmlJSAotEnum> enums;
|
||||
QList<QQmlJSAotObject> children; // these are pretty much always empty
|
||||
// special member functions
|
||||
QQmlJSAotSpecialMethod baselineCtor = {}; // does primary initialization
|
||||
QQmlJSAotMethod init = {}; // begins secondary initialization
|
||||
QQmlJSAotMethod endInit = {}; // ends initialization (with binding setup)
|
||||
QQmlJSAotMethod completeComponent = {}; // calls componentComplete()
|
||||
QQmlJSAotMethod finalizeComponent = {}; // invokes finalizer callbacks
|
||||
QQmlJSAotMethod handleOnCompleted = {}; // calls Component.onCompleted
|
||||
QQmlJSAotSpecialMethod externalCtor = {}; // calls baselineCtor, calls init
|
||||
std::optional<QQmlJSAotSpecialMethod> dtor = {};
|
||||
// member functions: methods, signals and slots
|
||||
QList<QQmlJSAotMethod> functions;
|
||||
// member variables
|
||||
QList<QQmlJSAotVariable> variables;
|
||||
// member properties
|
||||
QList<QQmlJSAotProperty> properties;
|
||||
|
||||
// TODO: only needed for binding callables - should be revisited
|
||||
bool ignoreInit = false; // specifies whether init and externalCtor should be ignored
|
||||
};
|
||||
|
||||
struct QQmlJSProgram
|
||||
{
|
||||
QList<QQmlJSAotObject> compiledObjects;
|
||||
QQmlJSAotMethod urlMethod;
|
||||
QString url;
|
||||
QString hPath;
|
||||
QString cppPath;
|
||||
QString outNamespace;
|
||||
QSet<QString> includes;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QMLCOMPILER_H
|
|
@ -74,6 +74,20 @@ static QString getFunctionCategory(const QmltcMethod &method)
|
|||
return category;
|
||||
}
|
||||
|
||||
static QString appendSpace(const QString &s)
|
||||
{
|
||||
if (s.isEmpty())
|
||||
return s;
|
||||
return s + u" ";
|
||||
}
|
||||
|
||||
static QString prependSpace(const QString &s)
|
||||
{
|
||||
if (s.isEmpty())
|
||||
return s;
|
||||
return u" " + s;
|
||||
}
|
||||
|
||||
static std::pair<QString, QString> functionSignatures(const QmltcMethodBase &method)
|
||||
{
|
||||
const QString name = method.name;
|
||||
|
@ -89,11 +103,18 @@ static std::pair<QString, QString> functionSignatures(const QmltcMethodBase &met
|
|||
headerParamList.back() += u" = " + variable.defaultValue;
|
||||
}
|
||||
|
||||
const QString headerSignature = name + u"(" + headerParamList.join(u", "_qs) + u")";
|
||||
const QString cppSignature = name + u"(" + cppParamList.join(u", "_qs) + u")";
|
||||
const QString headerSignature = name + u"(" + headerParamList.join(u", "_qs) + u")"
|
||||
+ prependSpace(method.modifiers.join(u" "));
|
||||
const QString cppSignature = name + u"(" + cppParamList.join(u", "_qs) + u")"
|
||||
+ prependSpace(method.modifiers.join(u" "));
|
||||
return { headerSignature, cppSignature };
|
||||
}
|
||||
|
||||
static QString functionReturnType(const QmltcMethod &m)
|
||||
{
|
||||
return appendSpace(m.declarationPrefixes.join(u" "_qs)) + m.returnType;
|
||||
}
|
||||
|
||||
void QmltcCodeWriter::writeGlobalHeader(QmltcOutputWrapper &code, const QString &sourcePath,
|
||||
const QString &hPath, const QString &cppPath,
|
||||
const QString &outNamespace,
|
||||
|
@ -129,14 +150,18 @@ void QmltcCodeWriter::writeGlobalHeader(QmltcOutputWrapper &code, const QString
|
|||
for (const auto &requiredInclude : requiredCppIncludes)
|
||||
code.rawAppendToHeader(u"#include \"" + requiredInclude + u"\"");
|
||||
code.rawAppendToHeader(u"// END(custom_cpp_includes)");
|
||||
code.rawAppendToHeader(u"// qmltc support library:");
|
||||
code.rawAppendToHeader(u"#include <private/qqmltcobjectcreationhelper_p.h>");
|
||||
|
||||
code.rawAppendToCpp(u"#include \"" + hPath + u"\""); // include own .h file
|
||||
code.rawAppendToCpp(u"// qmltc support library:");
|
||||
code.rawAppendToCpp(u"#include <private/qqmlcppbinding_p.h>"); // QmltcSupportLib
|
||||
code.rawAppendToCpp(u"#include <private/qqmlcpponassignment_p.h>"); // QmltcSupportLib
|
||||
|
||||
code.rawAppendToCpp(u""); // blank line
|
||||
code.rawAppendToCpp(u"#include <private/qqmlobjectcreator_p.h>"); // createComponent()
|
||||
code.rawAppendToCpp(u"#include <private/qqmlcomponent_p.h>"); // QQmlComponentPrivate::get()
|
||||
|
||||
code.rawAppendToCpp(u"");
|
||||
code.rawAppendToCpp(u"#include <private/qobject_p.h>"); // NB: for private properties
|
||||
code.rawAppendToCpp(u"#include <private/qqmlglobal_p.h>"); // QQml_setParent_noEvent()
|
||||
code.rawAppendToCpp(u"#include <private/qqmlobjectcreator_p.h>"); // for finalize callbacks
|
||||
|
||||
code.rawAppendToCpp(u""); // blank line
|
||||
code.rawAppendToCpp(u"QT_USE_NAMESPACE // avoid issues with QT_NAMESPACE");
|
||||
|
@ -187,10 +212,6 @@ void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcProgram &progra
|
|||
{
|
||||
writeGlobalHeader(code, program.url, program.hPath, program.cppPath, program.outNamespace,
|
||||
program.includes);
|
||||
// TODO: keep the "NOT IMPLEMENTED" as long as we don't actually compile
|
||||
// useful code
|
||||
code.rawAppendToHeader(u"/* QMLTC: NOT IMPLEMENTED */");
|
||||
code.rawAppendToCpp(u"/* QMLTC: NOT IMPLEMENTED */");
|
||||
|
||||
// url method comes first
|
||||
writeUrl(code, program.urlMethod);
|
||||
|
@ -207,12 +228,36 @@ void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcProgram &progra
|
|||
writeToFile(program.cppPath, code.code().cpp.toUtf8());
|
||||
}
|
||||
|
||||
template<typename Predicate>
|
||||
static void dumpFunctions(QmltcOutputWrapper &code, const QList<QmltcMethod> &functions,
|
||||
Predicate pred)
|
||||
{
|
||||
// functions are _ordered_ by access and kind. ordering is important to
|
||||
// provide consistent output
|
||||
QMap<QString, QList<const QmltcMethod *>> orderedFunctions;
|
||||
for (const auto &function : functions) {
|
||||
if (pred(function))
|
||||
orderedFunctions[getFunctionCategory(function)].append(std::addressof(function));
|
||||
}
|
||||
|
||||
for (auto it = orderedFunctions.cbegin(); it != orderedFunctions.cend(); ++it) {
|
||||
code.rawAppendToHeader(it.key() + u":", -1);
|
||||
for (const QmltcMethod *function : qAsConst(it.value()))
|
||||
QmltcCodeWriter::write(code, *function);
|
||||
}
|
||||
}
|
||||
|
||||
void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcType &type)
|
||||
{
|
||||
const auto constructClassString = [&]() {
|
||||
QString str = u"class " + type.cppType;
|
||||
if (!type.baseClasses.isEmpty())
|
||||
str += u" : public " + type.baseClasses.join(u", public "_qs);
|
||||
QStringList nonEmptyBaseClasses;
|
||||
nonEmptyBaseClasses.reserve(type.baseClasses.size());
|
||||
std::copy_if(type.baseClasses.cbegin(), type.baseClasses.cend(),
|
||||
std::back_inserter(nonEmptyBaseClasses),
|
||||
[](const QString &entry) { return !entry.isEmpty(); });
|
||||
if (!nonEmptyBaseClasses.isEmpty())
|
||||
str += u" : public " + nonEmptyBaseClasses.join(u", public "_qs);
|
||||
return str;
|
||||
};
|
||||
|
||||
|
@ -233,42 +278,70 @@ void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcType &type)
|
|||
QmltcOutputWrapper::HeaderIndentationScope headerIndent(&code);
|
||||
Q_UNUSED(headerIndent);
|
||||
|
||||
// special member functions
|
||||
code.rawAppendToHeader(u"protected:", -1);
|
||||
write(code, type.basicCtor);
|
||||
write(code, type.init);
|
||||
write(code, type.finalize);
|
||||
// NB: externalCtor might not be public when the type is QML singleton
|
||||
code.rawAppendToHeader(getFunctionCategory(type.fullCtor) + u":", -1);
|
||||
write(code, type.fullCtor);
|
||||
// first, write user-visible code, then everything else. someone might
|
||||
// want to look at the generated code, so let's make an effort when
|
||||
// writing it down
|
||||
|
||||
code.rawAppendToHeader(u"/* ----------------- */");
|
||||
code.rawAppendToHeader(u"/* External C++ API */");
|
||||
code.rawAppendToHeader(u"public:", -1);
|
||||
|
||||
// NB: when non-document root, the externalCtor won't be public - but we
|
||||
// really don't care about the output format of such types
|
||||
if (!type.ignoreInit && type.externalCtor.access == QQmlJSMetaMethod::Public) {
|
||||
// TODO: ignoreInit must be eliminated
|
||||
|
||||
QmltcCodeWriter::write(code, type.externalCtor);
|
||||
}
|
||||
|
||||
// dtor
|
||||
if (type.dtor)
|
||||
QmltcCodeWriter::write(code, *type.dtor);
|
||||
|
||||
// enums
|
||||
if (!type.enums.isEmpty()) {
|
||||
code.rawAppendToHeader(u""); // blank line
|
||||
code.rawAppendToHeader(u"public:", -1);
|
||||
}
|
||||
for (const auto &enumeration : qAsConst(type.enums))
|
||||
write(code, enumeration);
|
||||
QmltcCodeWriter::write(code, enumeration);
|
||||
|
||||
// child types
|
||||
if (!type.children.isEmpty())
|
||||
code.rawAppendToHeader(u""); // blank line
|
||||
for (const auto &child : qAsConst(type.children))
|
||||
write(code, child);
|
||||
// visible functions
|
||||
const auto isUserVisibleFunction = [](const QmltcMethod &function) {
|
||||
return function.userVisible;
|
||||
};
|
||||
dumpFunctions(code, type.functions, isUserVisibleFunction);
|
||||
|
||||
// functions (special case due to functions/signals/slots, etc.)
|
||||
QHash<QString, QList<const QmltcMethod *>> functionsByCategory;
|
||||
for (const auto &function : qAsConst(type.functions))
|
||||
functionsByCategory[getFunctionCategory(function)].append(&function);
|
||||
code.rawAppendToHeader(u"/* ----------------- */");
|
||||
code.rawAppendToHeader(u""); // blank line
|
||||
code.rawAppendToHeader(u"/* Internal functionality (do NOT use it!) */");
|
||||
|
||||
if (!functionsByCategory.isEmpty())
|
||||
code.rawAppendToHeader(u""); // blank line
|
||||
for (auto it = functionsByCategory.cbegin(); it != functionsByCategory.cend(); ++it) {
|
||||
code.rawAppendToHeader(it.key() + u":", -1);
|
||||
for (const QmltcMethod *function : qAsConst(it.value()))
|
||||
write(code, *function);
|
||||
// below are the hidden parts of the type
|
||||
|
||||
// (rest of the) ctors
|
||||
if (type.ignoreInit) { // TODO: this branch should be eliminated
|
||||
Q_ASSERT(type.baselineCtor.access == QQmlJSMetaMethod::Public);
|
||||
code.rawAppendToHeader(u"public:", -1);
|
||||
QmltcCodeWriter::write(code, type.baselineCtor);
|
||||
} else {
|
||||
code.rawAppendToHeader(u"protected:", -1);
|
||||
if (type.externalCtor.access != QQmlJSMetaMethod::Public) {
|
||||
Q_ASSERT(type.externalCtor.access == QQmlJSMetaMethod::Protected);
|
||||
QmltcCodeWriter::write(code, type.externalCtor);
|
||||
}
|
||||
QmltcCodeWriter::write(code, type.baselineCtor);
|
||||
QmltcCodeWriter::write(code, type.init);
|
||||
QmltcCodeWriter::write(code, type.endInit);
|
||||
QmltcCodeWriter::write(code, type.completeComponent);
|
||||
QmltcCodeWriter::write(code, type.finalizeComponent);
|
||||
QmltcCodeWriter::write(code, type.handleOnCompleted);
|
||||
|
||||
// code.rawAppendToHeader(u"public:", -1);
|
||||
}
|
||||
|
||||
// children
|
||||
for (const auto &child : qAsConst(type.children))
|
||||
QmltcCodeWriter::write(code, child);
|
||||
|
||||
// (non-visible) functions
|
||||
dumpFunctions(code, type.functions, std::not_fn(isUserVisibleFunction));
|
||||
|
||||
// variables and properties
|
||||
if (!type.variables.isEmpty() || !type.properties.isEmpty()) {
|
||||
code.rawAppendToHeader(u""); // blank line
|
||||
|
@ -314,10 +387,7 @@ void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcMethod &method)
|
|||
{
|
||||
const auto [hSignature, cppSignature] = functionSignatures(method);
|
||||
// Note: augment return type with preambles in declaration
|
||||
QString prefix = method.declarationPrefixes.join(u' ');
|
||||
if (!prefix.isEmpty())
|
||||
prefix.append(u' ');
|
||||
code.rawAppendToHeader(prefix + method.returnType + u" " + hSignature + u";");
|
||||
code.rawAppendToHeader(functionReturnType(method) + u" " + hSignature + u";");
|
||||
|
||||
// do not generate method implementation if it is a signal
|
||||
const auto methodType = method.type;
|
||||
|
@ -329,39 +399,65 @@ void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcMethod &method)
|
|||
{
|
||||
QmltcOutputWrapper::CppIndentationScope cppIndent(&code);
|
||||
Q_UNUSED(cppIndent);
|
||||
for (const QString &line : qAsConst(method.firstLines))
|
||||
code.rawAppendToCpp(line);
|
||||
for (const QString &line : qAsConst(method.body))
|
||||
code.rawAppendToCpp(line);
|
||||
for (const QString &line : qAsConst(method.lastLines))
|
||||
code.rawAppendToCpp(line);
|
||||
}
|
||||
code.rawAppendToCpp(u"}");
|
||||
}
|
||||
}
|
||||
|
||||
void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcCtor &ctor)
|
||||
template<typename WriteInitialization>
|
||||
static void writeSpecialMethod(QmltcOutputWrapper &code, const QmltcMethodBase &specialMethod,
|
||||
WriteInitialization writeInit)
|
||||
{
|
||||
const auto [hSignature, cppSignature] = functionSignatures(ctor);
|
||||
QString prefix = ctor.declarationPrefixes.join(u' ');
|
||||
if (!prefix.isEmpty())
|
||||
prefix.append(u' ');
|
||||
code.rawAppendToHeader(prefix + hSignature + u";");
|
||||
const auto [hSignature, cppSignature] = functionSignatures(specialMethod);
|
||||
code.rawAppendToHeader(hSignature + u";");
|
||||
|
||||
code.rawAppendToCpp(u""); // blank line
|
||||
code.rawAppendSignatureToCpp(cppSignature);
|
||||
if (!ctor.initializerList.isEmpty()) {
|
||||
code.rawAppendToCpp(u":", 1);
|
||||
// double \n to make separate initializer list lines stand out more
|
||||
code.rawAppendToCpp(
|
||||
ctor.initializerList.join(u",\n\n" + u" "_qs.repeated(code.cppIndent + 1)), 1);
|
||||
}
|
||||
|
||||
writeInit(specialMethod);
|
||||
|
||||
code.rawAppendToCpp(u"{");
|
||||
{
|
||||
QmltcOutputWrapper::CppIndentationScope cppIndent(&code);
|
||||
Q_UNUSED(cppIndent);
|
||||
for (const QString &line : qAsConst(ctor.body))
|
||||
for (const QString &line : qAsConst(specialMethod.firstLines))
|
||||
code.rawAppendToCpp(line);
|
||||
for (const QString &line : qAsConst(specialMethod.body))
|
||||
code.rawAppendToCpp(line);
|
||||
for (const QString &line : qAsConst(specialMethod.lastLines))
|
||||
code.rawAppendToCpp(line);
|
||||
}
|
||||
code.rawAppendToCpp(u"}");
|
||||
}
|
||||
|
||||
void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcCtor &ctor)
|
||||
{
|
||||
const auto writeInitializerList = [&](const QmltcMethodBase &ctorBase) {
|
||||
auto ctor = static_cast<const QmltcCtor &>(ctorBase);
|
||||
if (!ctor.initializerList.isEmpty()) {
|
||||
code.rawAppendToCpp(u":", 1);
|
||||
// double \n to make separate initializer list lines stand out more
|
||||
code.rawAppendToCpp(
|
||||
ctor.initializerList.join(u",\n\n" + u" "_qs.repeated(code.cppIndent + 1)),
|
||||
1);
|
||||
}
|
||||
};
|
||||
|
||||
writeSpecialMethod(code, ctor, writeInitializerList);
|
||||
}
|
||||
|
||||
void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcDtor &dtor)
|
||||
{
|
||||
const auto noop = [](const QmltcMethodBase &) {};
|
||||
writeSpecialMethod(code, dtor, noop);
|
||||
}
|
||||
|
||||
void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcVariable &var)
|
||||
{
|
||||
const QString optionalPart = var.defaultValue.isEmpty() ? u""_qs : u" = " + var.defaultValue;
|
||||
|
@ -370,7 +466,7 @@ void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcVariable &var)
|
|||
|
||||
void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcProperty &prop)
|
||||
{
|
||||
Q_ASSERT(prop.defaultValue.isEmpty()); // we don't support it yet
|
||||
Q_ASSERT(prop.defaultValue.isEmpty()); // we don't support it yet (or at all?)
|
||||
code.rawAppendToHeader(u"Q_OBJECT_BINDABLE_PROPERTY(%1, %2, %3, &%1::%4)"_qs.arg(
|
||||
prop.containingClass, prop.cppType, prop.name, prop.signalName));
|
||||
}
|
||||
|
@ -382,14 +478,12 @@ void QmltcCodeWriter::writeUrl(QmltcOutputWrapper &code, const QmltcMethod &urlM
|
|||
const auto [hSignature, _] = functionSignatures(urlMethod);
|
||||
Q_UNUSED(_);
|
||||
// Note: augment return type with preambles in declaration
|
||||
QString prefix = urlMethod.declarationPrefixes.join(u' ');
|
||||
if (!prefix.isEmpty())
|
||||
prefix.append(u' ');
|
||||
code.rawAppendToCpp(prefix + urlMethod.returnType + u" " + hSignature);
|
||||
code.rawAppendToCpp(functionReturnType(urlMethod) + hSignature);
|
||||
code.rawAppendToCpp(u"{");
|
||||
{
|
||||
QmltcOutputWrapper::CppIndentationScope cppIndent(&code);
|
||||
Q_UNUSED(cppIndent);
|
||||
Q_ASSERT(urlMethod.firstLines.isEmpty() && urlMethod.lastLines.isEmpty());
|
||||
for (const QString &line : qAsConst(urlMethod.body))
|
||||
code.rawAppendToCpp(line);
|
||||
}
|
||||
|
|
|
@ -49,9 +49,11 @@ struct QmltcCodeWriter
|
|||
static void write(QmltcOutputWrapper &code, const QmltcEnum &enumeration);
|
||||
static void write(QmltcOutputWrapper &code, const QmltcMethod &method);
|
||||
static void write(QmltcOutputWrapper &code, const QmltcCtor &ctor);
|
||||
static void write(QmltcOutputWrapper &code, const QmltcDtor &dtor);
|
||||
static void write(QmltcOutputWrapper &code, const QmltcVariable &var);
|
||||
static void write(QmltcOutputWrapper &code, const QmltcProperty &prop);
|
||||
|
||||
private:
|
||||
static void writeUrl(QmltcOutputWrapper &code, const QmltcMethod &urlMethod); // special
|
||||
};
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ void QmltcCompiler::compileType(QmltcType ¤t, const QQmlJSScope::ConstPtr
|
|||
|
||||
current.baseClasses = { baseClass };
|
||||
if (!documentRoot) {
|
||||
// make document root a friend to allow it to access init and finalize
|
||||
// make document root a friend to allow it to access init and endInit
|
||||
current.otherCode << u"friend class %1;"_qs.arg(rootType->internalName());
|
||||
} else {
|
||||
// make QQmltcObjectCreationBase<DocumentRoot> a friend to allow it to
|
||||
|
@ -147,68 +147,70 @@ void QmltcCompiler::compileType(QmltcType ¤t, const QQmlJSScope::ConstPtr
|
|||
};
|
||||
|
||||
// add special member functions
|
||||
current.basicCtor.access = QQmlJSMetaMethod::Protected;
|
||||
current.baselineCtor.access = QQmlJSMetaMethod::Protected;
|
||||
current.init.access = QQmlJSMetaMethod::Protected;
|
||||
current.finalize.access = QQmlJSMetaMethod::Protected;
|
||||
current.fullCtor.access = QQmlJSMetaMethod::Public;
|
||||
current.endInit.access = QQmlJSMetaMethod::Protected;
|
||||
current.externalCtor.access = QQmlJSMetaMethod::Public;
|
||||
|
||||
current.basicCtor.name = current.cppType;
|
||||
current.fullCtor.name = current.cppType;
|
||||
current.baselineCtor.name = current.cppType;
|
||||
current.externalCtor.name = current.cppType;
|
||||
current.init.name = u"qmltc_init"_qs;
|
||||
current.init.returnType = u"QQmlRefPointer<QQmlContextData>"_qs;
|
||||
current.finalize.name = u"qmltc_finalize"_qs;
|
||||
current.finalize.returnType = u"void"_qs;
|
||||
current.endInit.name = u"qmltc_finalize"_qs;
|
||||
current.endInit.returnType = u"void"_qs;
|
||||
|
||||
QmltcVariable creator(u"QQmltcObjectCreationHelper*"_qs, u"creator"_qs);
|
||||
QmltcVariable engine(u"QQmlEngine*"_qs, u"engine"_qs);
|
||||
QmltcVariable parent(u"QObject*"_qs, u"parent"_qs, u"nullptr"_qs);
|
||||
current.basicCtor.parameterList = { parent };
|
||||
current.baselineCtor.parameterList = { parent };
|
||||
QmltcVariable ctxtdata(u"const QQmlRefPointer<QQmlContextData>&"_qs, u"parentContext"_qs);
|
||||
QmltcVariable finalizeFlag(u"bool"_qs, u"canFinalize"_qs);
|
||||
if (documentRoot) {
|
||||
current.fullCtor.parameterList = { engine, parent };
|
||||
current.externalCtor.parameterList = { engine, parent };
|
||||
current.init.parameterList = { creator, engine, ctxtdata, finalizeFlag };
|
||||
current.finalize.parameterList = { creator, engine, finalizeFlag };
|
||||
current.endInit.parameterList = { creator, engine, finalizeFlag };
|
||||
} else {
|
||||
current.fullCtor.parameterList = { creator, engine, parent };
|
||||
current.externalCtor.parameterList = { creator, engine, parent };
|
||||
current.init.parameterList = { creator, engine, ctxtdata };
|
||||
current.finalize.parameterList = { creator, engine };
|
||||
current.endInit.parameterList = { creator, engine };
|
||||
}
|
||||
|
||||
current.fullCtor.initializerList = { current.basicCtor.name + u"(" + parent.name + u")" };
|
||||
current.externalCtor.initializerList = { current.baselineCtor.name + u"(" + parent.name
|
||||
+ u")" };
|
||||
if (baseTypeIsCompiledQml) {
|
||||
// call parent's (QML type's) basic ctor from this. that one will take
|
||||
// care about QObject::setParent()
|
||||
current.basicCtor.initializerList = { baseClass + u"(" + parent.name + u")" };
|
||||
current.baselineCtor.initializerList = { baseClass + u"(" + parent.name + u")" };
|
||||
} else {
|
||||
// default call to ctor is enough, but QQml_setParent_noEvent() is
|
||||
// needed (note: faster? version of QObject::setParent())
|
||||
current.basicCtor.body << u"QQml_setParent_noEvent(this, " + parent.name + u");";
|
||||
current.baselineCtor.body << u"QQml_setParent_noEvent(this, " + parent.name + u");";
|
||||
}
|
||||
|
||||
QmltcCodeGenerator generator { rootType };
|
||||
|
||||
// compilation stub:
|
||||
current.fullCtor.body << u"Q_UNUSED(engine);"_qs;
|
||||
current.finalize.body << u"Q_UNUSED(engine);"_qs;
|
||||
current.finalize.body << u"Q_UNUSED(creator);"_qs;
|
||||
current.externalCtor.body << u"Q_UNUSED(engine);"_qs;
|
||||
current.endInit.body << u"Q_UNUSED(engine);"_qs;
|
||||
current.endInit.body << u"Q_UNUSED(creator);"_qs;
|
||||
if (documentRoot) {
|
||||
current.fullCtor.body << u"// document root:"_qs;
|
||||
current.externalCtor.body << u"// document root:"_qs;
|
||||
// if it's document root, we want to create our QQmltcObjectCreationBase
|
||||
// that would store all the created objects
|
||||
current.fullCtor.body << u"QQmltcObjectCreationBase<%1> objectHolder;"_qs.arg(
|
||||
current.externalCtor.body << u"QQmltcObjectCreationBase<%1> objectHolder;"_qs.arg(
|
||||
type->internalName());
|
||||
current.fullCtor.body << u"QQmltcObjectCreationHelper creator = objectHolder.view();"_qs;
|
||||
current.externalCtor.body
|
||||
<< u"QQmltcObjectCreationHelper creator = objectHolder.view();"_qs;
|
||||
// now call init
|
||||
current.fullCtor.body << current.init.name
|
||||
current.externalCtor.body << current.init.name
|
||||
+ u"(&creator, engine, QQmlContextData::get(engine->rootContext()), /* "
|
||||
u"finalize */ true);";
|
||||
u"endInit */ true);";
|
||||
|
||||
current.finalize.body << u"Q_UNUSED(canFinalize);"_qs;
|
||||
current.endInit.body << u"Q_UNUSED(canFinalize);"_qs;
|
||||
} else {
|
||||
current.fullCtor.body << u"// not document root:"_qs;
|
||||
current.externalCtor.body << u"// not document root:"_qs;
|
||||
// just call init, we don't do any setup here otherwise
|
||||
current.fullCtor.body << current.init.name
|
||||
current.externalCtor.body << current.init.name
|
||||
+ u"(creator, engine, QQmlData::get(parent)->outerContext);";
|
||||
}
|
||||
|
||||
|
@ -353,9 +355,9 @@ void QmltcCompiler::compileProperty(QmltcType ¤t, const QQmlJSMetaProperty
|
|||
const QString storageName = variableName + u"_storage";
|
||||
current.variables.emplaceBack(u"QList<" + p.type()->internalName() + u" *>", storageName,
|
||||
QString());
|
||||
current.basicCtor.initializerList.emplaceBack(variableName + u"(" + underlyingType
|
||||
+ u"(this, std::addressof(" + storageName
|
||||
+ u")))");
|
||||
current.baselineCtor.initializerList.emplaceBack(variableName + u"(" + underlyingType
|
||||
+ u"(this, std::addressof(" + storageName
|
||||
+ u")))");
|
||||
}
|
||||
|
||||
// along with property, also add relevant moc code, so that we can use the
|
||||
|
|
|
@ -147,7 +147,7 @@ QmltcCodeGenerator::generate_qmlContextSetup(QmltcType ¤t, const QQmlJSSco
|
|||
current.init.body << u"// 4. call finalize in the document root"_qs;
|
||||
current.init.body << u"if (canFinalize) {"_qs;
|
||||
current.init.body << QStringLiteral(" %1(creator, engine, /* finalize */ true);")
|
||||
.arg(current.finalize.name);
|
||||
.arg(current.endInit.name);
|
||||
current.init.body << u"}"_qs;
|
||||
}
|
||||
current.init.body << u"return context;"_qs;
|
||||
|
|
|
@ -92,6 +92,12 @@ struct QmltcMethodBase
|
|||
QStringList body; // C++ function code
|
||||
QQmlJSMetaMethod::Access access = QQmlJSMetaMethod::Public; // access specifier
|
||||
QStringList declarationPrefixes;
|
||||
QStringList modifiers; // cv-qualifiers, ref-qualifier, noexcept, attributes
|
||||
|
||||
// TODO: these are only needed for Component.onCompleted/onDestruction. this
|
||||
// has to be re-written anyhow later
|
||||
QStringList firstLines; // C++ to run at the very beginning of a function
|
||||
QStringList lastLines; // C++ to run at the very end of a function
|
||||
};
|
||||
|
||||
// Represents QML -> C++ compiled function
|
||||
|
@ -99,6 +105,9 @@ struct QmltcMethod : QmltcMethodBase
|
|||
{
|
||||
QString returnType; // C++ return type
|
||||
QQmlJSMetaMethod::Type type = QQmlJSMetaMethod::Method; // Qt function type
|
||||
|
||||
// TODO: should be a better way to handle this
|
||||
bool userVisible = false; // tells if a function is prioritized during the output generation
|
||||
};
|
||||
|
||||
// Represents C++ ctor of a type
|
||||
|
@ -107,6 +116,11 @@ struct QmltcCtor : QmltcMethodBase
|
|||
QStringList initializerList; // C++ ctor's initializer list
|
||||
};
|
||||
|
||||
// Represents C++ dtor of a type
|
||||
struct QmltcDtor : QmltcMethodBase
|
||||
{
|
||||
};
|
||||
|
||||
// Represents QML -> C++ compiled type
|
||||
struct QmltcType
|
||||
{
|
||||
|
@ -120,10 +134,15 @@ struct QmltcType
|
|||
QList<QmltcType> children; // these are pretty much always empty
|
||||
|
||||
// special member functions:
|
||||
QmltcCtor basicCtor = {}; // does basic contruction
|
||||
QmltcCtor fullCtor = {}; // calls basicCtor, calls init
|
||||
QmltcMethod init = {}; // starts object initialization (context setup), calls finalize
|
||||
QmltcMethod finalize = {}; // finalizes object (bindings, special interface calls, etc.)
|
||||
QmltcCtor baselineCtor {}; // does basic contruction
|
||||
QmltcCtor externalCtor {}; // calls basicCtor, calls init
|
||||
QmltcMethod init {}; // starts object initialization (context setup), calls finalize
|
||||
QmltcMethod endInit {}; // ends object initialization (with binding setup)
|
||||
QmltcMethod completeComponent {}; // calls componentComplete()
|
||||
QmltcMethod finalizeComponent {}; // calls componentFinalized()
|
||||
QmltcMethod handleOnCompleted {}; // calls Component.onCompleted
|
||||
|
||||
std::optional<QmltcDtor> dtor {};
|
||||
|
||||
// member functions: methods, signals and slots
|
||||
QList<QmltcMethod> functions;
|
||||
|
@ -133,6 +152,9 @@ struct QmltcType
|
|||
|
||||
// QML document root specific:
|
||||
std::optional<QmltcVariable> typeCount; // the number of QML types defined in a document
|
||||
|
||||
// TODO: only needed for binding callables - should not be needed, generally
|
||||
bool ignoreInit = false; // specifies whether init and externalCtor should be ignored
|
||||
};
|
||||
|
||||
// Represents whole QML program, compiled to C++
|
||||
|
|
Loading…
Reference in New Issue