From bae423474b51fd0651aaea7cb18071a2206109b1 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 13 Aug 2018 11:57:03 +0200 Subject: Implement indirect exports in modules This allows exports in the style of export { foo as bar } from "./baz.js" Change-Id: I2f723c3d9c5fbc530a30ac5bcb12a02f21918648 Reviewed-by: Lars Knoll --- src/qml/compiler/qv4compileddata.cpp | 62 ++++++++++++++++++++----- src/qml/compiler/qv4compileddata_p.h | 13 +++++- tests/auto/qml/ecmascripttests/TestExpectations | 12 ----- 3 files changed, 63 insertions(+), 24 deletions(-) diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 1c311267b9..4e7674a67a 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -389,6 +389,11 @@ QStringList CompilationUnit::moduleRequests() const requests << stringAt(entry.moduleRequest); } + for (uint i = 0; i < data->indirectExportEntryTableSize; ++i) { + const ExportEntry &entry = data->indirectExportEntryTable()[i]; + requests << stringAt(entry.moduleRequest); + } + return requests; } @@ -429,36 +434,71 @@ Heap::Module *CompilationUnit::instantiate(ExecutionEngine *engine) imports[i] = valuePtr; } + for (uint i = 0; i < data->indirectExportEntryTableSize; ++i) { + const CompiledData::ExportEntry &entry = data->indirectExportEntryTable()[i]; + auto dependentModuleUnit = engine->loadModule(QUrl(stringAt(entry.moduleRequest)), this); + if (!dependentModuleUnit) + return nullptr; + + ScopedString importName(scope, runtimeStrings[entry.importName]); + if (!dependentModuleUnit->resolveExport(importName)) { + QString referenceErrorMessage = QStringLiteral("Unable to resolve re-export reference "); + referenceErrorMessage += importName->toQString(); + engine->throwReferenceError(referenceErrorMessage, fileName(), /*### line*/1, /*### column*/1); + return nullptr; + } + } + return m_module; } const Value *CompilationUnit::resolveExport(QV4::String *exportName) +{ + QVector resolveSet; + return resolveExportRecursively(exportName, &resolveSet); +} + +const Value *CompilationUnit::resolveExportRecursively(QV4::String *exportName, QVector *resolveSet) { if (!m_module) return nullptr; + for (const auto &entry: *resolveSet) + if (entry.module == this && entry.exportName->isEqualTo(exportName)) + return nullptr; + + (*resolveSet) << ResolveSetEntry(this, exportName); + Scope scope(engine); - ScopedString localName(scope, localNameForExportName(exportName)); - if (!localName) + + if (auto localExport = lookupNameInExportTable(data->localExportEntryTable(), data->localExportEntryTableSize, exportName)) { + ScopedString localName(scope, runtimeStrings[localExport->localName]); + uint index = m_module->scope->internalClass->find(localName->toPropertyKey()); + if (index < UINT_MAX) + return &m_module->scope->locals[index]; return nullptr; + } - uint index = m_module->scope->internalClass->find(localName->toPropertyKey()); - if (index < UINT_MAX) - return &m_module->scope->locals[index]; + if (auto indirectExport = lookupNameInExportTable(data->indirectExportEntryTable(), data->indirectExportEntryTableSize, exportName)) { + auto dependentModuleUnit = engine->loadModule(QUrl(stringAt(indirectExport->moduleRequest)), this); + if (!dependentModuleUnit) + return nullptr; + ScopedString importName(scope, runtimeStrings[indirectExport->importName]); + return dependentModuleUnit->resolveExportRecursively(importName, resolveSet); + } return nullptr; } -Heap::String *CompilationUnit::localNameForExportName(QV4::String *exportName) const +const ExportEntry *CompilationUnit::lookupNameInExportTable(const ExportEntry *firstExportEntry, int tableSize, QV4::String *name) const { - const CompiledData::ExportEntry *firstExport = data->localExportEntryTable(); - const CompiledData::ExportEntry *lastExport = data->localExportEntryTable() + data->localExportEntryTableSize; - auto matchingExport = std::lower_bound(firstExport, lastExport, exportName, [this](const CompiledData::ExportEntry &lhs, QV4::String *name) { + const CompiledData::ExportEntry *lastExportEntry = firstExportEntry + tableSize; + auto matchingExport = std::lower_bound(firstExportEntry, lastExportEntry, name, [this](const CompiledData::ExportEntry &lhs, QV4::String *name) { return stringAt(lhs.exportName) < name->toQString(); }); - if (matchingExport == lastExport || stringAt(matchingExport->exportName) != exportName->toQString()) + if (matchingExport == lastExportEntry || stringAt(matchingExport->exportName) != name->toQString()) return nullptr; - return runtimeStrings[matchingExport->localName]; + return matchingExport; } void CompilationUnit::evaluate() diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index f6face5f6e..7cd9e83dbd 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -1163,7 +1163,6 @@ public: QStringList moduleRequests() const; Heap::Module *instantiate(ExecutionEngine *engine); const Value *resolveExport(QV4::String *exportName); - Heap::String *localNameForExportName(QV4::String *exportName) const; void evaluate(); QV4::Function *linkToEngine(QV4::ExecutionEngine *engine); @@ -1186,6 +1185,18 @@ protected: private: void destroy(); + struct ResolveSetEntry + { + ResolveSetEntry() {} + ResolveSetEntry(CompilationUnit *module, QV4::String *exportName) + : module(module), exportName(exportName) {} + CompilationUnit *module = nullptr; + QV4::String *exportName = nullptr; + }; + + const Value *resolveExportRecursively(QV4::String *exportName, QVector *resolveSet); + const ExportEntry *lookupNameInExportTable(const ExportEntry *firstExportEntry, int tableSize, QV4::String *name) const; + QString m_fileName; // initialized from data->sourceFileIndex QString m_finalUrlString; // initialized from data->finalUrlIndex diff --git a/tests/auto/qml/ecmascripttests/TestExpectations b/tests/auto/qml/ecmascripttests/TestExpectations index a727994492..7a4a585501 100644 --- a/tests/auto/qml/ecmascripttests/TestExpectations +++ b/tests/auto/qml/ecmascripttests/TestExpectations @@ -2165,20 +2165,9 @@ language/module-code/eval-rqstd-order.js strictFails language/module-code/eval-self-once.js strictFails language/module-code/instn-iee-bndng-cls.js strictFails language/module-code/instn-iee-bndng-const.js strictFails -language/module-code/instn-iee-bndng-fun.js strictFails -language/module-code/instn-iee-bndng-gen.js strictFails language/module-code/instn-iee-bndng-let.js strictFails -language/module-code/instn-iee-bndng-var.js strictFails language/module-code/instn-iee-star-cycle.js strictFails language/module-code/instn-iee-trlng-comma.js strictFails -language/module-code/instn-iee-err-ambiguous-as.js strictFails -language/module-code/instn-iee-err-ambiguous.js strictFails -language/module-code/instn-iee-err-circular-as.js strictFails -language/module-code/instn-iee-err-circular.js strictFails -language/module-code/instn-iee-err-dflt-thru-star-as.js strictFails -language/module-code/instn-iee-err-dflt-thru-star.js strictFails -language/module-code/instn-iee-err-not-found-as.js strictFails -language/module-code/instn-iee-err-not-found.js strictFails language/module-code/instn-local-bndng-cls.js strictFails language/module-code/instn-local-bndng-const.js strictFails language/module-code/instn-local-bndng-export-cls.js strictFails @@ -2197,7 +2186,6 @@ language/module-code/instn-named-bndng-dflt-named.js strictFails language/module-code/instn-named-bndng-dflt-star.js strictFails language/module-code/instn-named-bndng-let.js strictFails language/module-code/instn-named-id-name.js strictFails -language/module-code/instn-named-iee-cycle.js strictFails language/module-code/instn-named-star-cycle.js strictFails language/module-code/instn-once.js strictFails language/module-code/instn-same-global.js strictFails -- cgit v1.2.3