diff options
author | Simon Hausmann <simon.hausmann@qt.io> | 2018-08-06 14:19:35 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2018-08-14 17:45:33 +0000 |
commit | e9f41fdf19749dda82c8005515c9941b757750c5 (patch) | |
tree | f015b35d04be96283ce5a7157445458339502963 /src/qml | |
parent | bae423474b51fd0651aaea7cb18071a2206109b1 (diff) |
Implement initial support for import namespaces
The import via
import * as foo from "./bar.js"
allows accessing all exports via the special namespace object. This is
conceptually quite similar to the existing import of .js files in
QtQuick.
Change-Id: Ia6d79342f0884a89dfe4dc07316570ca7789cac0
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/qml')
-rw-r--r-- | src/qml/compiler/qv4compileddata.cpp | 3 | ||||
-rw-r--r-- | src/qml/compiler/qv4compilerscanfunctions.cpp | 3 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4module.cpp | 118 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4module_p.h | 14 |
4 files changed, 134 insertions, 4 deletions
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 4e7674a67a..33e463c76a 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -469,6 +469,9 @@ const Value *CompilationUnit::resolveExportRecursively(QV4::String *exportName, (*resolveSet) << ResolveSetEntry(this, exportName); + if (exportName->toQString() == QLatin1String("*")) + return &m_module->self; + Scope scope(engine); if (auto localExport = lookupNameInExportTable(data->localExportEntryTable(), data->localExportEntryTableSize, exportName)) { diff --git a/src/qml/compiler/qv4compilerscanfunctions.cpp b/src/qml/compiler/qv4compilerscanfunctions.cpp index 8f16f9a362..f47643826f 100644 --- a/src/qml/compiler/qv4compilerscanfunctions.cpp +++ b/src/qml/compiler/qv4compilerscanfunctions.cpp @@ -251,9 +251,6 @@ bool ScanFunctions::visit(ImportDeclaration *declaration) entry.importName = QStringLiteral("*"); entry.localName = import->nameSpaceImport->importedBinding.toString(); _context->importEntries << entry; - - _cg->throwSyntaxError(import->nameSpaceImport->importedBindingToken, QStringLiteral("* imports are currently not supported.")); - return false; } if (import->namedImports) { diff --git a/src/qml/jsruntime/qv4module.cpp b/src/qml/jsruntime/qv4module.cpp index ed7df459b6..4a7d0c19c4 100644 --- a/src/qml/jsruntime/qv4module.cpp +++ b/src/qml/jsruntime/qv4module.cpp @@ -43,6 +43,7 @@ #include <private/qv4mm_p.h> #include <private/qv4vme_moth_p.h> #include <private/qv4context_p.h> +#include <private/qv4symbol_p.h> using namespace QV4; @@ -55,6 +56,7 @@ void Heap::Module::init(ExecutionEngine *engine, CompiledData::CompilationUnit * // This is a back pointer and there is no need to call addref() on the unit, because the unit // owns this object instead. unit = moduleUnit; + self.set(engine, this); Function *moduleFunction = unit->runtimeFunctions[unit->unitData()->indexOfRootFunction]; @@ -66,4 +68,120 @@ void Heap::Module::init(ExecutionEngine *engine, CompiledData::CompilationUnit * scope->locals.size = locals; scope->locals.alloc = locals; scope->nArgs = 0; + + Scope valueScope(engine); + Scoped<QV4::Module> This(valueScope, this); + ScopedString name(valueScope, engine->newString(QStringLiteral("Module"))); + This->insertMember(engine->symbol_toStringTag(), name, Attr_ReadOnly); + This->setPrototypeUnchecked(nullptr); +} + +ReturnedValue Module::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty) +{ + if (id.isSymbol()) + return Object::virtualGet(m, id, receiver, hasProperty); + + const Module *module = static_cast<const Module *>(m); + Scope scope(m->engine()); + ScopedString expectedName(scope, id.toStringOrSymbol(scope.engine)); + const Value *v = module->d()->unit->resolveExport(expectedName); + if (hasProperty) + *hasProperty = v != nullptr; + if (!v) + return Encode::undefined(); + return v->asReturnedValue(); +} + +PropertyAttributes Module::virtualGetOwnProperty(Managed *m, PropertyKey id, Property *p) +{ + if (id.isSymbol()) + return Object::virtualGetOwnProperty(m, id, p); + + const Module *module = static_cast<const Module *>(m); + Scope scope(m->engine()); + ScopedString expectedName(scope, id.toStringOrSymbol(scope.engine)); + const Value *v = module->d()->unit->resolveExport(expectedName); + if (!v) { + if (p) + p->value = Encode::undefined(); + return Attr_Invalid; + } + if (p) + p->value = v->asReturnedValue(); + return Attr_Data; +} + +bool Module::virtualPreventExtensions(Managed *) +{ + return true; +} + +bool Module::virtualDefineOwnProperty(Managed *, PropertyKey, const Property *, PropertyAttributes) +{ + return false; +} + +bool Module::virtualPut(Managed *, PropertyKey, const Value &, Value *) +{ + return false; +} + +bool Module::virtualDeleteProperty(Managed *m, PropertyKey id) +{ + if (id.isSymbol()) + return Object::virtualDeleteProperty(m, id); + const Module *module = static_cast<const Module *>(m); + Scope scope(m->engine()); + ScopedString expectedName(scope, id.toStringOrSymbol(scope.engine)); + if (!expectedName) + return true; + const Value *v = module->d()->unit->resolveExport(expectedName); + if (v) + return false; + return true; +} + +struct ModuleNamespaceIterator : ObjectOwnPropertyKeyIterator +{ + uint exportIndex = 0; + ~ModuleNamespaceIterator() override = default; + PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override; + +}; + +PropertyKey ModuleNamespaceIterator::next(const Object *o, Property *pd, PropertyAttributes *attrs) +{ + const Module *module = static_cast<const Module *>(o); + if (exportIndex < module->d()->unit->unitData()->localExportEntryTableSize) { + if (attrs) + *attrs = Attr_Data; + if (pd) { + const CompiledData::ExportEntry &entry = module->d()->unit->unitData()->localExportEntryTable()[exportIndex]; + Scope scope(module->engine()); + ScopedString exportName(scope, module->d()->unit->runtimeStrings[entry.exportName]); + pd->value = *module->d()->unit->resolveExport(exportName); + } + exportIndex++; + } + return ObjectOwnPropertyKeyIterator::next(o, pd, attrs); +} + +OwnPropertyKeyIterator *Module::virtualOwnPropertyKeys(const Object *) +{ + return new ModuleNamespaceIterator; +} + +Heap::Object *Module::virtualGetPrototypeOf(const Managed *) +{ + return nullptr; +} + +bool Module::virtualSetPrototypeOf(Managed *, const Object *proto) +{ + return proto == nullptr; +} + +bool Module::virtualIsExtensible(const Managed *) +{ + return false; } diff --git a/src/qml/jsruntime/qv4module_p.h b/src/qml/jsruntime/qv4module_p.h index 1958258ef0..c22e6cd1c3 100644 --- a/src/qml/jsruntime/qv4module_p.h +++ b/src/qml/jsruntime/qv4module_p.h @@ -61,7 +61,8 @@ namespace Heap { #define ModuleMembers(class, Member) \ Member(class, NoMark, CompiledData::CompilationUnit *, unit) \ - Member(class, Pointer, CallContext *, scope) + Member(class, Pointer, CallContext *, scope) \ + Member(class, HeapValue, HeapValue, self) DECLARE_EXPORTED_HEAP_OBJECT(Module, Object) { DECLARE_MARKOBJECTS(Module) @@ -73,6 +74,17 @@ DECLARE_EXPORTED_HEAP_OBJECT(Module, Object) { struct Q_QML_EXPORT Module : public Object { V4_OBJECT2(Module, Object) + + static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty); + static PropertyAttributes virtualGetOwnProperty(Managed *m, PropertyKey id, Property *p); + static bool virtualPreventExtensions(Managed *); + static bool virtualDefineOwnProperty(Managed *, PropertyKey, const Property *, PropertyAttributes); + static bool virtualPut(Managed *, PropertyKey, const Value &, Value *); + static bool virtualDeleteProperty(Managed *m, PropertyKey id); + static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *); + static Heap::Object *virtualGetPrototypeOf(const Managed *); + static bool virtualSetPrototypeOf(Managed *, const Object *proto); + static bool virtualIsExtensible(const Managed *); }; } |