diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2014-03-17 21:26:04 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-03-18 09:05:57 +0100 |
commit | fa24ef3d721a7b94d0c5abbc6c9558e74bdb0f3d (patch) | |
tree | 37bac24bafc1d2b879d76ac225272912538d072d /src/qml/compiler/qqmlirbuilder_p.h | |
parent | 3f7951c04ef474f81eda2134b67c4e4020fe39d1 (diff) |
Cleanup, part 2
* QQmlCodeGenerator -> QQmlIR::IRBuilder (it doesn't generate code, it
generates the Object/Property/Signal/etc. IR of the .qml file, that's
going to get transformed to QV4::CompiledData::*)
* ParsedQML -> QQmlIR::Document
Change-Id: I329e858487b66e1ae528d44316761f5dd34b79f4
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/qml/compiler/qqmlirbuilder_p.h')
-rw-r--r-- | src/qml/compiler/qqmlirbuilder_p.h | 502 |
1 files changed, 502 insertions, 0 deletions
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h new file mode 100644 index 0000000000..3a0a2054db --- /dev/null +++ b/src/qml/compiler/qqmlirbuilder_p.h @@ -0,0 +1,502 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QQMLIRBUILDER_P_H +#define QQMLIRBUILDER_P_H + +#include <private/qqmljsast_p.h> +#include <private/qqmlpool_p.h> +#include <private/qqmlscript_p.h> +#include <private/qqmljsengine_p.h> +#include <private/qv4compiler_p.h> +#include <private/qv4compileddata_p.h> +#include <private/qqmljsmemorypool_p.h> +#include <private/qv4codegen_p.h> +#include <private/qv4compiler_p.h> +#include <QTextStream> +#include <QCoreApplication> + +QT_BEGIN_NAMESPACE + +class QQmlTypeNameCache; + +namespace QmlIR { + +template <typename T> +struct PoolList +{ + PoolList() + : first(0) + , last(0) + , count(0) + {} + + T *first; + T *last; + int count; + + int append(T *item) { + item->next = 0; + if (last) + last->next = item; + else + first = item; + last = item; + return count++; + } + + void prepend(T *item) { + item->next = first; + first = item; + if (!last) + last = first; + ++count; + } + + template <typename Sortable, typename Base, Sortable Base::*sortMember> + T *findSortedInsertionPoint(T *item) const + { + T *insertPos = 0; + + for (T *it = first; it; it = it->next) { + if (!(it->*sortMember < item->*sortMember)) + break; + insertPos = it; + } + + return insertPos; + } + + void insertAfter(T *insertionPoint, T *item) { + if (!insertionPoint) { + prepend(item); + } else if (insertionPoint == last) { + append(item); + } else { + item->next = insertionPoint->next; + insertionPoint->next = item; + ++count; + } + } + + T *unlink(T *before, T *item) { + T * const newNext = item->next; + + if (before) + before->next = newNext; + else + first = newNext; + + if (item == last) { + if (newNext) + last = newNext; + else + last = first; + } + + --count; + return newNext; + } + + T *slowAt(int index) const + { + T *result = first; + while (index > 0 && result) { + result = result->next; + --index; + } + return result; + } +}; + +template <typename T> +class FixedPoolArray +{ + T *data; +public: + int count; + + void init(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)); + } + } + + 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; + } +}; + +struct Object; + +struct SignalParameter : public QV4::CompiledData::Parameter +{ + SignalParameter *next; +}; + +struct Signal +{ + int nameIndex; + QV4::CompiledData::Location location; + PoolList<SignalParameter> *parameters; + + QStringList parameterStringList(const QStringList &stringPool) const; + + Signal *next; +}; + +struct Property : public QV4::CompiledData::Property +{ + Property *next; +}; + +struct Binding : public QV4::CompiledData::Binding +{ + // Binding's compiledScriptIndex is index in object's functionsAndExpressions + Binding *next; +}; + +struct Function +{ + QQmlJS::AST::FunctionDeclaration *functionDeclaration; + QV4::CompiledData::Location location; + int nameIndex; + quint32 index; // index in parsedQML::functions + Function *next; +}; + +struct Q_QML_EXPORT CompiledFunctionOrExpression +{ + CompiledFunctionOrExpression() + : node(0) + , nameIndex(0) + , disableAcceleratedLookups(false) + , next(0) + {} + CompiledFunctionOrExpression(QQmlJS::AST::Node *n) + : node(n) + , nameIndex(0) + , disableAcceleratedLookups(false) + , next(0) + {} + QQmlJS::AST::Node *node; // FunctionDeclaration, Statement or Expression + quint32 nameIndex; + bool disableAcceleratedLookups; + CompiledFunctionOrExpression *next; +}; + +struct Q_QML_EXPORT Object +{ + Q_DECLARE_TR_FUNCTIONS(Object) +public: + quint32 inheritedTypeNameIndex; + quint32 idIndex; + int indexOfDefaultProperty; + + QV4::CompiledData::Location location; + QV4::CompiledData::Location locationOfIdProperty; + + const Property *firstProperty() const { return properties->first; } + int propertyCount() const { return properties->count; } + const Signal *firstSignal() const { return qmlSignals->first; } + int signalCount() const { return qmlSignals->count; } + Binding *firstBinding() const { return bindings->first; } + int bindingCount() const { return bindings->count; } + const Function *firstFunction() const { return functions->first; } + int functionCount() const { return functions->count; } + + // 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 id, const QQmlJS::AST::SourceLocation &location = QQmlJS::AST::SourceLocation()); + + QString sanityCheckFunctionNames(const QSet<QString> &illegalNames, QQmlJS::AST::SourceLocation *errorLocation); + + QString appendSignal(Signal *signal); + QString appendProperty(Property *prop, const QString &propertyName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation); + void appendFunction(QmlIR::Function *f); + + QString appendBinding(Binding *b, bool isListBinding); + Binding *findBinding(quint32 nameIndex) const; + Binding *unlinkBinding(Binding *before, Binding *binding) { return bindings->unlink(before, binding); } + void insertSorted(Binding *b); + + PoolList<CompiledFunctionOrExpression> *functionsAndExpressions; + FixedPoolArray<int> *runtimeFunctionIndices; + +private: + PoolList<Property> *properties; + PoolList<Signal> *qmlSignals; + PoolList<Binding> *bindings; + PoolList<Function> *functions; +}; + +struct Q_QML_EXPORT Pragma +{ + enum PragmaType { + PragmaSingleton = 0x1 + }; + quint32 type; + + QV4::CompiledData::Location location; +}; + +struct Q_QML_EXPORT Document +{ + Document(bool debugMode) + : jsModule(debugMode) + , jsGenerator(&jsModule, sizeof(QV4::CompiledData::QmlUnit)) + {} + QString code; + QQmlJS::Engine jsParserEngine; + QV4::IR::Module jsModule; + QList<QV4::CompiledData::Import*> imports; + QList<Pragma*> pragmas; + QQmlJS::AST::UiProgram *program; + int indexOfRootObject; + QList<Object*> objects; + QV4::Compiler::JSUnitGenerator jsGenerator; + + QV4::CompiledData::TypeReferenceMap typeReferences; + + QString stringAt(int index) const { return jsGenerator.strings.value(index); } +}; + +struct Q_QML_EXPORT IRBuilder : public QQmlJS::AST::Visitor +{ + Q_DECLARE_TR_FUNCTIONS(QQmlCodeGenerator) +public: + IRBuilder(const QSet<QString> &illegalNames); + bool generateFromQml(const QString &code, const QUrl &url, const QString &urlString, Document *output); + + static bool isSignalPropertyName(const QString &name); + + using QQmlJS::AST::Visitor::visit; + using QQmlJS::AST::Visitor::endVisit; + + virtual bool visit(QQmlJS::AST::UiArrayMemberList *ast); + virtual bool visit(QQmlJS::AST::UiImport *ast); + virtual bool visit(QQmlJS::AST::UiPragma *ast); + virtual bool visit(QQmlJS::AST::UiHeaderItemList *ast); + virtual bool visit(QQmlJS::AST::UiObjectInitializer *ast); + virtual bool visit(QQmlJS::AST::UiObjectMemberList *ast); + virtual bool visit(QQmlJS::AST::UiParameterList *ast); + virtual bool visit(QQmlJS::AST::UiProgram *); + virtual bool visit(QQmlJS::AST::UiQualifiedId *ast); + virtual bool visit(QQmlJS::AST::UiArrayBinding *ast); + virtual bool visit(QQmlJS::AST::UiObjectBinding *ast); + virtual bool visit(QQmlJS::AST::UiObjectDefinition *ast); + virtual bool visit(QQmlJS::AST::UiPublicMember *ast); + virtual bool visit(QQmlJS::AST::UiScriptBinding *ast); + virtual bool visit(QQmlJS::AST::UiSourceElement *ast); + + 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 = 0); + bool defineQMLObject(int *objectIndex, QQmlJS::AST::UiObjectDefinition *node, Object *declarationsOverride = 0) + { return defineQMLObject(objectIndex, node->qualifiedTypeNameId, node->qualifiedTypeNameId->firstSourceLocation(), 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; + static QQmlScript::LocationSpan location(QQmlJS::AST::UiQualifiedId *id) + { + return location(id->identifierToken, id->identifierToken); + } + + void setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST::Statement *statement); + + void appendBinding(QQmlJS::AST::UiQualifiedId *name, QQmlJS::AST::Statement *value); + 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); + void appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, int objectIndex, bool isListItem = false, bool isOnAssignment = false); + + Object *bindingsTarget() const; + + bool setId(const QQmlJS::AST::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 collectTypeReferences(); + + static QQmlScript::LocationSpan location(QQmlJS::AST::SourceLocation start, QQmlJS::AST::SourceLocation end); + + quint32 registerString(const QString &str) const { return jsGenerator->registerString(str); } + template <typename _Tp> _Tp *New() { return pool->New<_Tp>(); } + + QString stringAt(int index) const { return jsGenerator->strings.at(index); } + + static bool isStatementNodeScript(QQmlJS::AST::Statement *statement); + + QList<QQmlError> errors; + + QSet<QString> illegalNames; + + QList<QV4::CompiledData::Import*> _imports; + QList<Pragma*> _pragmas; + QList<Object*> _objects; + + QV4::CompiledData::TypeReferenceMap _typeReferences; + + Object *_object; + Property *_propertyDeclaration; + + QQmlJS::MemoryPool *pool; + QString sourceCode; + QUrl url; + QV4::Compiler::JSUnitGenerator *jsGenerator; +}; + +struct Q_QML_EXPORT QmlUnitGenerator +{ + QmlUnitGenerator() + : jsUnitGenerator(0) + { + } + + QV4::CompiledData::QmlUnit *generate(Document &output); + +private: + typedef bool (Binding::*BindingFilter)() const; + char *writeBindings(char *bindingPtr, Object *o, BindingFilter filter) const; + + int getStringId(const QString &str) const; + + QV4::Compiler::JSUnitGenerator *jsUnitGenerator; +}; + +struct Q_QML_EXPORT PropertyResolver +{ + PropertyResolver(QQmlPropertyCache *cache) + : cache(cache) + {} + + QQmlPropertyData *property(int index) + { + return cache->property(index); + } + + QQmlPropertyData *property(const QString &name, bool *notInRevision = 0, QObject *object = 0, QQmlContextData *context = 0); + + // This code must match the semantics of QQmlPropertyPrivate::findSignalByName + QQmlPropertyData *signal(const QString &name, bool *notInRevision, QObject *object = 0, QQmlContextData *context = 0); + + QQmlPropertyCache *cache; +}; + +struct Q_QML_EXPORT JSCodeGen : public QQmlJS::Codegen +{ + JSCodeGen(const QString &fileName, const QString &sourceCode, QV4::IR::Module *jsModule, + QQmlJS::Engine *jsEngine, QQmlJS::AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports, + const QStringList &stringPool); + + struct IdMapping + { + QString name; + int idIndex; + QQmlPropertyCache *type; + }; + typedef QVector<IdMapping> ObjectIdMapping; + + void beginContextScope(const ObjectIdMapping &objectIds, QQmlPropertyCache *contextObject); + void beginObjectScope(QQmlPropertyCache *scopeObject); + + // Returns mapping from input functions to index in IR::Module::functions / compiledData->runtimeFunctions + QVector<int> generateJSCodeForFunctionsAndBindings(const QList<CompiledFunctionOrExpression> &functions); + +protected: + virtual void beginFunctionBodyHook(); + virtual QV4::IR::Expr *fallbackNameLookup(const QString &name, int line, int col); + +private: + QQmlPropertyData *lookupQmlCompliantProperty(QQmlPropertyCache *cache, const QString &name, bool *propertyExistsButForceNameLookup = 0); + + QString sourceCode; + QQmlJS::Engine *jsEngine; // needed for memory pool + QQmlJS::AST::UiProgram *qmlRoot; + QQmlTypeNameCache *imports; + const QStringList &stringPool; + + bool _disableAcceleratedLookups; + ObjectIdMapping _idObjects; + QQmlPropertyCache *_contextObject; + QQmlPropertyCache *_scopeObject; + int _contextObjectTemp; + int _scopeObjectTemp; + int _importedScriptsTemp; + int _idArrayTemp; +}; + +} // namespace QmlIR + +QT_END_NAMESPACE + +#endif // QQMLIRBUILDER_P_H |