diff options
author | Simon Hausmann <simon.hausmann@qt.io> | 2018-07-10 14:52:34 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2018-08-09 13:18:39 +0000 |
commit | 82da798499aa8b656e771191332864a703069739 (patch) | |
tree | 35cb1d0ef8dd3d949f8b6f6324d19ec577b3f4df /src/qml/compiler/qv4codegen.cpp | |
parent | 6510046ee32ef69d7f250fd1d829063983f93fdd (diff) | |
download | qtdeclarative-82da798499aa8b656e771191332864a703069739.tar.gz |
Add initial basic support for ES6 modules
The entry point from the parsing perspective into modules is not
QV4::Script but QV4::ExecutionEngine::compileModule.
For convenience, the ESModule AST node gets a body, which is the
statement list connected between the ModuleItemList items that are not
import/export declarations.
The QV4::Module allocates a call context where the exported variables
are stored as named locals. This will also become the module namespace
object.
The imports in turn is an array of value pointers that point into the
locals array of the context of the imported modules.
The default module loading in ExecutionEngine assumes the accessibility
of module urls via QFile (so local file system or resource). This is
what qmljs also uses and QJSEngine as well via public API in the future.
The test runner compiles the modules manually and injects them, because
they need to be compiled together with the test harness code.
The QML type loader will the mechanism for injection in the future for
module imports from .qml files.
Change-Id: I93be9cfe54c651fdbd08c5e1d22d58f47284e54f
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/qml/compiler/qv4codegen.cpp')
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 70 |
1 files changed, 66 insertions, 4 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 30a73d31bd..7b059b3fb4 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -126,6 +126,49 @@ void Codegen::generateFromProgram(const QString &fileName, defineFunction(QStringLiteral("%entry"), node, nullptr, node->statements); } +void Codegen::generateFromModule(const QString &fileName, + const QString &finalUrl, + const QString &sourceCode, + ESModule *node, + Module *module) +{ + Q_ASSERT(node); + + _module = module; + _context = nullptr; + + // ### should be set on the module outside of this method + _module->fileName = fileName; + _module->finalUrl = finalUrl; + + ScanFunctions scan(this, sourceCode, ContextType::ESModule); + scan(node); + + if (hasError) + return; + + { + Compiler::Context *moduleContext = _module->contextMap.value(node); + for (const auto &entry: moduleContext->exportEntries) { + if (entry.moduleRequest.isEmpty()) { + // ### check against imported bound names + _module->localExportEntries << entry; + } else if (entry.importName == QLatin1Char('*')) { + _module->starExportEntries << entry; + } else { + _module->indirectExportEntries << entry; + } + } + _module->importEntries = moduleContext->importEntries; + } + + std::sort(_module->localExportEntries.begin(), _module->localExportEntries.end(), ExportEntry::lessThan); + std::sort(_module->starExportEntries.begin(), _module->starExportEntries.end(), ExportEntry::lessThan); + std::sort(_module->indirectExportEntries.begin(), _module->indirectExportEntries.end(), ExportEntry::lessThan); + + defineFunction(QStringLiteral("%entry"), node, nullptr, node->statements); +} + void Codegen::enterContext(Node *node) { _context = _module->contextMap.value(node); @@ -2163,13 +2206,21 @@ Codegen::Reference Codegen::referenceForName(const QString &name, bool isLhs) { Context::ResolvedName resolved = _context->resolveName(name); - if (resolved.type == Context::ResolvedName::Local || resolved.type == Context::ResolvedName::Stack) { + if (resolved.type == Context::ResolvedName::Local || resolved.type == Context::ResolvedName::Stack + || resolved.type == Context::ResolvedName::Import) { if (resolved.isArgOrEval && isLhs) // ### add correct source location throwSyntaxError(SourceLocation(), QStringLiteral("Variable name may not be eval or arguments in strict mode")); - Reference r = (resolved.type == Context::ResolvedName::Local) ? - Reference::fromScopedLocal(this, resolved.index, resolved.scope) : - Reference::fromStackSlot(this, resolved.index, true /*isLocal*/); + Reference r; + switch (resolved.type) { + case Context::ResolvedName::Local: + r = Reference::fromScopedLocal(this, resolved.index, resolved.scope); break; + case Context::ResolvedName::Stack: + r = Reference::fromStackSlot(this, resolved.index, true /*isLocal*/); break; + case Context::ResolvedName::Import: + r = Reference::fromImport(this, resolved.index); break; + default: Q_UNREACHABLE(); + } if (r.isStackSlot() && _volatileMemoryLocations.isVolatile(name)) r.isVolatile = true; r.isArgOrEval = resolved.isArgOrEval; @@ -3744,6 +3795,9 @@ Codegen::Reference &Codegen::Reference::operator =(const Reference &other) elementBase = other.elementBase; elementSubscript = other.elementSubscript; break; + case Import: + index = other.index; + break; case Const: constant = other.constant; break; @@ -3789,6 +3843,8 @@ bool Codegen::Reference::operator==(const Codegen::Reference &other) const return propertyBase == other.propertyBase && propertyNameIndex == other.propertyNameIndex; case Subscript: return elementBase == other.elementBase && elementSubscript == other.elementSubscript; + case Import: + return index == other.index; case Const: return constant == other.constant; case QmlScopeObject: @@ -4031,6 +4087,7 @@ void Codegen::Reference::storeAccumulator() const case Invalid: case Accumulator: case Const: + case Import: break; } @@ -4145,6 +4202,11 @@ QT_WARNING_POP codegen->bytecodeGenerator->addInstruction(load); } return; + case Import: { + Instruction::LoadImport load; + load.index = index; + codegen->bytecodeGenerator->addInstruction(load); + } return; case Subscript: { elementSubscript.loadInAccumulator(); Instruction::LoadElement load; |