diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2020-11-24 14:14:46 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2020-11-25 12:51:34 +0100 |
commit | 140a34afdd9ecbb7bc5f9db3f68dcd43a6c534e3 (patch) | |
tree | b235dbaabac9e900992c76baf6b7f919b9a7195a /src/qmlcompiler | |
parent | 927dd69db9bbffcc423b735a7f89e950e052892a (diff) |
QmlCompiler: Unify parsing of QML components, JS programs, ES modules
There is no reason to duplicate the code for retrieving method
signatures 3 times over. As an added benefit, the types on those methods
are resolved now.
Change-Id: I2f9681911b938c4a260b6593ab49e9cc5098c546
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/qmlcompiler')
-rw-r--r-- | src/qmlcompiler/qqmljsimportvisitor.cpp | 95 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljsimportvisitor_p.h | 12 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljsscope_p.h | 5 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljstypereader.cpp | 58 |
4 files changed, 96 insertions, 74 deletions
diff --git a/src/qmlcompiler/qqmljsimportvisitor.cpp b/src/qmlcompiler/qqmljsimportvisitor.cpp index 0e16b02846..c4f99f48b2 100644 --- a/src/qmlcompiler/qqmljsimportvisitor.cpp +++ b/src/qmlcompiler/qqmljsimportvisitor.cpp @@ -67,7 +67,7 @@ void QQmlJSImportVisitor::leaveEnvironment() void QQmlJSImportVisitor::resolveAliases() { QQueue<QQmlJSScope::Ptr> objects; - objects.enqueue(m_qmlRootScope); + objects.enqueue(m_exportedRootScope); while (!objects.isEmpty()) { const QQmlJSScope::Ptr object = objects.dequeue(); @@ -90,19 +90,24 @@ void QQmlJSImportVisitor::resolveAliases() QQmlJSScope::Ptr QQmlJSImportVisitor::result() const { - return m_qmlRootScope; + return m_exportedRootScope; } -bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiProgram *) +void QQmlJSImportVisitor::importBaseModules() { + Q_ASSERT(m_rootScopeImports.isEmpty()); m_rootScopeImports = m_importer->importBuiltins(); if (!m_qmltypesFiles.isEmpty()) m_rootScopeImports.insert(m_importer->importQmltypes(m_qmltypesFiles)); m_rootScopeImports.insert(m_importer->importDirectory(m_implicitImportDirectory)); - m_errors.append(m_importer->takeWarnings()); +} + +bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiProgram *) +{ + importBaseModules(); return true; } @@ -120,8 +125,8 @@ bool QQmlJSImportVisitor::visit(UiObjectDefinition *definition) superType.append(segment->name.toString()); } enterEnvironment(QQmlJSScope::QMLScope, superType, definition->firstSourceLocation()); - if (!m_qmlRootScope) - m_qmlRootScope = m_currentScope; + if (!m_exportedRootScope) + m_exportedRootScope = m_currentScope; m_currentScope->resolveTypes(m_rootScopeImports); return true; @@ -178,22 +183,22 @@ void QQmlJSImportVisitor::visitFunctionExpressionHelper(QQmlJS::AST::FunctionExp using namespace QQmlJS::AST; auto name = fexpr->name.toString(); if (!name.isEmpty()) { - if (m_currentScope->scopeType() == QQmlJSScope::QMLScope) { - QQmlJSMetaMethod method(name); - method.setMethodType(QQmlJSMetaMethod::Method); - if (const auto *formals = fexpr->formals) { - const auto parameters = formals->formals(); - for (const auto ¶meter : parameters) { - const QString type = parameter.typeName(); - method.addParameter(parameter.id, - type.isEmpty() ? QStringLiteral("var") : type); - } + QQmlJSMetaMethod method(name); + method.setMethodType(QQmlJSMetaMethod::Method); + if (const auto *formals = fexpr->formals) { + const auto parameters = formals->formals(); + for (const auto ¶meter : parameters) { + const QString type = parameter.typeName(); + method.addParameter(parameter.id, + type.isEmpty() ? QStringLiteral("var") : type); } - method.setReturnTypeName(fexpr->typeAnnotation - ? fexpr->typeAnnotation->type->toString() - : QStringLiteral("var")); - m_currentScope->addOwnMethod(method); - } else { + } + method.setReturnTypeName(fexpr->typeAnnotation + ? fexpr->typeAnnotation->type->toString() + : QStringLiteral("var")); + m_currentScope->addOwnMethod(method); + + if (m_currentScope->scopeType() != QQmlJSScope::QMLScope) { m_currentScope->insertJSIdentifier( name, { QQmlJSScope::JavaScriptIdentifier::LexicalScoped, @@ -504,4 +509,52 @@ void QQmlJSImportVisitor::endVisit(QQmlJS::AST::UiObjectBinding *uiob) m_currentScope->addOwnProperty(property); } +bool QQmlJSImportVisitor::visit(ExportDeclaration *) +{ + Q_ASSERT(!m_exportedRootScope.isNull()); + Q_ASSERT(m_exportedRootScope != m_globalScope); + Q_ASSERT(m_currentScope == m_globalScope); + m_currentScope = m_exportedRootScope; + return true; +} + +void QQmlJSImportVisitor::endVisit(ExportDeclaration *) +{ + Q_ASSERT(!m_exportedRootScope.isNull()); + m_currentScope = m_exportedRootScope->parentScope(); + Q_ASSERT(m_currentScope == m_globalScope); +} + +bool QQmlJSImportVisitor::visit(ESModule *module) +{ + enterEnvironment(QQmlJSScope::JSLexicalScope, QStringLiteral("module"), + module->firstSourceLocation()); + Q_ASSERT(m_exportedRootScope.isNull()); + m_exportedRootScope = m_currentScope; + m_exportedRootScope->setIsScript(true); + importBaseModules(); + leaveEnvironment(); + return true; +} + +void QQmlJSImportVisitor::endVisit(ESModule *) +{ + m_exportedRootScope->resolveTypes(m_rootScopeImports); +} + +bool QQmlJSImportVisitor::visit(Program *) +{ + Q_ASSERT(m_globalScope == m_currentScope); + Q_ASSERT(m_exportedRootScope.isNull()); + m_exportedRootScope = m_currentScope; + m_exportedRootScope->setIsScript(true); + importBaseModules(); + return true; +} + +void QQmlJSImportVisitor::endVisit(Program *) +{ + m_exportedRootScope->resolveTypes(m_rootScopeImports); +} + QT_END_NAMESPACE diff --git a/src/qmlcompiler/qqmljsimportvisitor_p.h b/src/qmlcompiler/qqmljsimportvisitor_p.h index dfb4b13c41..14fe2236e1 100644 --- a/src/qmlcompiler/qqmljsimportvisitor_p.h +++ b/src/qmlcompiler/qqmljsimportvisitor_p.h @@ -95,12 +95,21 @@ protected: bool visit(QQmlJS::AST::UiObjectBinding *uiob) override; void endVisit(QQmlJS::AST::UiObjectBinding *uiob) override; + bool visit(QQmlJS::AST::ExportDeclaration *exp) override; + void endVisit(QQmlJS::AST::ExportDeclaration *exp) override; + + bool visit(QQmlJS::AST::ESModule *module) override; + void endVisit(QQmlJS::AST::ESModule *module) override; + + bool visit(QQmlJS::AST::Program *program) override; + void endVisit(QQmlJS::AST::Program *program) override; + void throwRecursionDepthError() override; QString m_implicitImportDirectory; QStringList m_qmltypesFiles; QQmlJSScope::Ptr m_currentScope; - QQmlJSScope::Ptr m_qmlRootScope; + QQmlJSScope::Ptr m_exportedRootScope; QQmlJSScope::ConstPtr m_globalScope; QHash<QString, QQmlJSScope::ConstPtr> m_scopesById; QHash<QString, QQmlJSScope::ConstPtr> m_rootScopeImports; @@ -113,6 +122,7 @@ protected: void leaveEnvironment(); private: + void importBaseModules(); void resolveAliases(); void visitFunctionExpressionHelper(QQmlJS::AST::FunctionExpression *fexpr); }; diff --git a/src/qmlcompiler/qqmljsscope_p.h b/src/qmlcompiler/qqmljsscope_p.h index 0801e6eb7e..711d24c7aa 100644 --- a/src/qmlcompiler/qqmljsscope_p.h +++ b/src/qmlcompiler/qqmljsscope_p.h @@ -108,7 +108,8 @@ public: enum Flag { Creatable = 0x1, Composite = 0x2, - Singleton = 0x4 + Singleton = 0x4, + Script = 0x8, }; Q_DECLARE_FLAGS(Flags, Flag) Q_FLAGS(Flags); @@ -216,9 +217,11 @@ public: bool isSingleton() const { return m_flags & Singleton; } bool isCreatable() const { return m_flags & Creatable; } bool isComposite() const { return m_flags & Composite; } + bool isScript() const { return m_flags & Script; } void setIsSingleton(bool v) { m_flags = v ? (m_flags | Singleton) : (m_flags & ~Singleton); } void setIsCreatable(bool v) { m_flags = v ? (m_flags | Creatable) : (m_flags & ~Creatable); } void setIsComposite(bool v) { m_flags = v ? (m_flags | Composite) : (m_flags & ~Composite); } + void setIsScript(bool v) { m_flags = v ? (m_flags | Script) : (m_flags & ~Script); } void setAccessSemantics(AccessSemantics semantics) { m_semantics = semantics; } AccessSemantics accessSemantics() const { return m_semantics; } diff --git a/src/qmlcompiler/qqmljstypereader.cpp b/src/qmlcompiler/qqmljstypereader.cpp index 789166a301..25636dbe32 100644 --- a/src/qmlcompiler/qqmljstypereader.cpp +++ b/src/qmlcompiler/qqmljstypereader.cpp @@ -40,43 +40,6 @@ QT_BEGIN_NAMESPACE -static QQmlJSScope::Ptr parseModule(QQmlJS::AST::ESModule *module, const QString &name) -{ - using namespace QQmlJS::AST; - QQmlJSScope::Ptr result = QQmlJSScope::create(QQmlJSScope::JSLexicalScope); - result->setInternalName(name); - for (auto *statement = module->body; statement; statement = statement->next) { - if (auto *exp = cast<ExportDeclaration *>(statement->statement)) { - // TODO: There are a number of other things we could find here - if (auto *function = cast<FunctionDeclaration *>(exp->variableStatementOrDeclaration)) { - QQmlJSMetaMethod method(function->name.toString()); - method.setMethodType(QQmlJSMetaMethod::Method); - for (auto *argument = function->formals; argument; argument = argument->next) - method.addParameter(argument->element->bindingIdentifier.toString(), QString()); - result->addOwnMethod(method); - } - } - } - return result; -} - -static QQmlJSScope::Ptr parseProgram(QQmlJS::AST::Program *program, const QString &name) -{ - using namespace QQmlJS::AST; - QQmlJSScope::Ptr result = QQmlJSScope::create(QQmlJSScope::JSLexicalScope); - result->setInternalName(name); - for (auto *statement = program->statements; statement; statement = statement->next) { - if (auto *function = cast<FunctionDeclaration *>(statement->statement)) { - QQmlJSMetaMethod method(function->name.toString()); - method.setMethodType(QQmlJSMetaMethod::Method); - for (auto *parameters = function->formals; parameters; parameters = parameters->next) - method.addParameter(parameters->element->bindingIdentifier.toString(), QString()); - result->addOwnMethod(method); - } - } - return result; -} - QQmlJSScope::Ptr QQmlJSTypeReader::operator()() { using namespace QQmlJS::AST; @@ -116,20 +79,13 @@ QQmlJSScope::Ptr QQmlJSTypeReader::operator()() return result; } - if (!isJavaScript) { - QQmlJS::AST::UiProgram *program = parser.ast(); - QQmlJSImportVisitor membersVisitor(m_importer, QFileInfo(m_file).canonicalPath(), - m_qmltypesFiles); - program->accept(&membersVisitor); - m_errors = membersVisitor.errors(); - return membersVisitor.result(); - } - - - if (isESModule) - return parseModule(cast<ESModule *>(parser.rootNode()), scopeName); - else - return parseProgram(cast<Program *>(parser.rootNode()), scopeName); + QQmlJS::AST::Node *rootNode = parser.rootNode(); + QQmlJSImportVisitor membersVisitor(m_importer, QFileInfo(m_file).canonicalPath(), + m_qmltypesFiles); + rootNode->accept(&membersVisitor); + auto result = membersVisitor.result(); + result->setInternalName(scopeName); + return result; } QT_END_NAMESPACE |