{
Instruction::StoreUrl instr;
QString string = v->value.asString();
+ // Encoded dir-separators defeat QUrl processing - decode them first
+ string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
instr.propertyIndex = prop->index;
instr.value = output->indexForUrl(u);
return true;
}
-void QQmlCompiler::genObject(QQmlScript::Object *obj)
+void QQmlCompiler::genObject(QQmlScript::Object *obj, bool parentToSuper)
{
QQmlCompiledData::TypeReference &tr = output->types[obj->type];
if (tr.type && obj->metatype->metaObject() == &QQmlComponent::staticMetaObject) {
create.type = obj->type;
create.line = obj->location.start.line;
create.column = obj->location.start.column;
+ create.parentToSuper = parentToSuper;
output->addInstruction(create);
} else {
create.data = output->indexForByteArray(obj->custom);
create.type = obj->type;
create.isRoot = (compileState->root == obj);
+ create.parentToSuper = parentToSuper;
output->addInstruction(create);
} else {
Instruction::CreateQMLObject create;
pop.type = prop->type;
pop.bindingSkipList = 0;
output->addInstruction(pop);
+
+ genPropertyAssignment(prop, obj);
}
void QQmlCompiler::genComponent(QQmlScript::Object *obj)
if (prop->value || !prop->values.isOne())
COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
- prop->index = sig->coreIndex;
+ prop->index = propertyCacheForObject(obj)->methodIndexToSignalIndex(sig->coreIndex);
prop->core = *sig;
obj->addSignalProperty(prop);
v->type == Value::ValueInterceptor);
if (v->type == Value::ValueSource) {
- genObject(v->object);
+ genObject(v->object, valueTypeProperty?true:false);
Instruction::StoreValueSource store;
- if (valueTypeProperty) {
+ if (valueTypeProperty)
store.property = genValueTypeData(prop, valueTypeProperty);
- store.owner = 1;
- } else {
+ else
store.property = prop->core;
- store.owner = 0;
- }
QQmlType *valueType = toQmlType(v->object);
store.castValue = valueType->propertyValueSourceCast();
output->addInstruction(store);
} else if (v->type == Value::ValueInterceptor) {
- genObject(v->object);
+ genObject(v->object, valueTypeProperty?true:false);
Instruction::StoreValueInterceptor store;
- if (valueTypeProperty) {
+ if (valueTypeProperty)
store.property = genValueTypeData(prop, valueTypeProperty);
- store.owner = 1;
- } else {
+ else
store.property = prop->core;
- store.owner = 0;
- }
QQmlType *valueType = toQmlType(v->object);
store.castValue = valueType->propertyValueInterceptorCast();
output->addInstruction(store);
if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
if (!prop->values.isEmpty()) {
- if (prop->values.first()->location < prop->value->location) {
- COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
- } else {
- COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
+ // Only error if we are assigning values, and not e.g. a property interceptor
+ for (Property *dotProp = prop->value->properties.first(); dotProp; dotProp = prop->value->properties.next(dotProp)) {
+ if (!dotProp->values.isEmpty()) {
+ if (prop->values.first()->location < prop->value->location) {
+ COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
+ } else {
+ COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
+ }
+ }
}
}
COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
}
-
if (prop->isAlias) {
for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
vtProp->isAlias = true;
COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
prop->value, obj, ctxt.incr()));
+
+ // When building a value type where sub components are declared, this
+ // code path is followed from buildProperty, even if there is a previous
+ // assignment to the value type as a whole. Therefore we need to look
+ // for (and build) assignments to the entire value type before looking
+ // for any onValue assignments.
+ for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
+ if (v->object) {
+ COMPILE_EXCEPTION(v->object, tr("Objects cannot be assigned to value types"));
+ }
+ COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
+ }
+
+ for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
+ Q_ASSERT(v->object);
+ COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
+ }
+
obj->addValueTypeProperty(prop);
+
} else {
COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
}
return true;
}
+struct StaticQtMetaObject : public QObject
+{
+ static const QMetaObject *get()
+ { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
+};
+
bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
QQmlScript::Object *obj,
QQmlScript::Value *v,
if (isIntProp) {
// Allow enum assignment to ints.
- int enumval = evaluateEnum(typeName, enumValue.toUtf8());
- if (enumval != -1) {
+ bool ok;
+ int enumval = evaluateEnum(typeName, enumValue.toUtf8(), &ok);
+ if (ok) {
v->type = Value::Literal;
v->value = QQmlScript::Variant((double)enumval);
*isAssignment = true;
QQmlType *type = 0;
unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
- if (!type)
+ if (!type && typeName != QLatin1String("Qt"))
return true;
int value = 0;
- bool ok;
+ bool ok = false;
- if (toQmlType(obj) == type) {
+ if (type && toQmlType(obj) == type) {
// When these two match, we can short cut the search
if (mprop.isFlagType()) {
value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
}
} else {
// Otherwise we have to search the whole type
- // This matches the logic in QV8TypeWrapper
- QByteArray enumName = enumValue.toUtf8();
- const QMetaObject *metaObject = type->baseMetaObject();
- ok = false;
- for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
- QMetaEnum e = metaObject->enumerator(ii);
- value = e.keyToValue(enumName.constData(), &ok);
+ if (type) {
+ value = type->enumValue(QHashedStringRef(enumValue), &ok);
+ } else {
+ QByteArray enumName = enumValue.toUtf8();
+ const QMetaObject *metaObject = StaticQtMetaObject::get();
+ for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
+ QMetaEnum e = metaObject->enumerator(ii);
+ value = e.keyToValue(enumName.constData(), &ok);
+ }
}
}
return true;
}
-struct StaticQtMetaObject : public QObject
-{
- static const QMetaObject *get()
- { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
-};
-
// Similar logic to above, but not knowing target property.
-int QQmlCompiler::evaluateEnum(const QHashedStringRef &scope, const QByteArray& enumValue) const
+int QQmlCompiler::evaluateEnum(const QHashedStringRef &scope, const QByteArray& enumValue, bool *ok) const
{
- QQmlType *type = 0;
+ Q_ASSERT_X(ok, "QQmlCompiler::evaluateEnum", "ok must not be a null pointer");
+ *ok = false;
+
if (scope != QLatin1String("Qt")) {
+ QQmlType *type = 0;
unit->imports().resolveType(scope, &type, 0, 0, 0, 0);
- if (!type)
- return -1;
-
+ return type ? type->enumValue(QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1;
}
- const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
+
+ const QMetaObject *mo = StaticQtMetaObject::get();
int i = mo->enumeratorCount();
while (i--) {
- bool ok;
- int v = mo->enumerator(i).keyToValue(enumValue.constData(), &ok);
- if (ok)
+ int v = mo->enumerator(i).keyToValue(enumValue.constData(), ok);
+ if (*ok)
return v;
}
return -1;
// Dynamic properties (except var and aliases)
- effectiveMethodIndex = cache->methodIndexCacheStart;
+ int effectiveSignalIndex = cache->signalHandlerIndexCacheStart;
for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
p = obj->dynamicProperties.next(p)) {
p->name.hash());
if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16();
cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
- propertyType, effectiveMethodIndex);
+ propertyType, effectiveSignalIndex);
} else {
QString propertyName = p->name.toString();
if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName;
cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
- propertyType, effectiveMethodIndex);
+ propertyType, effectiveSignalIndex);
}
- effectiveMethodIndex++;
+ effectiveSignalIndex++;
VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
(vmd->propertyData() + vmd->propertyCount)->propertyType = vmePropertyType;
p->name.hash());
if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16();
cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
- QMetaType::QVariant, effectiveMethodIndex);
+ QMetaType::QVariant, effectiveSignalIndex);
} else {
QString propertyName = p->name.toString();
if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName;
cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
- QMetaType::QVariant, effectiveMethodIndex);
+ QMetaType::QVariant, effectiveSignalIndex);
}
- effectiveMethodIndex++;
+ effectiveSignalIndex++;
}
// Alias property count. Actual data is setup in buildDynamicMetaAliases
QQmlPropertyCache *cache = obj->synthCache;
char *cStringData = cache->_dynamicStringData.data();
- int effectiveMethodIndex = cache->methodIndexCacheStart + cache->propertyIndexCache.count();
+ int effectiveSignalIndex = cache->signalHandlerIndexCacheStart + cache->propertyIndexCache.count();
int effectivePropertyIndex = cache->propertyIndexCacheStart + cache->propertyIndexCache.count();
int effectiveAliasIndex = 0;
p->name.hash());
if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16();
cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
- type, effectiveMethodIndex++);
+ type, effectiveSignalIndex++);
} else {
QString propertyName = p->name.toString();
if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName;
cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
- type, effectiveMethodIndex++);
+ type, effectiveSignalIndex++);
}
}
Instruction::StoreV4Binding store;
store.value = js.compiledIndex;
+ store.fallbackValue = js.sharedIndex;
store.context = js.bindingContext.stack;
store.owner = js.bindingContext.owner;
store.isAlias = prop->isAlias;
store.line = binding->location.start.line;
store.column = binding->location.start.column;
output->addInstruction(store);
+
+ if (store.fallbackValue > -1) {
+ //also create v8 instruction (needed to properly configure the fallback v8 binding)
+ JSBindingReference &js = static_cast<JSBindingReference &>(*binding->bindingReference);
+ js.dataType = BindingReference::V8;
+ genBindingAssignment(binding, prop, obj, valueTypeProperty);
+ }
} else if (ref.dataType == BindingReference::V8) {
const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
Instruction::StoreV8Binding store;
- store.value = js.compiledIndex;
+ store.value = js.sharedIndex;
store.context = js.bindingContext.stack;
store.owner = js.bindingContext.owner;
store.isAlias = prop->isAlias;
} else {
store.isRoot = (compileState->root == obj);
}
+ store.isFallback = js.compiledIndex > -1;
store.line = binding->location.start.line;
store.column = binding->location.start.column;
} else {
store.isRoot = (compileState->root == obj);
}
+ store.isFallback = false;
Q_ASSERT(js.bindingContext.owner == 0 ||
(js.bindingContext.owner != 0 && valueTypeProperty));
expr.property = binding.property;
expr.expression = binding.expression;
- int index = bindingCompiler.compile(expr, enginePrivate);
+ bool needsFallback = false;
+ int index = bindingCompiler.compile(expr, enginePrivate, &needsFallback);
if (index != -1) {
+ // Ensure the index value fits within the available space
+ Q_ASSERT(index < (1 << 15));
+
binding.dataType = BindingReference::V4;
binding.compiledIndex = index;
+ binding.sharedIndex = -1;
if (componentStats)
componentStats->componentStat.optimizedBindings.append(b->value->location);
- continue;
+
+ if (!needsFallback)
+ continue;
+
+ // Drop through. We need to create a V8 binding in case the V4 binding is invalidated
}
// Pre-rewrite the expression
binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
if (isSharable && binding.property->type != qMetaTypeId<QQmlBinding*>()) {
- binding.dataType = BindingReference::V8;
sharedBindings.append(b);
- if (componentStats)
- componentStats->componentStat.sharedBindings.append(b->value->location);
+ if (!needsFallback) {
+ binding.dataType = BindingReference::V8;
+ binding.compiledIndex = -1;
+
+ if (componentStats)
+ componentStats->componentStat.sharedBindings.append(b->value->location);
+ }
} else {
+ Q_ASSERT(!needsFallback);
binding.dataType = BindingReference::QtScript;
if (componentStats)
functionArray += expression.toUtf8();
lineNumber += expression.count(QLatin1Char('\n'));
- reference->compiledIndex = ii;
+
+ // Ensure the index value fits within the available space
+ Q_ASSERT(ii < (1 << 15));
+ reference->sharedIndex = ii;
}
functionArray.append("]", 1);
return rv;
}
+QQmlPropertyCache *
+QQmlCompiler::propertyCacheForObject(QQmlScript::Object *object)
+ {
+ if (object->synthCache)
+ return object->synthCache;
+ else if (object->type != -1)
+ return output->types[object->type].createPropertyCache(engine);
+ else
+ return object->metatype;
+}
+
QQmlPropertyData *
QQmlCompiler::property(QQmlScript::Object *object, int index)
{
- QQmlPropertyCache *cache = 0;
-
- if (object->synthCache)
- cache = object->synthCache;
- else if (object->type != -1)
- cache = output->types[object->type].createPropertyCache(engine);
- else
- cache = object->metatype;
+ QQmlPropertyCache *cache = propertyCacheForObject(object);
return cache->property(index);
}
{
if (notInRevision) *notInRevision = false;
- QQmlPropertyCache *cache = 0;
-
- if (object->synthCache)
- cache = object->synthCache;
- else if (object->type != -1)
- cache = output->types[object->type].createPropertyCache(engine);
- else
- cache = object->metatype;
+ QQmlPropertyCache *cache = propertyCacheForObject(object);
QQmlPropertyData *d = cache->property(name);
{
if (notInRevision) *notInRevision = false;
- QQmlPropertyCache *cache = 0;
-
- if (object->synthCache)
- cache = object->synthCache;
- else if (object->type != -1)
- cache = output->types[object->type].createPropertyCache(engine);
- else
- cache = object->metatype;
+ QQmlPropertyCache *cache = propertyCacheForObject(object);
QQmlPropertyData *d = cache->property(name);
if (d && !cache->isAllowedInRevision(d)) {
if (notInRevision) *notInRevision = true;
return 0;
- } else if (d) {
+ } else if (d && d->isSignal()) {
return d;
}
d = property(object, propName, notInRevision);
if (d)
- return cache->method(d->notifyIndex);
+ return cache->signal(d->notifyIndex);
}
return 0;