diff options
Diffstat (limited to 'src/qml/compiler/qqmlirbuilder_p.h')
-rw-r--r-- | src/qml/compiler/qqmlirbuilder_p.h | 616 |
1 files changed, 410 insertions, 206 deletions
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h index 56724bcda5..ffd3ad72f7 100644 --- a/src/qml/compiler/qqmlirbuilder_p.h +++ b/src/qml/compiler/qqmlirbuilder_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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:LGPL$ -** 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 Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QQMLIRBUILDER_P_H #define QQMLIRBUILDER_P_H @@ -55,25 +19,22 @@ #include <private/qv4compiler_p.h> #include <private/qv4compileddata_p.h> #include <private/qqmljsmemorypool_p.h> +#include <private/qqmljsfixedpoolarray_p.h> #include <private/qv4codegen_p.h> #include <private/qv4compiler_p.h> #include <QTextStream> #include <QCoreApplication> -#ifndef V4_BOOTSTRAP -#include <private/qqmlpropertycache_p.h> -#endif - QT_BEGIN_NAMESPACE class QQmlPropertyCache; class QQmlContextData; class QQmlTypeNameCache; +struct QQmlIRLoader; namespace QmlIR { struct Document; -struct IRLoader; template <typename T> struct PoolList @@ -161,6 +122,13 @@ struct PoolList } struct Iterator { + // turn Iterator into a proper iterator + using iterator_category = std::forward_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T *; + using reference = T &; + T *ptr; explicit Iterator(T *p) : ptr(p) {} @@ -181,8 +149,15 @@ struct PoolList return *ptr; } - void operator++() { + Iterator& operator++() { + ptr = ptr->next; + return *this; + } + + Iterator operator++(int) { + Iterator that {ptr}; ptr = ptr->next; + return that; } bool operator==(const Iterator &rhs) const { @@ -192,73 +167,15 @@ struct PoolList bool operator!=(const Iterator &rhs) const { return ptr != rhs.ptr; } + + operator T *() { return ptr; } + operator const T *() const { return ptr; } }; Iterator begin() { return Iterator(first); } Iterator end() { return Iterator(nullptr); } -}; -template <typename T> -class FixedPoolArray -{ - T *data; -public: - int count = 0; - - FixedPoolArray() - : data(nullptr) - - {} - - void allocate(QQmlJS::MemoryPool *pool, int size) - { - count = size; - data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T))); - } - - void allocate(QQmlJS::MemoryPool *pool, const QVector<T> &vector) - { - count = vector.count(); - data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T))); - - if (QTypeInfo<T>::isComplex) { - for (int i = 0; i < count; ++i) - new (data + i) T(vector.at(i)); - } else { - memcpy(data, static_cast<const void*>(vector.constData()), count * sizeof(T)); - } - } - - template <typename Container> - void allocate(QQmlJS::MemoryPool *pool, const Container &container) - { - count = container.count(); - data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T))); - typename Container::ConstIterator it = container.constBegin(); - for (int i = 0; i < count; ++i) - new (data + i) T(*it++); - } - - const T &at(int index) const { - Q_ASSERT(index >= 0 && index < count); - return data[index]; - } - - T &operator[](int index) { - Q_ASSERT(index >= 0 && index < count); - return data[index]; - } - - - int indexOf(const T &value) const { - for (int i = 0; i < count; ++i) - if (data[i] == value) - return i; - return -1; - } - - const T *begin() const { return data; } - const T *end() const { return data + count; } + using iterator = Iterator; }; struct Object; @@ -282,22 +199,53 @@ struct Enum }; -struct SignalParameter : public QV4::CompiledData::Parameter +struct Parameter : public QV4::CompiledData::Parameter { - SignalParameter *next; + Parameter *next; + + template<typename IdGenerator> + static bool initType( + QV4::CompiledData::ParameterType *type, const IdGenerator &idGenerator, + const QQmlJS::AST::Type *annotation) + { + using Flag = QV4::CompiledData::ParameterType::Flag; + + if (!annotation) + return initType(type, QString(), idGenerator(QString()), Flag::NoFlag); + + const QString typeId = annotation->typeId->toString(); + const QString typeArgument = + annotation->typeArgument ? annotation->typeArgument->toString() : QString(); + + if (typeArgument.isEmpty()) + return initType(type, typeId, idGenerator(typeId), Flag::NoFlag); + + if (typeId == QLatin1String("list")) + return initType(type, typeArgument, idGenerator(typeArgument), Flag::List); + + const QString annotationString = annotation->toString(); + return initType(type, annotationString, idGenerator(annotationString), Flag::NoFlag); + } + + static QV4::CompiledData::CommonType stringToBuiltinType(const QString &typeName); + +private: + static bool initType( + QV4::CompiledData::ParameterType *paramType, const QString &typeName, + int typeNameIndex, QV4::CompiledData::ParameterType::Flag listFlag); }; struct Signal { int nameIndex; QV4::CompiledData::Location location; - PoolList<SignalParameter> *parameters; + PoolList<Parameter> *parameters; QStringList parameterStringList(const QV4::Compiler::StringTableGenerator *stringPool) const; int parameterCount() const { return parameters->count; } - PoolList<SignalParameter>::Iterator parametersBegin() const { return parameters->begin(); } - PoolList<SignalParameter>::Iterator parametersEnd() const { return parameters->end(); } + PoolList<Parameter>::Iterator parametersBegin() const { return parameters->begin(); } + PoolList<Parameter>::Iterator parametersEnd() const { return parameters->end(); } Signal *next; }; @@ -317,27 +265,38 @@ struct Binding : public QV4::CompiledData::Binding Binding *next; }; +struct InlineComponent : public QV4::CompiledData::InlineComponent +{ + InlineComponent *next; +}; + struct Alias : public QV4::CompiledData::Alias { Alias *next; }; +struct RequiredPropertyExtraData : public QV4::CompiledData::RequiredPropertyExtraData +{ + RequiredPropertyExtraData *next; +}; + struct Function { QV4::CompiledData::Location location; int nameIndex; quint32 index; // index in parsedQML::functions - FixedPoolArray<int> formals; + QQmlJS::FixedPoolArray<Parameter> formals; + QV4::CompiledData::ParameterType returnType; // --- QQmlPropertyCacheCreator interface - const int *formalsBegin() const { return formals.begin(); } - const int *formalsEnd() const { return formals.end(); } + const Parameter *formalsBegin() const { return formals.begin(); } + const Parameter *formalsEnd() const { return formals.end(); } // --- Function *next; }; -struct Q_QML_PRIVATE_EXPORT CompiledFunctionOrExpression +struct Q_QML_COMPILER_EXPORT CompiledFunctionOrExpression { CompiledFunctionOrExpression() {} @@ -348,7 +307,7 @@ struct Q_QML_PRIVATE_EXPORT CompiledFunctionOrExpression CompiledFunctionOrExpression *next = nullptr; }; -struct Q_QML_PRIVATE_EXPORT Object +struct Q_QML_COMPILER_EXPORT Object { Q_DECLARE_TR_FUNCTIONS(Object) public: @@ -374,6 +333,11 @@ public: int bindingCount() const { return bindings->count; } const Function *firstFunction() const { return functions->first; } int functionCount() const { return functions->count; } + const InlineComponent *inlineComponent() const { return inlineComponents->first; } + int inlineComponentCount() const { return inlineComponents->count; } + const RequiredPropertyExtraData *requiredPropertyExtraData() const {return requiredPropertyExtraDatas->first; } + int requiredPropertyExtraDataCount() const { return requiredPropertyExtraDatas->count; } + void simplifyRequiredProperties(); PoolList<Binding>::Iterator bindingsBegin() const { return bindings->begin(); } PoolList<Binding>::Iterator bindingsEnd() const { return bindings->end(); } @@ -387,18 +351,24 @@ public: PoolList<Signal>::Iterator signalsEnd() const { return qmlSignals->end(); } PoolList<Function>::Iterator functionsBegin() const { return functions->begin(); } PoolList<Function>::Iterator functionsEnd() const { return functions->end(); } + PoolList<InlineComponent>::Iterator inlineComponentsBegin() const { return inlineComponents->begin(); } + PoolList<InlineComponent>::Iterator inlineComponentsEnd() const { return inlineComponents->end(); } + PoolList<RequiredPropertyExtraData>::Iterator requiredPropertyExtraDataBegin() const {return requiredPropertyExtraDatas->begin(); } + PoolList<RequiredPropertyExtraData>::Iterator requiredPropertyExtraDataEnd() const {return requiredPropertyExtraDatas->end(); } // If set, then declarations for this object (and init bindings for these) should go into the // specified object. Used for declarations inside group properties. Object *declarationsOverride; - void init(QQmlJS::MemoryPool *pool, int typeNameIndex, int idIndex, const QQmlJS::AST::SourceLocation &location = QQmlJS::AST::SourceLocation()); + void init(QQmlJS::MemoryPool *pool, int typeNameIndex, int idIndex, const QV4::CompiledData::Location &location); QString appendEnum(Enum *enumeration); QString appendSignal(Signal *signal); - QString appendProperty(Property *prop, const QString &propertyName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation); - QString appendAlias(Alias *prop, const QString &aliasName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation); + QString appendProperty(Property *prop, const QString &propertyName, bool isDefaultProperty, const QQmlJS::SourceLocation &defaultToken, QQmlJS::SourceLocation *errorLocation); + QString appendAlias(Alias *prop, const QString &aliasName, bool isDefaultProperty, const QQmlJS::SourceLocation &defaultToken, QQmlJS::SourceLocation *errorLocation); void appendFunction(QmlIR::Function *f); + void appendInlineComponent(InlineComponent *ic); + void appendRequiredPropertyExtraData(RequiredPropertyExtraData *extraData); QString appendBinding(Binding *b, bool isListBinding); Binding *findBinding(quint32 nameIndex) const; @@ -407,14 +377,18 @@ public: QString bindingAsString(Document *doc, int scriptIndex) const; PoolList<CompiledFunctionOrExpression> *functionsAndExpressions; - FixedPoolArray<int> runtimeFunctionIndices; + QQmlJS::FixedPoolArray<int> runtimeFunctionIndices; - FixedPoolArray<quint32> namedObjectsInComponent; - int namedObjectsInComponentCount() const { return namedObjectsInComponent.count; } + QQmlJS::FixedPoolArray<quint32> namedObjectsInComponent; + int namedObjectsInComponentCount() const { return namedObjectsInComponent.size(); } const quint32 *namedObjectsInComponentTable() const { return namedObjectsInComponent.begin(); } + bool hasFlag(QV4::CompiledData::Object::Flag flag) const { return flags & flag; } + qint32 objectId() const { return id; } + bool hasAliasAsDefaultProperty() const { return defaultPropertyIsAlias; } + private: - friend struct IRLoader; + friend struct ::QQmlIRLoader; PoolList<Property> *properties; PoolList<Alias> *aliases; @@ -422,19 +396,72 @@ private: PoolList<Signal> *qmlSignals; PoolList<Binding> *bindings; PoolList<Function> *functions; + PoolList<InlineComponent> *inlineComponents; + PoolList<RequiredPropertyExtraData> *requiredPropertyExtraDatas; }; -struct Q_QML_PRIVATE_EXPORT Pragma +struct Q_QML_COMPILER_EXPORT Pragma { - enum PragmaType { - PragmaSingleton = 0x1 + enum PragmaType + { + Singleton, + Strict, + ListPropertyAssignBehavior, + ComponentBehavior, + FunctionSignatureBehavior, + NativeMethodBehavior, + ValueTypeBehavior, + Translator, + }; + + enum ListPropertyAssignBehaviorValue + { + Append, + Replace, + ReplaceIfNotDefault, + }; + + enum ComponentBehaviorValue + { + Unbound, + Bound + }; + + enum FunctionSignatureBehaviorValue + { + Ignored, + Enforced + }; + + enum NativeMethodBehaviorValue + { + AcceptThisObject, + RejectThisObject + }; + + enum ValueTypeBehaviorValue + { + Copy = 0x1, + Addressable = 0x2, + Assertable = 0x4, + }; + Q_DECLARE_FLAGS(ValueTypeBehaviorValues, ValueTypeBehaviorValue); + + PragmaType type; + + union { + ListPropertyAssignBehaviorValue listPropertyAssignBehavior; + ComponentBehaviorValue componentBehavior; + FunctionSignatureBehaviorValue functionSignatureBehavior; + NativeMethodBehaviorValue nativeMethodBehavior; + ValueTypeBehaviorValues::Int valueTypeBehavior; + uint translationContextIndex; }; - quint32 type; QV4::CompiledData::Location location; }; -struct Q_QML_PRIVATE_EXPORT Document +struct Q_QML_COMPILER_EXPORT Document { Document(bool debugMode); QString code; @@ -448,13 +475,20 @@ struct Q_QML_PRIVATE_EXPORT Document QQmlRefPointer<QV4::CompiledData::CompilationUnit> javaScriptCompilationUnit; + bool isSingleton() const { + return std::any_of(pragmas.constBegin(), pragmas.constEnd(), [](const Pragma *pragma) { + return pragma->type == Pragma::Singleton; + }); + } + int registerString(const QString &str) { return jsGenerator.registerString(str); } QString stringAt(int index) const { return jsGenerator.stringForIndex(index); } - static void removeScriptPragmas(QString &script); + int objectCount() const {return objects.size();} + Object* objectAt(int i) const {return objects.at(i);} }; -class Q_QML_PRIVATE_EXPORT ScriptDirectivesCollector : public QQmlJS::Directives +class Q_QML_COMPILER_EXPORT ScriptDirectivesCollector : public QQmlJS::Directives { QmlIR::Document *document; QQmlJS::Engine *engine; @@ -468,15 +502,13 @@ public: void importModule(const QString &uri, const QString &version, const QString &module, int lineNumber, int column) override; }; -struct Q_QML_PRIVATE_EXPORT IRBuilder : public QQmlJS::AST::Visitor +struct Q_QML_COMPILER_EXPORT IRBuilder : public QQmlJS::AST::Visitor { Q_DECLARE_TR_FUNCTIONS(QQmlCodeGenerator) public: IRBuilder(const QSet<QString> &illegalNames); bool generateFromQml(const QString &code, const QString &url, Document *output); - static bool isSignalPropertyName(const QString &name); - using QQmlJS::AST::Visitor::visit; using QQmlJS::AST::Visitor::endVisit; @@ -492,51 +524,71 @@ public: bool visit(QQmlJS::AST::UiArrayBinding *ast) override; bool visit(QQmlJS::AST::UiObjectBinding *ast) override; bool visit(QQmlJS::AST::UiObjectDefinition *ast) override; + bool visit(QQmlJS::AST::UiInlineComponent *ast) override; bool visit(QQmlJS::AST::UiEnumDeclaration *ast) override; bool visit(QQmlJS::AST::UiPublicMember *ast) override; bool visit(QQmlJS::AST::UiScriptBinding *ast) override; bool visit(QQmlJS::AST::UiSourceElement *ast) override; + bool visit(QQmlJS::AST::UiRequired *ast) override; void throwRecursionDepthError() override { - recordError(AST::SourceLocation(), + recordError(QQmlJS::SourceLocation(), QStringLiteral("Maximum statement or expression depth exceeded")); } void accept(QQmlJS::AST::Node *node); // returns index in _objects - bool defineQMLObject(int *objectIndex, QQmlJS::AST::UiQualifiedId *qualifiedTypeNameId, const QQmlJS::AST::SourceLocation &location, QQmlJS::AST::UiObjectInitializer *initializer, Object *declarationsOverride = nullptr); - bool defineQMLObject(int *objectIndex, QQmlJS::AST::UiObjectDefinition *node, Object *declarationsOverride = nullptr) - { return defineQMLObject(objectIndex, node->qualifiedTypeNameId, node->qualifiedTypeNameId->firstSourceLocation(), node->initializer, declarationsOverride); } + bool defineQMLObject( + int *objectIndex, QQmlJS::AST::UiQualifiedId *qualifiedTypeNameId, + const QV4::CompiledData::Location &location, + QQmlJS::AST::UiObjectInitializer *initializer, Object *declarationsOverride = nullptr); + + bool defineQMLObject( + int *objectIndex, QQmlJS::AST::UiObjectDefinition *node, + Object *declarationsOverride = nullptr) + { + const QQmlJS::SourceLocation location = node->qualifiedTypeNameId->firstSourceLocation(); + return defineQMLObject( + objectIndex, node->qualifiedTypeNameId, + { location.startLine, location.startColumn }, node->initializer, + declarationsOverride); + } static QString asString(QQmlJS::AST::UiQualifiedId *node); - QStringRef asStringRef(QQmlJS::AST::Node *node); - static void extractVersion(QStringRef string, int *maj, int *min); - QStringRef textRefAt(const QQmlJS::AST::SourceLocation &loc) const - { return QStringRef(&sourceCode, loc.offset, loc.length); } - QStringRef textRefAt(const QQmlJS::AST::SourceLocation &first, - const QQmlJS::AST::SourceLocation &last) const; - - void setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST::Statement *statement, AST::Node *parentNode); - void tryGeneratingTranslationBinding(const QStringRef &base, QQmlJS::AST::ArgumentList *args, QV4::CompiledData::Binding *binding); - - void appendBinding(QQmlJS::AST::UiQualifiedId *name, QQmlJS::AST::Statement *value, AST::Node *parentNode); + QStringView asStringRef(QQmlJS::AST::Node *node); + static QTypeRevision extractVersion(QStringView string); + QStringView textRefAt(const QQmlJS::SourceLocation &loc) const + { return QStringView(sourceCode).mid(loc.offset, loc.length); } + QStringView textRefAt(const QQmlJS::SourceLocation &first, + const QQmlJS::SourceLocation &last) const; + + void setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST::Statement *statement, + QQmlJS::AST::Node *parentNode); + void tryGeneratingTranslationBinding(QStringView base, QQmlJS::AST::ArgumentList *args, QV4::CompiledData::Binding *binding); + + void appendBinding(QQmlJS::AST::UiQualifiedId *name, QQmlJS::AST::Statement *value, + QQmlJS::AST::Node *parentNode); void appendBinding(QQmlJS::AST::UiQualifiedId *name, int objectIndex, bool isOnAssignment = false); - void appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, QQmlJS::AST::Statement *value, AST::Node *parentNode); - void appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, int objectIndex, bool isListItem = false, bool isOnAssignment = false); + void appendBinding(const QQmlJS::SourceLocation &qualifiedNameLocation, + const QQmlJS::SourceLocation &nameLocation, quint32 propertyNameIndex, + QQmlJS::AST::Statement *value, QQmlJS::AST::Node *parentNode); + void appendBinding(const QQmlJS::SourceLocation &qualifiedNameLocation, + const QQmlJS::SourceLocation &nameLocation, quint32 propertyNameIndex, + int objectIndex, bool isListItem = false, bool isOnAssignment = false); bool appendAlias(QQmlJS::AST::UiPublicMember *node); Object *bindingsTarget() const; - bool setId(const QQmlJS::AST::SourceLocation &idLocation, QQmlJS::AST::Statement *value); + bool setId(const QQmlJS::SourceLocation &idLocation, QQmlJS::AST::Statement *value); // resolves qualified name (font.pixelSize for example) and returns the last name along // with the object any right-hand-side of a binding should apply to. bool resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToResolve, Object **object, bool onAssignment = false); - void recordError(const QQmlJS::AST::SourceLocation &location, const QString &description); + void recordError(const QQmlJS::SourceLocation &location, const QString &description); quint32 registerString(const QString &str) const { return jsGenerator->registerString(str); } template <typename _Tp> _Tp *New() { return pool->New<_Tp>(); } @@ -546,11 +598,12 @@ public: static bool isStatementNodeScript(QQmlJS::AST::Statement *statement); static bool isRedundantNullInitializerForPropertyDeclaration(Property *property, QQmlJS::AST::Statement *statement); - QString sanityCheckFunctionNames(Object *obj, const QSet<QString> &illegalNames, QQmlJS::AST::SourceLocation *errorLocation); + QString sanityCheckFunctionNames(Object *obj, const QSet<QString> &illegalNames, QQmlJS::SourceLocation *errorLocation); QList<QQmlJS::DiagnosticMessage> errors; QSet<QString> illegalNames; + QSet<QString> inlineComponentsNames; QList<const QV4::CompiledData::Import *> _imports; QList<Pragma*> _pragmas; @@ -564,9 +617,11 @@ public: QQmlJS::MemoryPool *pool; QString sourceCode; QV4::Compiler::JSUnitGenerator *jsGenerator; + + bool insideInlineComponent = false; }; -struct Q_QML_PRIVATE_EXPORT QmlUnitGenerator +struct Q_QML_COMPILER_EXPORT QmlUnitGenerator { void generate(Document &output, const QV4::CompiledData::DependentTypesHasher &dependencyHasher = QV4::CompiledData::DependentTypesHasher()); @@ -575,75 +630,224 @@ private: char *writeBindings(char *bindingPtr, const Object *o, BindingFilter filter) const; }; -#ifndef V4_BOOTSTRAP -struct Q_QML_EXPORT PropertyResolver +struct Q_QML_COMPILER_EXPORT JSCodeGen : public QV4::Compiler::Codegen { - PropertyResolver(const QQmlRefPointer<QQmlPropertyCache> &cache) - : cache(cache) - {} - - QQmlPropertyData *property(int index) const - { - return cache->property(index); - } - - enum RevisionCheck { - CheckRevision, - IgnoreRevision - }; + JSCodeGen(Document *document, const QSet<QString> &globalNames, + QV4::Compiler::CodegenWarningInterface *iface = + QV4::Compiler::defaultCodegenWarningInterface(), + bool storeSourceLocations = false); - QQmlPropertyData *property(const QString &name, bool *notInRevision = nullptr, RevisionCheck check = CheckRevision) const; + // Returns mapping from input functions to index in IR::Module::functions / compiledData->runtimeFunctions + QVector<int> + generateJSCodeForFunctionsAndBindings(const QList<CompiledFunctionOrExpression> &functions); - // This code must match the semantics of QQmlPropertyPrivate::findSignalByName - QQmlPropertyData *signal(const QString &name, bool *notInRevision) const; + bool generateRuntimeFunctions(QmlIR::Object *object); - QQmlRefPointer<QQmlPropertyCache> cache; +private: + Document *document; }; -#endif -struct Q_QML_PRIVATE_EXPORT JSCodeGen : public QV4::Compiler::Codegen +// RegisterStringN ~= std::function<int(QStringView)> +// FinalizeTranlationData ~= std::function<void(QV4::CompiledData::Binding::ValueType, QV4::CompiledData::TranslationData)> +/* + \internal + \a base: name of the potential translation function + \a args: arguments to the function call + \a registerMainString: Takes the first argument passed to the translation function, and it's + result will be stored in a TranslationData's stringIndex for translation bindings and in numbeIndex + for string bindings. + \a registerCommentString: Takes the comment argument passed to some of the translation functions. + Result will be stored in a TranslationData's commentIndex + \a finalizeTranslationData: Takes the type of the binding and the previously set up TranslationData + */ +template< + typename RegisterMainString, + typename RegisterCommentString, + typename RegisterContextString, + typename FinalizeTranslationData> +void tryGeneratingTranslationBindingBase(QStringView base, QQmlJS::AST::ArgumentList *args, + RegisterMainString registerMainString, + RegisterCommentString registerCommentString, + RegisterContextString registerContextString, + FinalizeTranslationData finalizeTranslationData + ) { - JSCodeGen(const QString &sourceCode, QV4::Compiler::JSUnitGenerator *jsUnitGenerator, QV4::Compiler::Module *jsModule, - QQmlJS::Engine *jsEngine, QQmlJS::AST::UiProgram *qmlRoot, - const QV4::Compiler::StringTableGenerator *stringPool, const QSet<QString> &globalNames); + if (base == QLatin1String("qsTr")) { + QV4::CompiledData::TranslationData translationData; + translationData.number = -1; - // Returns mapping from input functions to index in IR::Module::functions / compiledData->runtimeFunctions - QVector<int> generateJSCodeForFunctionsAndBindings(const QList<CompiledFunctionOrExpression> &functions); + // empty string + translationData.commentIndex = 0; -private: - QString sourceCode; - QQmlJS::Engine *jsEngine; // needed for memory pool - QQmlJS::AST::UiProgram *qmlRoot; - const QV4::Compiler::StringTableGenerator *stringPool; -}; + // No context (not empty string) + translationData.contextIndex = QV4::CompiledData::TranslationData::NoContextIndex; -struct Q_QML_PRIVATE_EXPORT IRLoader { - IRLoader(const QV4::CompiledData::Unit *unit, QmlIR::Document *output); + if (!args || !args->expression) + return; // no arguments, stop - void load(); + QStringView translation; + if (QQmlJS::AST::StringLiteral *arg1 = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(args->expression)) { + translation = arg1->value; + } else { + return; // first argument is not a string, stop + } -private: - QmlIR::Object *loadObject(const QV4::CompiledData::Object *serializedObject); + translationData.stringIndex = registerMainString(translation); + + args = args->next; + + if (args) { + QQmlJS::AST::StringLiteral *arg2 = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(args->expression); + if (!arg2) + return; // second argument is not a string, stop + translationData.commentIndex = registerCommentString(arg2->value); + + args = args->next; + if (args) { + if (QQmlJS::AST::NumericLiteral *arg3 = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(args->expression)) { + translationData.number = int(arg3->value); + args = args->next; + } else { + return; // third argument is not a translation number, stop + } + } + } - template <typename _Tp> _Tp *New() { return pool->New<_Tp>(); } + if (args) + return; // too many arguments, stop - const QV4::CompiledData::Unit *unit; - QmlIR::Document *output; - QQmlJS::MemoryPool *pool; -}; + finalizeTranslationData(QV4::CompiledData::Binding::Type_Translation, translationData); + } else if (base == QLatin1String("qsTrId")) { + QV4::CompiledData::TranslationData translationData; + translationData.number = -1; -} // namespace QmlIR + // empty string, but unused + translationData.commentIndex = 0; -struct QQmlCompileError -{ - QQmlCompileError() {} - QQmlCompileError(const QV4::CompiledData::Location &location, const QString &description) - : location(location), description(description) {} - QV4::CompiledData::Location location; - QString description; + // No context (not empty string) + translationData.contextIndex = QV4::CompiledData::TranslationData::NoContextIndex; - bool isSet() const { return !description.isEmpty(); } -}; + if (!args || !args->expression) + return; // no arguments, stop + + QStringView id; + if (QQmlJS::AST::StringLiteral *arg1 = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(args->expression)) { + id = arg1->value; + } else { + return; // first argument is not a string, stop + } + translationData.stringIndex = registerMainString(id); + + args = args->next; + + if (args) { + if (QQmlJS::AST::NumericLiteral *arg3 = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(args->expression)) { + translationData.number = int(arg3->value); + args = args->next; + } else { + return; // third argument is not a translation number, stop + } + } + + if (args) + return; // too many arguments, stop + + finalizeTranslationData(QV4::CompiledData::Binding::Type_TranslationById, translationData); + } else if (base == QLatin1String("QT_TR_NOOP") || base == QLatin1String("QT_TRID_NOOP")) { + if (!args || !args->expression) + return; // no arguments, stop + + QStringView str; + if (QQmlJS::AST::StringLiteral *arg1 = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(args->expression)) { + str = arg1->value; + } else { + return; // first argument is not a string, stop + } + + args = args->next; + if (args) + return; // too many arguments, stop + + QV4::CompiledData::TranslationData translationData; + translationData.number = registerMainString(str); + finalizeTranslationData(QV4::CompiledData::Binding::Type_String, translationData); + } else if (base == QLatin1String("QT_TRANSLATE_NOOP")) { + if (!args || !args->expression) + return; // no arguments, stop + + args = args->next; + if (!args || !args->expression) + return; // no second arguments, stop + + QStringView str; + if (QQmlJS::AST::StringLiteral *arg2 = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(args->expression)) { + str = arg2->value; + } else { + return; // first argument is not a string, stop + } + + args = args->next; + if (args) + return; // too many arguments, stop + + QV4::CompiledData::TranslationData fakeTranslationData; + fakeTranslationData.number = registerMainString(str); + finalizeTranslationData(QV4::CompiledData::Binding::Type_String, fakeTranslationData); + } else if (base == QLatin1String("qsTranslate")) { + QV4::CompiledData::TranslationData translationData; + translationData.number = -1; + translationData.commentIndex = 0; // empty string + + if (!args || !args->next) + return; // less than 2 arguments, stop + + QStringView translation; + if (QQmlJS::AST::StringLiteral *arg1 + = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(args->expression)) { + translation = arg1->value; + } else { + return; // first argument is not a string, stop + } + + translationData.contextIndex = registerContextString(translation); + + args = args->next; + Q_ASSERT(args); + + QQmlJS::AST::StringLiteral *arg2 + = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(args->expression); + if (!arg2) + return; // second argument is not a string, stop + translationData.stringIndex = registerMainString(arg2->value); + + args = args->next; + if (args) { + QQmlJS::AST::StringLiteral *arg3 + = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(args->expression); + if (!arg3) + return; // third argument is not a string, stop + translationData.commentIndex = registerCommentString(arg3->value); + + args = args->next; + if (args) { + if (QQmlJS::AST::NumericLiteral *arg4 + = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(args->expression)) { + translationData.number = int(arg4->value); + args = args->next; + } else { + return; // fourth argument is not a translation number, stop + } + } + } + + if (args) + return; // too many arguments, stop + + finalizeTranslationData(QV4::CompiledData::Binding::Type_Translation, translationData); + } +} + +} // namespace QmlIR QT_END_NAMESPACE |