diff options
Diffstat (limited to 'src/qml/compiler/qqmlirbuilder.cpp')
-rw-r--r-- | src/qml/compiler/qqmlirbuilder.cpp | 149 |
1 files changed, 140 insertions, 9 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 092c0020fa..57121e5460 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -45,6 +45,7 @@ #include <private/qqmljslexer_p.h> #include <QCoreApplication> #include <QCryptographicHash> +#include <cmath> #ifndef V4_BOOTSTRAP #include <private/qqmlglobal_p.h> @@ -86,6 +87,7 @@ void Object::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int idIndex, cons flags = QV4::CompiledData::Object::NoFlag; properties = pool->New<PoolList<Property> >(); aliases = pool->New<PoolList<Alias> >(); + qmlEnums = pool->New<PoolList<Enum>>(); qmlSignals = pool->New<PoolList<Signal> >(); bindings = pool->New<PoolList<Binding> >(); functions = pool->New<PoolList<Function> >(); @@ -118,6 +120,21 @@ QString Object::sanityCheckFunctionNames(const QSet<QString> &illegalNames, QQml return QString(); // no error } +QString Object::appendEnum(Enum *enumeration) +{ + Object *target = declarationsOverride; + if (!target) + target = this; + + for (Enum *e = qmlEnums->first; e; e = e->next) { + if (e->nameIndex == enumeration->nameIndex) + return tr("Duplicate scoped enum name"); + } + + target->qmlEnums->append(enumeration); + return QString(); // no error +} + QString Object::appendSignal(Signal *signal) { Object *target = declarationsOverride; @@ -711,6 +728,52 @@ static QStringList astNodeToStringList(QQmlJS::AST::Node *node) return QStringList(); } +bool IRBuilder::visit(QQmlJS::AST::UiEnumDeclaration *node) +{ + Enum *enumeration = New<Enum>(); + QString enumName = node->name.toString(); + enumeration->nameIndex = registerString(enumName); + + if (enumName.at(0).isLower()) + COMPILE_EXCEPTION(node->enumToken, tr("Scoped enum names must begin with an upper case letter")); + + enumeration->location.line = node->enumToken.startLine; + enumeration->location.column = node->enumToken.startColumn; + + enumeration->enumValues = New<PoolList<EnumValue>>(); + + QQmlJS::AST::UiEnumMemberList *e = node->members; + while (e) { + EnumValue *enumValue = New<EnumValue>(); + QString member = e->member.toString(); + enumValue->nameIndex = registerString(member); + if (member.at(0).isLower()) + COMPILE_EXCEPTION(e->memberToken, tr("Enum names must begin with an upper case letter")); + + double part; + if (std::modf(e->value, &part) != 0.0) + COMPILE_EXCEPTION(e->valueToken, tr("Enum value must be an integer")); + if (e->value > std::numeric_limits<qint32>::max() || e->value < std::numeric_limits<qint32>::min()) + COMPILE_EXCEPTION(e->valueToken, tr("Enum value out of range")); + enumValue->value = e->value; + + enumValue->location.line = e->memberToken.startLine; + enumValue->location.column = e->memberToken.startColumn; + enumeration->enumValues->append(enumValue); + + e = e->next; + } + + QString error = _object->appendEnum(enumeration); + if (!error.isEmpty()) { + recordError(node->enumToken, error); + return false; + } + + return false; +} + + bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node) { static const struct TypeNameToType { @@ -1377,13 +1440,19 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output, const QV4: int objectsSize = 0; for (Object *o : qAsConst(output.objects)) { objectOffsets.insert(o, unitSize + importSize + objectOffsetTableSize + objectsSize); - objectsSize += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->aliasCount(), o->signalCount(), o->bindingCount(), o->namedObjectsInComponent.count); + objectsSize += QV4::CompiledData::Object::calculateSizeExcludingSignalsAndEnums(o->functionCount(), o->propertyCount(), o->aliasCount(), o->enumCount(), o->signalCount(), o->bindingCount(), o->namedObjectsInComponent.count); int signalTableSize = 0; for (const Signal *s = o->firstSignal(); s; s = s->next) signalTableSize += QV4::CompiledData::Signal::calculateSize(s->parameters->count); objectsSize += signalTableSize; + + int enumTableSize = 0; + for (const Enum *e = o->firstEnum(); e; e = e->next) + enumTableSize += QV4::CompiledData::Enum::calculateSize(e->enumValues->count); + + objectsSize += enumTableSize; } const int totalSize = unitSize + importSize + objectOffsetTableSize + objectsSize + output.jsGenerator.stringTable.sizeOfTableAndData(); @@ -1426,7 +1495,7 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output, const QV4: } // write objects - QV4::CompiledData::LEUInt32 *objectTable = reinterpret_cast<QV4::CompiledData::LEUInt32*>(data + qmlUnit->offsetToObjects); + quint32_le *objectTable = reinterpret_cast<quint32_le*>(data + qmlUnit->offsetToObjects); char *objectPtr = data + qmlUnit->offsetToObjects + objectOffsetTableSize; for (int i = 0; i < output.objects.count(); ++i) { const Object *o = output.objects.at(i); @@ -1456,6 +1525,10 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output, const QV4: objectToWrite->offsetToAliases = nextOffset; nextOffset += objectToWrite->nAliases * sizeof(QV4::CompiledData::Alias); + objectToWrite->nEnums = o->enumCount(); + objectToWrite->offsetToEnums = nextOffset; + nextOffset += objectToWrite->nEnums * sizeof(quint32); + objectToWrite->nSignals = o->signalCount(); objectToWrite->offsetToSignals = nextOffset; nextOffset += objectToWrite->nSignals * sizeof(quint32); @@ -1468,7 +1541,7 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output, const QV4: objectToWrite->offsetToNamedObjectsInComponent = nextOffset; nextOffset += objectToWrite->nNamedObjectsInComponent * sizeof(quint32); - QV4::CompiledData::LEUInt32 *functionsTable = reinterpret_cast<QV4::CompiledData::LEUInt32*>(objectPtr + objectToWrite->offsetToFunctions); + quint32_le *functionsTable = reinterpret_cast<quint32_le *>(objectPtr + objectToWrite->offsetToFunctions); for (const Function *f = o->firstFunction(); f; f = f->next) *functionsTable++ = o->runtimeFunctionIndices.at(f->index); @@ -1494,7 +1567,7 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output, const QV4: bindingPtr = writeBindings(bindingPtr, o, &QV4::CompiledData::Binding::isValueBindingToAlias); Q_ASSERT((bindingPtr - objectToWrite->offsetToBindings - objectPtr) / sizeof(QV4::CompiledData::Binding) == unsigned(o->bindingCount())); - QV4::CompiledData::LEUInt32 *signalOffsetTable = reinterpret_cast<QV4::CompiledData::LEUInt32*>(objectPtr + objectToWrite->offsetToSignals); + quint32_le *signalOffsetTable = reinterpret_cast<quint32_le *>(objectPtr + objectToWrite->offsetToSignals); quint32 signalTableSize = 0; char *signalPtr = objectPtr + nextOffset; for (const Signal *s = o->firstSignal(); s; s = s->next) { @@ -1513,14 +1586,36 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output, const QV4: signalTableSize += size; signalPtr += size; } + nextOffset += signalTableSize; + + quint32_le *enumOffsetTable = reinterpret_cast<quint32_le*>(objectPtr + objectToWrite->offsetToEnums); + quint32 enumTableSize = 0; + char *enumPtr = objectPtr + nextOffset; + for (const Enum *e = o->firstEnum(); e; e = e->next) { + *enumOffsetTable++ = enumPtr - objectPtr; + QV4::CompiledData::Enum *enumToWrite = reinterpret_cast<QV4::CompiledData::Enum*>(enumPtr); + + enumToWrite->nameIndex = e->nameIndex; + enumToWrite->location = e->location; + enumToWrite->nEnumValues = e->enumValues->count; + + QV4::CompiledData::EnumValue *enumValueToWrite = reinterpret_cast<QV4::CompiledData::EnumValue*>(enumPtr + sizeof(*enumToWrite)); + for (EnumValue *enumValue = e->enumValues->first; enumValue; enumValue = enumValue->next, ++enumValueToWrite) + *enumValueToWrite = *enumValue; + + int size = QV4::CompiledData::Enum::calculateSize(e->enumValues->count); + enumTableSize += size; + enumPtr += size; + } - QV4::CompiledData::LEUInt32 *namedObjectInComponentPtr = reinterpret_cast<QV4::CompiledData::LEUInt32*>(objectPtr + objectToWrite->offsetToNamedObjectsInComponent); + quint32_le *namedObjectInComponentPtr = reinterpret_cast<quint32_le *>(objectPtr + objectToWrite->offsetToNamedObjectsInComponent); for (int i = 0; i < o->namedObjectsInComponent.count; ++i) { *namedObjectInComponentPtr++ = o->namedObjectsInComponent.at(i); } - objectPtr += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->aliasCount(), o->signalCount(), o->bindingCount(), o->namedObjectsInComponent.count); + objectPtr += QV4::CompiledData::Object::calculateSizeExcludingSignalsAndEnums(o->functionCount(), o->propertyCount(), o->aliasCount(), o->enumCount(), o->signalCount(), o->bindingCount(), o->namedObjectsInComponent.count); objectPtr += signalTableSize; + objectPtr += enumTableSize; } // enable flag if we encountered pragma Singleton @@ -1605,7 +1700,7 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil scan.leaveEnvironment(); scan.leaveEnvironment(); - _env = 0; + _variableEnvironment = 0; _function = _module->functions.at(defineFunction(QStringLiteral("context scope"), qmlRoot, 0, 0)); for (int i = 0; i < functions.count(); ++i) { @@ -1688,6 +1783,7 @@ enum MetaObjectResolverFlags { }; static void initMetaObjectResolver(QV4::IR::MemberExpressionResolver *resolver, QQmlPropertyCache *metaObject); +static void initScopedEnumResolver(QV4::IR::MemberExpressionResolver *resolver, const QQmlType &qmlType, int index); static QV4::IR::DiscoveredType resolveQmlType(QQmlEnginePrivate *qmlEngine, const QV4::IR::MemberExpressionResolver *resolver, @@ -1703,6 +1799,14 @@ static QV4::IR::DiscoveredType resolveQmlType(QQmlEnginePrivate *qmlEngine, if (ok) { member->setEnumValue(value); return QV4::IR::SInt32Type; + } else { + int index = type.scopedEnumIndex(qmlEngine, *member->name, &ok); + if (ok) { + auto newResolver = resolver->owner->New<QV4::IR::MemberExpressionResolver>(); + newResolver->owner = resolver->owner; + initScopedEnumResolver(newResolver, type, index); + return QV4::IR::DiscoveredType(newResolver); + } } } @@ -1886,6 +1990,33 @@ static void initMetaObjectResolver(QV4::IR::MemberExpressionResolver *resolver, resolver->flags = 0; } +static QV4::IR::DiscoveredType resolveScopedEnum(QQmlEnginePrivate *qmlEngine, + const QV4::IR::MemberExpressionResolver *resolver, + QV4::IR::Member *member) +{ + if (!member->name->constData()->isUpper()) + return QV4::IR::VarType; + + QQmlType type = resolver->qmlType; + int index = resolver->flags; + + bool ok = false; + int value = type.scopedEnumValue(qmlEngine, index, *member->name, &ok); + if (!ok) + return QV4::IR::VarType; + member->setEnumValue(value); + return QV4::IR::SInt32Type; +} + +static void initScopedEnumResolver(QV4::IR::MemberExpressionResolver *resolver, const QQmlType &qmlType, int index) +{ + Q_ASSERT(resolver); + + resolver->resolveMember = &resolveScopedEnum; + resolver->qmlType = qmlType; + resolver->flags = index; +} + #endif // V4_BOOTSTRAP void JSCodeGen::beginFunctionBodyHook() @@ -2187,7 +2318,7 @@ QmlIR::Object *IRLoader::loadObject(const QV4::CompiledData::Object *serializedO QQmlJS::Engine *jsParserEngine = &output->jsParserEngine; - const QV4::CompiledData::LEUInt32 *functionIdx = serializedObject->functionOffsetTable(); + const quint32_le *functionIdx = serializedObject->functionOffsetTable(); for (uint i = 0; i < serializedObject->nFunctions; ++i, ++functionIdx) { QmlIR::Function *f = pool->New<QmlIR::Function>(); const QV4::CompiledData::Function *compiledFunction = unit->functionAt(*functionIdx); @@ -2198,7 +2329,7 @@ QmlIR::Object *IRLoader::loadObject(const QV4::CompiledData::Object *serializedO f->nameIndex = compiledFunction->nameIndex; QQmlJS::AST::FormalParameterList *paramList = 0; - const QV4::CompiledData::LEUInt32 *formalNameIdx = compiledFunction->formalsTable(); + const quint32_le *formalNameIdx = compiledFunction->formalsTable(); for (uint i = 0; i < compiledFunction->nFormals; ++i, ++formalNameIdx) { const QString formal = unit->stringAt(*formalNameIdx); QStringRef paramNameRef = jsParserEngine->newStringRef(formal); |