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 +++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 11 deletions(-) (limited to 'src/qml/compiler/qv4compileddata.cpp') 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() -- cgit v1.2.3