1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 #include "private/qdeclarativecompiler_p.h"
44 #include "private/qdeclarativeparser_p.h"
45 #include "private/qdeclarativescriptparser_p.h"
46 #include "qdeclarativepropertyvaluesource.h"
47 #include "qdeclarativecomponent.h"
48 #include "private/qmetaobjectbuilder_p.h"
49 #include "private/qdeclarativestringconverters_p.h"
50 #include "private/qdeclarativeengine_p.h"
51 #include "qdeclarativeengine.h"
52 #include "qdeclarativecontext.h"
53 #include "private/qdeclarativemetatype_p.h"
54 #include "private/qdeclarativecustomparser_p_p.h"
55 #include "private/qdeclarativecontext_p.h"
56 #include "private/qdeclarativecomponent_p.h"
57 #include "parser/qdeclarativejsast_p.h"
58 #include "private/qdeclarativevmemetaobject_p.h"
59 #include "private/qdeclarativeexpression_p.h"
60 #include "private/qdeclarativeproperty_p.h"
61 #include "private/qdeclarativerewrite_p.h"
62 #include "qdeclarativescriptstring.h"
63 #include "private/qdeclarativeglobal_p.h"
64 #include "private/qdeclarativescriptparser_p.h"
65 #include "private/qdeclarativebinding_p.h"
66 #include "private/qdeclarativecompiledbindings_p.h"
67 #include "private/qdeclarativeglobalscriptclass_p.h"
75 #include <QtCore/qdebug.h>
76 #include <QtCore/qdatetime.h>
80 DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP);
81 DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS);
82 DEFINE_BOOL_CONFIG_OPTION(bindingsDump, QML_BINDINGS_DUMP);
84 using namespace QDeclarativeParser;
87 Instantiate a new QDeclarativeCompiler.
89 QDeclarativeCompiler::QDeclarativeCompiler()
90 : output(0), engine(0), unitRoot(0), unit(0)
95 Returns true if the last call to compile() caused errors.
99 bool QDeclarativeCompiler::isError() const
101 return !exceptions.isEmpty();
105 Return the list of errors from the last call to compile(), or an empty list
106 if there were no errors.
108 QList<QDeclarativeError> QDeclarativeCompiler::errors() const
114 Returns true if \a name refers to an attached property, false otherwise.
116 Attached property names are those that start with a capital letter.
118 bool QDeclarativeCompiler::isAttachedPropertyName(const QByteArray &name)
120 return !name.isEmpty() && name.at(0) >= 'A' && name.at(0) <= 'Z';
124 Returns true if \a name refers to a signal property, false otherwise.
126 Signal property names are those that start with "on", followed by a capital
129 bool QDeclarativeCompiler::isSignalPropertyName(const QByteArray &name)
131 return name.length() >= 3 && name.startsWith("on") &&
132 'A' <= name.at(2) && 'Z' >= name.at(2);
136 \macro COMPILE_EXCEPTION
138 Inserts an error into the QDeclarativeCompiler error list, and returns false
141 \a token is used to source the error line and column, and \a desc is the
142 error itself. \a desc can be an expression that can be piped into QDebug.
147 COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(QString::fromUtf8(property->name)));
150 #define COMPILE_EXCEPTION(token, desc) \
152 QString exceptionDescription; \
153 QDeclarativeError error; \
154 error.setUrl(output->url); \
155 error.setLine((token)->location.start.line); \
156 error.setColumn((token)->location.start.column); \
157 error.setDescription(desc.trimmed()); \
158 exceptions << error; \
165 Returns false if \a is false, otherwise does nothing.
167 #define COMPILE_CHECK(a) \
169 if (!a) return false; \
173 Returns true if literal \a v can be assigned to property \a prop, otherwise
176 This test corresponds to action taken by genLiteralAssignment(). Any change
177 made here, must have a corresponding action in genLiteralAssigment().
179 bool QDeclarativeCompiler::testLiteralAssignment(const QMetaProperty &prop,
180 QDeclarativeParser::Value *v)
182 QString string = v->value.asString();
184 if (!prop.isWritable())
185 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
187 if (prop.isEnumType()) {
189 if (prop.isFlagType()) {
190 value = prop.enumerator().keysToValue(string.toUtf8().constData());
192 value = prop.enumerator().keyToValue(string.toUtf8().constData());
194 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration"));
197 int type = prop.userType();
201 case QVariant::String:
202 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
205 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected"));
209 bool ok = v->value.isNumber();
211 double n = v->value.asNumber();
212 if (double(uint(n)) != n)
215 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected"));
220 bool ok = v->value.isNumber();
222 double n = v->value.asNumber();
223 if (double(int(n)) != n)
226 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected"));
229 case QMetaType::Float:
230 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
232 case QVariant::Double:
233 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
235 case QVariant::Color:
238 QDeclarativeStringConverters::colorFromString(string, &ok);
239 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected"));
242 #ifndef QT_NO_DATESTRING
246 QDeclarativeStringConverters::dateFromString(string, &ok);
247 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected"));
253 QDeclarativeStringConverters::timeFromString(string, &ok);
254 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected"));
257 case QVariant::DateTime:
260 QDeclarativeStringConverters::dateTimeFromString(string, &ok);
261 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected"));
264 #endif // QT_NO_DATESTRING
265 case QVariant::Point:
266 case QVariant::PointF:
269 QPointF point = QDeclarativeStringConverters::pointFFromString(string, &ok);
270 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected"));
274 case QVariant::SizeF:
277 QSizeF size = QDeclarativeStringConverters::sizeFFromString(string, &ok);
278 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected"));
282 case QVariant::RectF:
285 QRectF rect = QDeclarativeStringConverters::rectFFromString(string, &ok);
286 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected"));
291 if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected"));
294 case QVariant::Vector3D:
297 QDeclarativeStringConverters::vector3DFromString(string, &ok);
298 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected"));
303 int t = prop.userType();
304 QDeclarativeMetaType::StringConverter converter =
305 QDeclarativeMetaType::customStringConverter(t);
307 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName(prop.type()))));
315 Generate a store instruction for assigning literal \a v to property \a prop.
317 Any literal assignment that is approved in testLiteralAssignment() must have
318 a corresponding action in this method.
320 void QDeclarativeCompiler::genLiteralAssignment(const QMetaProperty &prop,
321 QDeclarativeParser::Value *v)
323 QString string = v->value.asString();
325 QDeclarativeInstruction instr;
326 instr.line = v->location.start.line;
327 if (prop.isEnumType()) {
329 if (prop.isFlagType()) {
330 value = prop.enumerator().keysToValue(string.toUtf8().constData());
332 value = prop.enumerator().keyToValue(string.toUtf8().constData());
334 instr.type = QDeclarativeInstruction::StoreInteger;
335 instr.storeInteger.propertyIndex = prop.propertyIndex();
336 instr.storeInteger.value = value;
337 output->bytecode << instr;
341 int type = prop.userType();
345 if (v->value.isNumber()) {
346 double n = v->value.asNumber();
347 if (double(int(n)) == n) {
348 instr.type = QDeclarativeInstruction::StoreVariantInteger;
349 instr.storeInteger.propertyIndex = prop.propertyIndex();
350 instr.storeInteger.value = int(n);
352 instr.type = QDeclarativeInstruction::StoreVariantDouble;
353 instr.storeDouble.propertyIndex = prop.propertyIndex();
354 instr.storeDouble.value = n;
356 } else if(v->value.isBoolean()) {
357 instr.type = QDeclarativeInstruction::StoreVariantBool;
358 instr.storeBool.propertyIndex = prop.propertyIndex();
359 instr.storeBool.value = v->value.asBoolean();
361 instr.type = QDeclarativeInstruction::StoreVariant;
362 instr.storeString.propertyIndex = prop.propertyIndex();
363 instr.storeString.value = output->indexForString(string);
367 case QVariant::String:
369 instr.type = QDeclarativeInstruction::StoreString;
370 instr.storeString.propertyIndex = prop.propertyIndex();
371 instr.storeString.value = output->indexForString(string);
376 instr.type = QDeclarativeInstruction::StoreUrl;
377 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
378 instr.storeUrl.propertyIndex = prop.propertyIndex();
379 instr.storeUrl.value = output->indexForUrl(u);
384 instr.type = QDeclarativeInstruction::StoreInteger;
385 instr.storeInteger.propertyIndex = prop.propertyIndex();
386 instr.storeInteger.value = uint(v->value.asNumber());
391 instr.type = QDeclarativeInstruction::StoreInteger;
392 instr.storeInteger.propertyIndex = prop.propertyIndex();
393 instr.storeInteger.value = int(v->value.asNumber());
396 case QMetaType::Float:
398 instr.type = QDeclarativeInstruction::StoreFloat;
399 instr.storeFloat.propertyIndex = prop.propertyIndex();
400 instr.storeFloat.value = float(v->value.asNumber());
403 case QVariant::Double:
405 instr.type = QDeclarativeInstruction::StoreDouble;
406 instr.storeDouble.propertyIndex = prop.propertyIndex();
407 instr.storeDouble.value = v->value.asNumber();
410 case QVariant::Color:
412 QColor c = QDeclarativeStringConverters::colorFromString(string);
413 instr.type = QDeclarativeInstruction::StoreColor;
414 instr.storeColor.propertyIndex = prop.propertyIndex();
415 instr.storeColor.value = c.rgba();
418 #ifndef QT_NO_DATESTRING
421 QDate d = QDeclarativeStringConverters::dateFromString(string);
422 instr.type = QDeclarativeInstruction::StoreDate;
423 instr.storeDate.propertyIndex = prop.propertyIndex();
424 instr.storeDate.value = d.toJulianDay();
429 QTime time = QDeclarativeStringConverters::timeFromString(string);
430 int data[] = { time.hour(), time.minute(),
431 time.second(), time.msec() };
432 int index = output->indexForInt(data, 4);
433 instr.type = QDeclarativeInstruction::StoreTime;
434 instr.storeTime.propertyIndex = prop.propertyIndex();
435 instr.storeTime.valueIndex = index;
438 case QVariant::DateTime:
440 QDateTime dateTime = QDeclarativeStringConverters::dateTimeFromString(string);
441 int data[] = { dateTime.date().toJulianDay(),
442 dateTime.time().hour(),
443 dateTime.time().minute(),
444 dateTime.time().second(),
445 dateTime.time().msec() };
446 int index = output->indexForInt(data, 5);
447 instr.type = QDeclarativeInstruction::StoreDateTime;
448 instr.storeDateTime.propertyIndex = prop.propertyIndex();
449 instr.storeDateTime.valueIndex = index;
452 #endif // QT_NO_DATESTRING
453 case QVariant::Point:
454 case QVariant::PointF:
458 QDeclarativeStringConverters::pointFFromString(string, &ok);
459 float data[] = { float(point.x()), float(point.y()) };
460 int index = output->indexForFloat(data, 2);
461 if (type == QVariant::PointF)
462 instr.type = QDeclarativeInstruction::StorePointF;
464 instr.type = QDeclarativeInstruction::StorePoint;
465 instr.storeRealPair.propertyIndex = prop.propertyIndex();
466 instr.storeRealPair.valueIndex = index;
470 case QVariant::SizeF:
473 QSizeF size = QDeclarativeStringConverters::sizeFFromString(string, &ok);
474 float data[] = { float(size.width()), float(size.height()) };
475 int index = output->indexForFloat(data, 2);
476 if (type == QVariant::SizeF)
477 instr.type = QDeclarativeInstruction::StoreSizeF;
479 instr.type = QDeclarativeInstruction::StoreSize;
480 instr.storeRealPair.propertyIndex = prop.propertyIndex();
481 instr.storeRealPair.valueIndex = index;
485 case QVariant::RectF:
488 QRectF rect = QDeclarativeStringConverters::rectFFromString(string, &ok);
489 float data[] = { float(rect.x()), float(rect.y()),
490 float(rect.width()), float(rect.height()) };
491 int index = output->indexForFloat(data, 4);
492 if (type == QVariant::RectF)
493 instr.type = QDeclarativeInstruction::StoreRectF;
495 instr.type = QDeclarativeInstruction::StoreRect;
496 instr.storeRect.propertyIndex = prop.propertyIndex();
497 instr.storeRect.valueIndex = index;
502 bool b = v->value.asBoolean();
503 instr.type = QDeclarativeInstruction::StoreBool;
504 instr.storeBool.propertyIndex = prop.propertyIndex();
505 instr.storeBool.value = b;
508 case QVariant::Vector3D:
512 QDeclarativeStringConverters::vector3DFromString(string, &ok);
513 float data[] = { float(vector.x()), float(vector.y()), float(vector.z()) };
514 int index = output->indexForFloat(data, 3);
515 instr.type = QDeclarativeInstruction::StoreVector3D;
516 instr.storeRealPair.propertyIndex = prop.propertyIndex();
517 instr.storeRealPair.valueIndex = index;
522 int t = prop.userType();
523 int index = output->customTypeData.count();
524 instr.type = QDeclarativeInstruction::AssignCustomType;
525 instr.assignCustomType.propertyIndex = prop.propertyIndex();
526 instr.assignCustomType.valueIndex = index;
528 QDeclarativeCompiledData::CustomTypeData data;
529 data.index = output->indexForString(string);
531 output->customTypeData << data;
535 output->bytecode << instr;
539 Resets data by clearing the lists that the QDeclarativeCompiler modifies.
541 void QDeclarativeCompiler::reset(QDeclarativeCompiledData *data)
544 data->primitives.clear();
545 data->floatData.clear();
546 data->intData.clear();
547 data->customTypeData.clear();
549 data->bytecode.clear();
553 Compile \a unit, and store the output in \a out. \a engine is the QDeclarativeEngine
554 with which the QDeclarativeCompiledData will be associated.
556 Returns true on success, false on failure. On failure, the compile errors
557 are available from errors().
559 If the environment variant QML_COMPILER_DUMP is set
560 (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
561 on a successful compiler.
563 bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine,
564 QDeclarativeTypeData *unit,
565 QDeclarativeCompiledData *out)
575 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
576 QList<QDeclarativeScriptParser::TypeReference *> referencedTypes = unit->parser().referencedTypes();
578 for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
579 QDeclarativeCompiledData::TypeReference ref;
581 const QDeclarativeTypeData::TypeReference &tref = resolvedTypes.at(ii);
582 QDeclarativeScriptParser::TypeReference *parserRef = referencedTypes.at(ii);
585 ref.type = tref.type;
586 if (!ref.type->isCreatable()) {
587 QString err = ref.type->noCreationReason();
589 err = tr( "Element is not creatable.");
590 COMPILE_EXCEPTION(parserRef->refObjects.first(), err);
593 if (ref.type->containsRevisionedAttributes()) {
594 QDeclarativeError cacheError;
595 ref.typePropertyCache =
596 QDeclarativeEnginePrivate::get(engine)->cache(ref.type, resolvedTypes.at(ii).minorVersion, cacheError);
598 if (!ref.typePropertyCache) {
599 COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description());
601 ref.typePropertyCache->addref();
604 } else if (tref.typeData) {
605 ref.component = tref.typeData->compiledData();
607 ref.className = parserRef->name.toUtf8();
611 QDeclarativeParser::Object *root = unit->parser().tree();
614 this->engine = engine;
615 this->enginePrivate = QDeclarativeEnginePrivate::get(engine);
617 this->unitRoot = root;
622 out->dumpInstructions();
623 if (compilerStatDump())
629 compileState = ComponentCompileState();
630 savedCompileStates.clear();
633 this->enginePrivate = 0;
640 void QDeclarativeCompiler::compileTree(QDeclarativeParser::Object *tree)
642 compileState.root = tree;
643 componentStat.lineNumber = tree->location.start.line;
645 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
648 QDeclarativeInstruction init;
649 init.type = QDeclarativeInstruction::Init;
651 init.init.bindingsSize = compileState.bindings.count();
652 init.init.parserStatusSize = compileState.parserStatusCount;
653 init.init.contextCache = genContextCache();
654 if (compileState.compiledBindingData.isEmpty())
655 init.init.compiledBinding = -1;
657 init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData);
658 output->bytecode << init;
660 // Build global import scripts
661 QHash<QString, Object::ScriptBlock> importedScripts;
662 QStringList importedScriptIndexes;
664 foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
665 QString scriptCode = script.script->scriptSource();
666 Object::ScriptBlock::Pragmas pragmas = script.script->pragmas();
668 Q_ASSERT(!importedScripts.contains(script.qualifier));
670 if (!scriptCode.isEmpty()) {
671 Object::ScriptBlock &scriptBlock = importedScripts[script.qualifier];
673 scriptBlock.code = scriptCode;
674 scriptBlock.file = script.script->finalUrl().toString();
675 scriptBlock.pragmas = pragmas;
679 for (QHash<QString, Object::ScriptBlock>::Iterator iter = importedScripts.begin();
680 iter != importedScripts.end(); ++iter) {
682 importedScriptIndexes.append(iter.key());
684 QDeclarativeInstruction import;
685 import.type = QDeclarativeInstruction::StoreImportedScript;
687 import.storeScript.value = output->scripts.count();
688 output->scripts << *iter;
689 output->bytecode << import;
694 QDeclarativeInstruction def;
696 def.type = QDeclarativeInstruction::SetDefault;
697 output->bytecode << def;
699 output->importCache = new QDeclarativeTypeNameCache(engine);
701 for (int ii = 0; ii < importedScriptIndexes.count(); ++ii)
702 output->importCache->add(importedScriptIndexes.at(ii), ii);
704 unit->imports().populateCache(output->importCache, engine);
706 Q_ASSERT(tree->metatype);
708 if (tree->metadata.isEmpty()) {
709 output->root = tree->metatype;
711 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
712 output->root = &output->rootData;
714 if (!tree->metadata.isEmpty())
715 enginePrivate->registerCompositeType(output);
718 static bool ValuePtrLessThan(const QDeclarativeParser::Value *t1, const QDeclarativeParser::Value *t2)
720 return t1->location.start.line < t2->location.start.line ||
721 (t1->location.start.line == t2->location.start.line &&
722 t1->location.start.column < t2->location.start.column);
725 bool QDeclarativeCompiler::buildObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
727 componentStat.objects++;
729 Q_ASSERT (obj->type != -1);
730 const QDeclarativeCompiledData::TypeReference &tr =
731 output->types.at(obj->type);
732 obj->metatype = tr.metaObject();
735 obj->url = tr.component->url;
737 obj->typeName = tr.type->qmlTypeName();
738 obj->className = tr.className;
740 // This object is a "Component" element
741 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
742 COMPILE_CHECK(buildComponent(obj, ctxt));
746 // Object instantiations reset the binding context
747 BindingContext objCtxt(obj);
749 // Create the synthesized meta object, ignoring aliases
750 COMPILE_CHECK(checkDynamicMeta(obj));
751 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
752 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
754 // Find the native type and check for the QDeclarativeParserStatus interface
755 QDeclarativeType *type = toQmlType(obj);
757 obj->parserStatusCast = type->parserStatusCast();
758 if (obj->parserStatusCast != -1)
759 compileState.parserStatusCount++;
761 // Check if this is a custom parser type. Custom parser types allow
762 // assignments to non-existent properties. These assignments are then
763 // compiled by the type.
764 bool isCustomParser = output->types.at(obj->type).type &&
765 output->types.at(obj->type).type->customParser() != 0;
766 QList<QDeclarativeCustomParserProperty> customProps;
768 // Fetch the list of deferred properties
769 QStringList deferredList = deferredProperties(obj);
771 // Must do id property first. This is to ensure that the id given to any
772 // id reference created matches the order in which the objects are
774 foreach(Property *prop, obj->properties) {
775 if (prop->name == "id") {
776 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
782 Property *defaultProperty = 0;
783 Property *skipProperty = 0;
784 if (obj->defaultProperty) {
785 const QMetaObject *metaObject = obj->metaObject();
786 Q_ASSERT(metaObject);
787 QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
789 Property *explicitProperty = obj->getProperty(p.name(), false);
790 if (explicitProperty && !explicitProperty->value) {
791 skipProperty = explicitProperty;
793 defaultProperty = new Property;
794 defaultProperty->parent = obj;
795 defaultProperty->isDefault = true;
796 defaultProperty->location = obj->defaultProperty->location;
797 defaultProperty->listValueRange = obj->defaultProperty->listValueRange;
798 defaultProperty->listCommaPositions = obj->defaultProperty->listCommaPositions;
800 defaultProperty->values = obj->defaultProperty->values;
801 defaultProperty->values += explicitProperty->values;
802 foreach(QDeclarativeParser::Value *value, defaultProperty->values)
804 qSort(defaultProperty->values.begin(), defaultProperty->values.end(), ValuePtrLessThan);
807 defaultProperty = obj->defaultProperty;
808 defaultProperty->addref();
811 defaultProperty = obj->defaultProperty;
812 defaultProperty->addref();
816 QDeclarativeCustomParser *cp = 0;
818 cp = output->types.at(obj->type).type->customParser();
820 // Build all explicit properties specified
821 foreach(Property *prop, obj->properties) {
823 if (prop == skipProperty)
825 if (prop->name == "id")
828 bool canDefer = false;
829 if (isCustomParser) {
830 if (doesPropertyExist(prop, obj) &&
831 (!(cp->flags() & QDeclarativeCustomParser::AcceptsAttachedProperties) ||
832 !isAttachedPropertyName(prop->name))) {
833 int ids = compileState.ids.count();
834 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
835 canDefer = ids == compileState.ids.count();
837 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
840 if (isSignalPropertyName(prop->name)) {
841 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
843 int ids = compileState.ids.count();
844 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
845 canDefer = ids == compileState.ids.count();
849 if (canDefer && !deferredList.isEmpty() &&
850 deferredList.contains(QString::fromUtf8(prop->name)))
851 prop->isDeferred = true;
855 // Build the default property
856 if (defaultProperty) {
857 Property *prop = defaultProperty;
859 bool canDefer = false;
860 if (isCustomParser) {
861 if (doesPropertyExist(prop, obj)) {
862 int ids = compileState.ids.count();
863 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
864 canDefer = ids == compileState.ids.count();
866 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
869 int ids = compileState.ids.count();
870 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
871 canDefer = ids == compileState.ids.count();
874 if (canDefer && !deferredList.isEmpty() &&
875 deferredList.contains(QString::fromUtf8(prop->name)))
876 prop->isDeferred = true;
880 defaultProperty->release();
882 // Compile custom parser parts
883 if (isCustomParser && !customProps.isEmpty()) {
887 obj->custom = cp->compile(customProps);
890 foreach (QDeclarativeError err, cp->errors()) {
891 err.setUrl(output->url);
899 void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj)
901 QDeclarativeCompiledData::TypeReference &tr = output->types[obj->type];
902 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
908 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
909 !output->types.at(obj->type).type->isExtendedType() && obj != compileState.root) {
911 QDeclarativeInstruction create;
912 create.type = QDeclarativeInstruction::CreateSimpleObject;
913 create.line = obj->location.start.line;
914 create.createSimple.create = output->types.at(obj->type).type->createFunction();
915 create.createSimple.typeSize = output->types.at(obj->type).type->createSize();
916 create.createSimple.type = obj->type;
917 create.createSimple.column = obj->location.start.column;
918 output->bytecode << create;
922 QDeclarativeInstruction create;
923 create.type = QDeclarativeInstruction::CreateObject;
924 create.line = obj->location.start.line;
925 create.create.column = obj->location.start.column;
926 create.create.data = -1;
927 if (!obj->custom.isEmpty())
928 create.create.data = output->indexForByteArray(obj->custom);
929 create.create.type = obj->type;
930 if (!output->types.at(create.create.type).type &&
931 !obj->bindingBitmask.isEmpty()) {
932 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
933 create.create.bindingBits =
934 output->indexForByteArray(obj->bindingBitmask);
936 create.create.bindingBits = -1;
938 output->bytecode << create;
942 // Setup the synthesized meta object if necessary
943 if (!obj->metadata.isEmpty()) {
944 QDeclarativeInstruction meta;
945 meta.type = QDeclarativeInstruction::StoreMetaObject;
947 meta.storeMeta.data = output->indexForByteArray(obj->metadata);
948 meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata);
949 meta.storeMeta.propertyCache = output->propertyCaches.count();
951 QDeclarativePropertyCache *propertyCache = obj->synthCache;
952 Q_ASSERT(propertyCache);
953 propertyCache->addref();
955 // Add flag for alias properties
956 if (!obj->synthdata.isEmpty()) {
957 const QDeclarativeVMEMetaData *vmeMetaData =
958 reinterpret_cast<const QDeclarativeVMEMetaData *>(obj->synthdata.constData());
959 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
960 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
961 propertyCache->property(index)->flags |= QDeclarativePropertyCache::Data::IsAlias;
965 if (obj == unitRoot) {
966 propertyCache->addref();
967 output->rootPropertyCache = propertyCache;
970 output->propertyCaches << propertyCache;
971 output->bytecode << meta;
972 } else if (obj == unitRoot) {
973 output->rootPropertyCache = tr.createPropertyCache(engine);
974 output->rootPropertyCache->addref();
978 if (!obj->id.isEmpty()) {
979 QDeclarativeInstruction id;
980 id.type = QDeclarativeInstruction::SetId;
982 id.setId.value = output->indexForString(obj->id);
983 id.setId.index = obj->idIndex;
984 output->bytecode << id;
988 if (tr.type && obj->parserStatusCast != -1) {
989 QDeclarativeInstruction begin;
990 begin.type = QDeclarativeInstruction::BeginObject;
991 begin.begin.castValue = obj->parserStatusCast;
992 begin.line = obj->location.start.line;
993 output->bytecode << begin;
999 void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj)
1001 typedef QPair<Property *, int> PropPair;
1002 foreach(const PropPair &prop, obj->scriptStringProperties) {
1003 QDeclarativeInstruction ss;
1004 ss.type = QDeclarativeInstruction::StoreScriptString;
1005 ss.storeScriptString.propertyIndex = prop.first->index;
1006 ss.storeScriptString.value =
1007 output->indexForString(prop.first->values.at(0)->value.asScript());
1008 ss.storeScriptString.scope = prop.second;
1009 output->bytecode << ss;
1012 bool seenDefer = false;
1013 foreach(Property *prop, obj->valueProperties) {
1014 if (prop->isDeferred) {
1019 genValueProperty(prop, obj);
1022 QDeclarativeInstruction defer;
1023 defer.type = QDeclarativeInstruction::Defer;
1025 defer.defer.deferCount = 0;
1026 int deferIdx = output->bytecode.count();
1027 output->bytecode << defer;
1029 QDeclarativeInstruction init;
1030 init.type = QDeclarativeInstruction::Init;
1031 init.init.bindingsSize = compileState.bindings.count(); // XXX - bigger than necessary
1032 init.init.parserStatusSize = compileState.parserStatusCount; // XXX - bigger than necessary
1033 init.init.contextCache = -1;
1034 init.init.compiledBinding = -1;
1035 output->bytecode << init;
1037 foreach(Property *prop, obj->valueProperties) {
1038 if (!prop->isDeferred)
1040 genValueProperty(prop, obj);
1043 output->bytecode[deferIdx].defer.deferCount =
1044 output->bytecode.count() - deferIdx - 1;
1047 foreach(Property *prop, obj->signalProperties) {
1049 QDeclarativeParser::Value *v = prop->values.at(0);
1051 if (v->type == Value::SignalObject) {
1053 genObject(v->object);
1055 QDeclarativeInstruction assign;
1056 assign.type = QDeclarativeInstruction::AssignSignalObject;
1057 assign.line = v->location.start.line;
1058 assign.assignSignalObject.signal =
1059 output->indexForByteArray(prop->name);
1060 output->bytecode << assign;
1062 } else if (v->type == Value::SignalExpression) {
1064 BindingContext ctxt = compileState.signalExpressions.value(v);
1066 QDeclarativeInstruction store;
1067 store.type = QDeclarativeInstruction::StoreSignal;
1068 store.line = v->location.start.line;
1069 store.storeSignal.signalIndex = prop->index;
1070 store.storeSignal.value =
1071 output->indexForString(v->value.asScript().trimmed());
1072 store.storeSignal.context = ctxt.stack;
1073 store.storeSignal.name = output->indexForByteArray(prop->name);
1074 output->bytecode << store;
1080 foreach(Property *prop, obj->attachedProperties) {
1081 QDeclarativeInstruction fetch;
1082 fetch.type = QDeclarativeInstruction::FetchAttached;
1083 fetch.line = prop->location.start.line;
1084 fetch.fetchAttached.id = prop->index;
1085 output->bytecode << fetch;
1087 genObjectBody(prop->value);
1089 QDeclarativeInstruction pop;
1090 pop.type = QDeclarativeInstruction::PopFetchedObject;
1091 pop.line = prop->location.start.line;
1092 output->bytecode << pop;
1095 foreach(Property *prop, obj->groupedProperties) {
1096 QDeclarativeInstruction fetch;
1097 fetch.type = QDeclarativeInstruction::FetchObject;
1098 fetch.fetch.property = prop->index;
1099 fetch.line = prop->location.start.line;
1100 output->bytecode << fetch;
1102 if (!prop->value->metadata.isEmpty()) {
1103 QDeclarativeInstruction meta;
1104 meta.type = QDeclarativeInstruction::StoreMetaObject;
1106 meta.storeMeta.data = output->indexForByteArray(prop->value->metadata);
1107 meta.storeMeta.aliasData = output->indexForByteArray(prop->value->synthdata);
1108 meta.storeMeta.propertyCache = -1;
1109 output->bytecode << meta;
1112 genObjectBody(prop->value);
1114 QDeclarativeInstruction pop;
1115 pop.type = QDeclarativeInstruction::PopFetchedObject;
1116 pop.line = prop->location.start.line;
1117 output->bytecode << pop;
1120 foreach(Property *prop, obj->valueTypeProperties) {
1122 genValueTypeProperty(obj, prop);
1125 foreach(Property *prop, obj->valueProperties) {
1126 if (prop->isDeferred)
1129 genValueProperty(prop, obj);
1132 foreach(Property *prop, obj->valueTypeProperties) {
1134 genValueTypeProperty(obj, prop);
1138 void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeParser::Object *obj,QDeclarativeParser::Property *prop)
1140 QDeclarativeInstruction fetch;
1141 fetch.type = QDeclarativeInstruction::FetchValueType;
1142 fetch.fetchValue.property = prop->index;
1143 fetch.fetchValue.type = prop->type;
1144 fetch.fetchValue.bindingSkipList = 0;
1145 fetch.line = prop->location.start.line;
1147 if (obj->type == -1 || output->types.at(obj->type).component) {
1148 // We only have to do this if this is a composite type. If it is a builtin
1149 // type it can't possibly already have bindings that need to be cleared.
1150 foreach(Property *vprop, prop->value->valueProperties) {
1151 if (!vprop->values.isEmpty()) {
1152 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1153 fetch.fetchValue.bindingSkipList |= (1 << vprop->index);
1158 output->bytecode << fetch;
1160 foreach(Property *vprop, prop->value->valueProperties) {
1161 genPropertyAssignment(vprop, prop->value, prop);
1164 QDeclarativeInstruction pop;
1165 pop.type = QDeclarativeInstruction::PopValueType;
1166 pop.fetchValue.property = prop->index;
1167 pop.fetchValue.type = prop->type;
1168 pop.fetchValue.bindingSkipList = 0;
1169 pop.line = prop->location.start.line;
1170 output->bytecode << pop;
1173 void QDeclarativeCompiler::genComponent(QDeclarativeParser::Object *obj)
1175 QDeclarativeParser::Object *root = obj->defaultProperty->values.at(0)->object;
1178 QDeclarativeInstruction create;
1179 create.type = QDeclarativeInstruction::CreateComponent;
1180 create.line = root->location.start.line;
1181 create.createComponent.column = root->location.start.column;
1182 create.createComponent.endLine = root->location.end.line;
1183 output->bytecode << create;
1184 int count = output->bytecode.count();
1186 ComponentCompileState oldCompileState = compileState;
1187 compileState = componentState(root);
1189 QDeclarativeInstruction init;
1190 init.type = QDeclarativeInstruction::Init;
1191 init.init.bindingsSize = compileState.bindings.count();
1192 init.init.parserStatusSize = compileState.parserStatusCount;
1193 init.init.contextCache = genContextCache();
1194 if (compileState.compiledBindingData.isEmpty())
1195 init.init.compiledBinding = -1;
1197 init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData);
1198 init.line = obj->location.start.line;
1199 output->bytecode << init;
1203 QDeclarativeInstruction def;
1205 def.type = QDeclarativeInstruction::SetDefault;
1206 output->bytecode << def;
1208 output->bytecode[count - 1].createComponent.count =
1209 output->bytecode.count() - count;
1211 compileState = oldCompileState;
1213 if (!obj->id.isEmpty()) {
1214 QDeclarativeInstruction id;
1215 id.type = QDeclarativeInstruction::SetId;
1217 id.setId.value = output->indexForString(obj->id);
1218 id.setId.index = obj->idIndex;
1219 output->bytecode << id;
1223 bool QDeclarativeCompiler::buildComponent(QDeclarativeParser::Object *obj,
1224 const BindingContext &ctxt)
1226 // The special "Component" element can only have the id property and a
1227 // default property, that actually defines the component's tree
1229 // Find, check and set the "id" property (if any)
1230 Property *idProp = 0;
1231 if (obj->properties.count() > 1 ||
1232 (obj->properties.count() == 1 && obj->properties.begin().key() != "id"))
1233 COMPILE_EXCEPTION(*obj->properties.begin(), tr("Component elements may not contain properties other than id"));
1235 if (obj->properties.count())
1236 idProp = *obj->properties.begin();
1239 if (idProp->value || idProp->values.count() > 1 || idProp->values.at(0)->object)
1240 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1241 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1243 QString idVal = idProp->values.first()->primitive();
1245 if (compileState.ids.contains(idVal))
1246 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1252 // Check the Component tree is well formed
1253 if (obj->defaultProperty &&
1254 (obj->defaultProperty->value || obj->defaultProperty->values.count() > 1 ||
1255 (obj->defaultProperty->values.count() == 1 && !obj->defaultProperty->values.first()->object)))
1256 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1258 if (!obj->dynamicProperties.isEmpty())
1259 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1260 if (!obj->dynamicSignals.isEmpty())
1261 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1262 if (!obj->dynamicSlots.isEmpty())
1263 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1265 QDeclarativeParser::Object *root = 0;
1266 if (obj->defaultProperty && obj->defaultProperty->values.count())
1267 root = obj->defaultProperty->values.first()->object;
1270 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1272 // Build the component tree
1273 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1278 bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeParser::Object *obj,
1279 const BindingContext &ctxt)
1281 ComponentCompileState oldComponentCompileState = compileState;
1282 ComponentStat oldComponentStat = componentStat;
1284 compileState = ComponentCompileState();
1285 compileState.root = obj;
1287 componentStat = ComponentStat();
1288 componentStat.lineNumber = obj->location.start.line;
1291 COMPILE_CHECK(buildObject(obj, ctxt));
1293 COMPILE_CHECK(completeComponentBuild());
1295 compileState = oldComponentCompileState;
1296 componentStat = oldComponentStat;
1302 // Build a sub-object. A sub-object is one that was not created directly by
1303 // QML - such as a grouped property object, or an attached object. Sub-object's
1304 // can't have an id, involve a custom parser, have attached properties etc.
1305 bool QDeclarativeCompiler::buildSubObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
1307 Q_ASSERT(obj->metatype);
1308 Q_ASSERT(!obj->defaultProperty);
1309 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1312 foreach(Property *prop, obj->properties) {
1313 if (isSignalPropertyName(prop->name)) {
1314 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1316 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1323 int QDeclarativeCompiler::componentTypeRef()
1325 QDeclarativeType *t = QDeclarativeMetaType::qmlType("QtQuick/Component",1,0);
1326 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1327 if (output->types.at(ii).type == t)
1330 QDeclarativeCompiledData::TypeReference ref;
1331 ref.className = "Component";
1333 output->types << ref;
1334 return output->types.count() - 1;
1337 bool QDeclarativeCompiler::buildSignal(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj,
1338 const BindingContext &ctxt)
1340 Q_ASSERT(obj->metaObject());
1342 QByteArray name = prop->name;
1343 Q_ASSERT(name.startsWith("on"));
1345 if(name[0] >= 'A' && name[0] <= 'Z')
1346 name[0] = name[0] - 'A' + 'a';
1348 bool notInRevision = false;
1349 int sigIdx = indexOfSignal(obj, name, ¬InRevision);
1353 if (notInRevision && -1 == indexOfProperty(obj, prop->name, 0)) {
1354 Q_ASSERT(obj->type != -1);
1355 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1356 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1358 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)).arg(QString::fromUtf8(type.type->module())).arg(type.majorVersion).arg(type.minorVersion));
1360 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)));
1364 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1366 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1370 if (prop->value || prop->values.count() != 1)
1371 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1373 prop->index = sigIdx;
1374 obj->addSignalProperty(prop);
1376 if (prop->values.at(0)->object) {
1377 COMPILE_CHECK(buildObject(prop->values.at(0)->object, ctxt));
1378 prop->values.at(0)->type = Value::SignalObject;
1380 prop->values.at(0)->type = Value::SignalExpression;
1382 if (!prop->values.at(0)->value.isScript())
1383 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1385 QString script = prop->values.at(0)->value.asScript().trimmed();
1386 if (script.isEmpty())
1387 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1389 compileState.signalExpressions.insert(prop->values.at(0), ctxt);
1398 Returns true if (value) property \a prop exists on obj, false otherwise.
1400 bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeParser::Property *prop,
1401 QDeclarativeParser::Object *obj)
1403 if(isAttachedPropertyName(prop->name) || prop->name == "id")
1406 const QMetaObject *mo = obj->metaObject();
1408 if (prop->isDefault) {
1409 QMetaProperty p = QDeclarativeMetaType::defaultProperty(mo);
1410 return p.name() != 0;
1412 int idx = indexOfProperty(obj, prop->name);
1413 return idx != -1 && mo->property(idx).isScriptable();
1420 bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop,
1421 QDeclarativeParser::Object *obj,
1422 const BindingContext &ctxt)
1424 if (prop->isEmpty())
1425 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1427 const QMetaObject *metaObject = obj->metaObject();
1428 Q_ASSERT(metaObject);
1430 if (isAttachedPropertyName(prop->name)) {
1431 // Setup attached property data
1433 if (ctxt.isSubContext()) {
1434 // Attached properties cannot be used on sub-objects. Sub-objects
1435 // always exist in a binding sub-context, which is what we test
1437 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1440 QDeclarativeType *type = 0;
1441 QDeclarativeImportedNamespace *typeNamespace = 0;
1442 unit->imports().resolveType(prop->name, &type, 0, 0, 0, &typeNamespace);
1444 if (typeNamespace) {
1445 // ### We might need to indicate that this property is a namespace
1447 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1450 } else if (!type || !type->attachedPropertiesType()) {
1451 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1455 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1457 Q_ASSERT(type->attachedPropertiesFunction());
1458 prop->index = type->attachedPropertiesId();
1459 prop->value->metatype = type->attachedPropertiesType();
1461 // Setup regular property data
1464 if (prop->isDefault) {
1465 p = QDeclarativeMetaType::defaultProperty(metaObject);
1468 prop->index = p.propertyIndex();
1469 prop->name = p.name();
1473 bool notInRevision = false;
1474 prop->index = indexOfProperty(obj, prop->name, ¬InRevision);
1475 if (prop->index == -1 && notInRevision) {
1476 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1477 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1479 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)).arg(QString::fromUtf8(type.type->module())).arg(type.majorVersion).arg(type.minorVersion));
1481 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)));
1485 if (prop->index != -1) {
1486 p = metaObject->property(prop->index);
1489 if (!p.isScriptable()) {
1491 p = QMetaProperty();
1496 // We can't error here as the "id" property does not require a
1497 // successful index resolution
1499 prop->type = p.userType();
1501 // Check if this is an alias
1502 if (prop->index != -1 &&
1504 prop->parent->type != -1 &&
1505 output->types.at(prop->parent->type).component) {
1507 QDeclarativePropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1508 if (cache && cache->property(prop->index) &&
1509 cache->property(prop->index)->flags & QDeclarativePropertyCache::Data::IsAlias)
1510 prop->isAlias = true;
1513 if (prop->index != -1 && !prop->values.isEmpty())
1514 prop->parent->setBindingBit(prop->index);
1517 if (!prop->isDefault && prop->name == "id" && !ctxt.isSubContext()) {
1519 // The magic "id" behavior doesn't apply when "id" is resolved as a
1520 // default property or to sub-objects (which are always in binding
1522 COMPILE_CHECK(buildIdProperty(prop, obj));
1523 if (prop->type == QVariant::String &&
1524 prop->values.at(0)->value.isString())
1525 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1527 } else if (isAttachedPropertyName(prop->name)) {
1529 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1531 } else if (prop->index == -1) {
1533 if (prop->isDefault) {
1534 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1536 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1539 } else if (prop->value) {
1541 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1543 } else if (enginePrivate->isList(prop->type)) {
1545 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1547 } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) {
1549 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1553 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1560 bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
1561 QDeclarativeParser::Property *nsProp,
1562 QDeclarativeParser::Object *obj,
1563 const BindingContext &ctxt)
1566 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1568 foreach (Property *prop, nsProp->value->properties) {
1570 if (!isAttachedPropertyName(prop->name))
1571 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1573 // Setup attached property data
1575 QDeclarativeType *type = 0;
1576 unit->imports().resolveType(ns, prop->name, &type, 0, 0, 0);
1578 if (!type || !type->attachedPropertiesType())
1579 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1582 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1584 Q_ASSERT(type->attachedPropertiesFunction());
1585 prop->index = type->index();
1586 prop->value->metatype = type->attachedPropertiesType();
1588 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1594 void QDeclarativeCompiler::genValueProperty(QDeclarativeParser::Property *prop,
1595 QDeclarativeParser::Object *obj)
1597 if (enginePrivate->isList(prop->type)) {
1598 genListProperty(prop, obj);
1600 genPropertyAssignment(prop, obj);
1604 void QDeclarativeCompiler::genListProperty(QDeclarativeParser::Property *prop,
1605 QDeclarativeParser::Object *obj)
1607 int listType = enginePrivate->listType(prop->type);
1609 QDeclarativeInstruction fetch;
1610 fetch.type = QDeclarativeInstruction::FetchQList;
1611 fetch.line = prop->location.start.line;
1612 fetch.fetchQmlList.property = prop->index;
1613 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1614 fetch.fetchQmlList.type = listType;
1615 output->bytecode << fetch;
1617 for (int ii = 0; ii < prop->values.count(); ++ii) {
1618 QDeclarativeParser::Value *v = prop->values.at(ii);
1620 if (v->type == Value::CreatedObject) {
1622 genObject(v->object);
1623 if (listTypeIsInterface) {
1624 QDeclarativeInstruction assign;
1625 assign.type = QDeclarativeInstruction::AssignObjectList;
1626 assign.line = prop->location.start.line;
1627 output->bytecode << assign;
1629 QDeclarativeInstruction store;
1630 store.type = QDeclarativeInstruction::StoreObjectQList;
1631 store.line = prop->location.start.line;
1632 output->bytecode << store;
1635 } else if (v->type == Value::PropertyBinding) {
1637 genBindingAssignment(v, prop, obj);
1643 QDeclarativeInstruction pop;
1644 pop.type = QDeclarativeInstruction::PopQList;
1645 pop.line = prop->location.start.line;
1646 output->bytecode << pop;
1649 void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *prop,
1650 QDeclarativeParser::Object *obj,
1651 QDeclarativeParser::Property *valueTypeProperty)
1653 for (int ii = 0; ii < prop->values.count(); ++ii) {
1654 QDeclarativeParser::Value *v = prop->values.at(ii);
1656 Q_ASSERT(v->type == Value::CreatedObject ||
1657 v->type == Value::PropertyBinding ||
1658 v->type == Value::Literal);
1660 if (v->type == Value::CreatedObject) {
1662 genObject(v->object);
1664 if (QDeclarativeMetaType::isInterface(prop->type)) {
1666 QDeclarativeInstruction store;
1667 store.type = QDeclarativeInstruction::StoreInterface;
1668 store.line = v->object->location.start.line;
1669 store.storeObject.propertyIndex = prop->index;
1670 output->bytecode << store;
1672 } else if (prop->type == -1) {
1674 QDeclarativeInstruction store;
1675 store.type = QDeclarativeInstruction::StoreVariantObject;
1676 store.line = v->object->location.start.line;
1677 store.storeObject.propertyIndex = prop->index;
1678 output->bytecode << store;
1682 QDeclarativeInstruction store;
1683 store.type = QDeclarativeInstruction::StoreObject;
1684 store.line = v->object->location.start.line;
1685 store.storeObject.propertyIndex = prop->index;
1686 output->bytecode << store;
1689 } else if (v->type == Value::PropertyBinding) {
1691 genBindingAssignment(v, prop, obj, valueTypeProperty);
1693 } else if (v->type == Value::Literal) {
1695 QMetaProperty mp = obj->metaObject()->property(prop->index);
1696 genLiteralAssignment(mp, v);
1702 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
1704 QDeclarativeParser::Value *v = prop->onValues.at(ii);
1706 Q_ASSERT(v->type == Value::ValueSource ||
1707 v->type == Value::ValueInterceptor);
1709 if (v->type == Value::ValueSource) {
1710 genObject(v->object);
1712 QDeclarativeInstruction store;
1713 store.type = QDeclarativeInstruction::StoreValueSource;
1714 store.line = v->object->location.start.line;
1715 if (valueTypeProperty) {
1716 store.assignValueSource.property = genValueTypeData(prop, valueTypeProperty);
1717 store.assignValueSource.owner = 1;
1719 store.assignValueSource.property = genPropertyData(prop);
1720 store.assignValueSource.owner = 0;
1722 QDeclarativeType *valueType = toQmlType(v->object);
1723 store.assignValueSource.castValue = valueType->propertyValueSourceCast();
1724 output->bytecode << store;
1726 } else if (v->type == Value::ValueInterceptor) {
1727 genObject(v->object);
1729 QDeclarativeInstruction store;
1730 store.type = QDeclarativeInstruction::StoreValueInterceptor;
1731 store.line = v->object->location.start.line;
1732 if (valueTypeProperty) {
1733 store.assignValueInterceptor.property = genValueTypeData(prop, valueTypeProperty);
1734 store.assignValueInterceptor.owner = 1;
1736 store.assignValueInterceptor.property = genPropertyData(prop);
1737 store.assignValueInterceptor.owner = 0;
1739 QDeclarativeType *valueType = toQmlType(v->object);
1740 store.assignValueInterceptor.castValue = valueType->propertyValueInterceptorCast();
1741 output->bytecode << store;
1747 bool QDeclarativeCompiler::buildIdProperty(QDeclarativeParser::Property *prop,
1748 QDeclarativeParser::Object *obj)
1751 prop->values.count() > 1 ||
1752 prop->values.at(0)->object)
1753 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
1755 QDeclarativeParser::Value *idValue = prop->values.at(0);
1756 QString val = idValue->primitive();
1758 COMPILE_CHECK(checkValidId(idValue, val));
1760 if (compileState.ids.contains(val))
1761 COMPILE_EXCEPTION(prop, tr("id is not unique"));
1763 prop->values.at(0)->type = Value::Id;
1771 void QDeclarativeCompiler::addId(const QString &id, QDeclarativeParser::Object *obj)
1773 Q_ASSERT(!compileState.ids.contains(id));
1774 Q_ASSERT(obj->id == id);
1775 obj->idIndex = compileState.ids.count();
1776 compileState.ids.insert(id, obj);
1777 compileState.idIndexes.insert(obj->idIndex, obj);
1780 void QDeclarativeCompiler::addBindingReference(const BindingReference &ref)
1782 Q_ASSERT(ref.value && !compileState.bindings.contains(ref.value));
1783 compileState.bindings.insert(ref.value, ref);
1786 void QDeclarativeCompiler::saveComponentState()
1788 Q_ASSERT(compileState.root);
1789 Q_ASSERT(!savedCompileStates.contains(compileState.root));
1791 savedCompileStates.insert(compileState.root, compileState);
1792 savedComponentStats.append(componentStat);
1795 QDeclarativeCompiler::ComponentCompileState
1796 QDeclarativeCompiler::componentState(QDeclarativeParser::Object *obj)
1798 Q_ASSERT(savedCompileStates.contains(obj));
1799 return savedCompileStates.value(obj);
1802 // Build attached property object. In this example,
1806 // GridView is an attached property object.
1807 bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeParser::Property *prop,
1808 QDeclarativeParser::Object *obj,
1809 const BindingContext &ctxt)
1811 Q_ASSERT(prop->value);
1812 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
1814 obj->addAttachedProperty(prop);
1816 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1822 // Build "grouped" properties. In this example:
1824 // font.pointSize: 12
1825 // font.family: "Helvetica"
1827 // font is a nested property. pointSize and family are not.
1828 bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeParser::Property *prop,
1829 QDeclarativeParser::Object *obj,
1830 const BindingContext &ctxt)
1832 Q_ASSERT(prop->type != 0);
1833 Q_ASSERT(prop->index != -1);
1835 if (QDeclarativeValueTypeFactory::isValueType(prop->type)) {
1836 if (prop->type >= 0 /* QVariant == -1 */ && enginePrivate->valueTypes[prop->type]) {
1838 if (prop->values.count()) {
1839 if (prop->values.at(0)->location < prop->value->location) {
1840 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
1842 COMPILE_EXCEPTION(prop->values.at(0), tr( "Property has already been assigned a value"));
1846 if (!obj->metaObject()->property(prop->index).isWritable()) {
1847 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
1851 if (prop->isAlias) {
1852 foreach (Property *vtProp, prop->value->properties)
1853 vtProp->isAlias = true;
1856 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
1857 prop->value, obj, ctxt.incr()));
1858 obj->addValueTypeProperty(prop);
1860 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1864 // Load the nested property's meta type
1865 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
1866 if (!prop->value->metatype)
1867 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1869 if (prop->values.count())
1870 COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign a value directly to a grouped property"));
1872 obj->addGroupedProperty(prop);
1874 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1880 bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
1881 QDeclarativeParser::Object *obj,
1882 QDeclarativeParser::Object *baseObj,
1883 const BindingContext &ctxt)
1885 if (obj->defaultProperty)
1886 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
1887 obj->metatype = type->metaObject();
1889 foreach (Property *prop, obj->properties) {
1890 int idx = type->metaObject()->indexOfProperty(prop->name.constData());
1892 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1893 QMetaProperty p = type->metaObject()->property(idx);
1894 if (!p.isScriptable())
1895 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1897 prop->type = p.userType();
1898 prop->isValueTypeSubProperty = true;
1901 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
1903 if (prop->values.count() > 1) {
1904 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
1905 } else if (prop->values.count()) {
1906 QDeclarativeParser::Value *value = prop->values.at(0);
1908 if (value->object) {
1909 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
1910 } else if (value->value.isScript()) {
1911 // ### Check for writability
1913 //optimization for <Type>.<EnumValue> enum assignments
1914 bool isEnumAssignment = false;
1915 COMPILE_CHECK(testQualifiedEnumAssignment(p, obj, value, &isEnumAssignment));
1916 if (isEnumAssignment) {
1917 value->type = Value::Literal;
1919 BindingReference reference;
1920 reference.expression = value->value;
1921 reference.property = prop;
1922 reference.value = value;
1923 reference.bindingContext = ctxt;
1924 reference.bindingContext.owner++;
1925 addBindingReference(reference);
1926 value->type = Value::PropertyBinding;
1929 COMPILE_CHECK(testLiteralAssignment(p, value));
1930 value->type = Value::Literal;
1934 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
1935 QDeclarativeParser::Value *v = prop->onValues.at(ii);
1936 Q_ASSERT(v->object);
1938 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
1941 obj->addValueProperty(prop);
1947 // Build assignments to QML lists. QML lists are properties of type
1948 // QDeclarativeListProperty<T>. List properties can accept a list of
1949 // objects, or a single binding.
1950 bool QDeclarativeCompiler::buildListProperty(QDeclarativeParser::Property *prop,
1951 QDeclarativeParser::Object *obj,
1952 const BindingContext &ctxt)
1954 Q_ASSERT(enginePrivate->isList(prop->type));
1958 obj->addValueProperty(prop);
1960 int listType = enginePrivate->listType(t);
1961 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1963 bool assignedBinding = false;
1964 for (int ii = 0; ii < prop->values.count(); ++ii) {
1965 QDeclarativeParser::Value *v = prop->values.at(ii);
1967 v->type = Value::CreatedObject;
1968 COMPILE_CHECK(buildObject(v->object, ctxt));
1970 // We check object coercian here. We check interface assignment
1972 if (!listTypeIsInterface) {
1973 if (!canCoerce(listType, v->object)) {
1974 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
1978 } else if (v->value.isScript()) {
1979 if (assignedBinding)
1980 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
1982 assignedBinding = true;
1983 COMPILE_CHECK(buildBinding(v, prop, ctxt));
1984 v->type = Value::PropertyBinding;
1986 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
1993 // Compiles an assignment to a QDeclarativeScriptString property
1994 bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeParser::Property *prop,
1995 QDeclarativeParser::Object *obj,
1996 const BindingContext &ctxt)
1998 if (prop->values.count() > 1)
1999 COMPILE_EXCEPTION(prop->values.at(1), tr( "Cannot assign multiple values to a script property"));
2001 if (prop->values.at(0)->object)
2002 COMPILE_EXCEPTION(prop->values.at(0), tr( "Invalid property assignment: script expected"));
2004 obj->addScriptStringProperty(prop, ctxt.stack);
2009 // Compile regular property assignments of the form "property: <value>"
2010 bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeParser::Property *prop,
2011 QDeclarativeParser::Object *obj,
2012 const BindingContext &ctxt)
2014 obj->addValueProperty(prop);
2016 if (prop->values.count() > 1)
2017 COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign multiple values to a singular property") );
2019 for (int ii = 0; ii < prop->values.count(); ++ii) {
2020 QDeclarativeParser::Value *v = prop->values.at(ii);
2023 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2027 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2032 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
2033 QDeclarativeParser::Value *v = prop->onValues.at(ii);
2035 Q_ASSERT(v->object);
2036 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2042 // Compile assigning a single object instance to a regular property
2043 bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeParser::Property *prop,
2044 QDeclarativeParser::Object *obj,
2045 QDeclarativeParser::Value *v,
2046 const BindingContext &ctxt)
2048 Q_ASSERT(prop->index != -1);
2049 Q_ASSERT(v->object->type != -1);
2051 if (!obj->metaObject()->property(prop->index).isWritable())
2052 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2054 if (QDeclarativeMetaType::isInterface(prop->type)) {
2056 // Assigning an object to an interface ptr property
2057 COMPILE_CHECK(buildObject(v->object, ctxt));
2059 v->type = Value::CreatedObject;
2061 } else if (prop->type == -1) {
2063 // Assigning an object to a QVariant
2064 COMPILE_CHECK(buildObject(v->object, ctxt));
2066 v->type = Value::CreatedObject;
2068 // Normally buildObject() will set this up, but we need the static
2069 // meta object earlier to test for assignability. It doesn't matter
2070 // that there may still be outstanding synthesized meta object changes
2071 // on this type, as they are not relevant for assignability testing
2072 v->object->metatype = output->types.at(v->object->type).metaObject();
2073 Q_ASSERT(v->object->metaObject());
2075 // We want to raw metaObject here as the raw metaobject is the
2076 // actual property type before we applied any extensions that might
2077 // effect the properties on the type, but don't effect assignability
2078 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2080 // Will be true if the assgned type inherits propertyMetaObject
2081 bool isAssignable = false;
2082 // Determine isAssignable value
2083 if (propertyMetaObject) {
2084 const QMetaObject *c = v->object->metatype;
2086 isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject));
2087 c = c->superClass();
2092 // Simple assignment
2093 COMPILE_CHECK(buildObject(v->object, ctxt));
2095 v->type = Value::CreatedObject;
2096 } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) {
2097 // Automatic "Component" insertion
2098 QDeclarativeParser::Object *root = v->object;
2099 QDeclarativeParser::Object *component = new QDeclarativeParser::Object;
2100 component->type = componentTypeRef();
2101 component->typeName = "Qt/Component";
2102 component->metatype = &QDeclarativeComponent::staticMetaObject;
2103 component->location = root->location;
2104 QDeclarativeParser::Value *componentValue = new QDeclarativeParser::Value;
2105 componentValue->object = root;
2106 component->getDefaultProperty()->addValue(componentValue);
2107 v->object = component;
2108 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2110 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2117 // Compile assigning a single object instance to a regular property using the "on" syntax.
2121 // NumberAnimation on x { }
2123 bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeParser::Property *prop,
2124 QDeclarativeParser::Object *obj,
2125 QDeclarativeParser::Object *baseObj,
2126 QDeclarativeParser::Value *v,
2127 const BindingContext &ctxt)
2129 Q_ASSERT(prop->index != -1);
2130 Q_ASSERT(v->object->type != -1);
2132 if (!obj->metaObject()->property(prop->index).isWritable())
2133 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2136 // Normally buildObject() will set this up, but we need the static
2137 // meta object earlier to test for assignability. It doesn't matter
2138 // that there may still be outstanding synthesized meta object changes
2139 // on this type, as they are not relevant for assignability testing
2140 v->object->metatype = output->types.at(v->object->type).metaObject();
2141 Q_ASSERT(v->object->metaObject());
2143 // Will be true if the assigned type inherits QDeclarativePropertyValueSource
2144 bool isPropertyValue = false;
2145 // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor
2146 bool isPropertyInterceptor = false;
2147 if (QDeclarativeType *valueType = toQmlType(v->object)) {
2148 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2149 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2152 if (isPropertyValue || isPropertyInterceptor) {
2153 // Assign as a property value source
2154 COMPILE_CHECK(buildObject(v->object, ctxt));
2156 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2157 buildDynamicMeta(baseObj, ForceCreation);
2158 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2160 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(QString::fromUtf8(v->object->typeName)).arg(QString::fromUtf8(prop->name.constData())));
2166 // Compile assigning a literal or binding to a regular property
2167 bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeParser::Property *prop,
2168 QDeclarativeParser::Object *obj,
2169 QDeclarativeParser::Value *v,
2170 const BindingContext &ctxt)
2172 Q_ASSERT(prop->index != -1);
2174 if (v->value.isScript()) {
2176 //optimization for <Type>.<EnumValue> enum assignments
2177 bool isEnumAssignment = false;
2178 COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj, v, &isEnumAssignment));
2179 if (isEnumAssignment) {
2180 v->type = Value::Literal;
2184 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2186 v->type = Value::PropertyBinding;
2190 COMPILE_CHECK(testLiteralAssignment(obj->metaObject()->property(prop->index), v));
2192 v->type = Value::Literal;
2198 bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop,
2199 QDeclarativeParser::Object *obj,
2200 QDeclarativeParser::Value *v,
2203 *isAssignment = false;
2204 if (!prop.isEnumType())
2207 if (!prop.isWritable())
2208 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
2210 QString string = v->value.asString();
2211 if (!string.at(0).isUpper())
2214 QStringList parts = string.split(QLatin1Char('.'));
2215 if (parts.count() != 2)
2218 QString typeName = parts.at(0);
2219 QDeclarativeType *type = 0;
2220 unit->imports().resolveType(typeName.toUtf8(), &type, 0, 0, 0, 0);
2222 //handle enums on value types (where obj->typeName is empty)
2223 QByteArray objTypeName = obj->typeName;
2224 if (objTypeName.isEmpty()) {
2225 QDeclarativeType *objType = toQmlType(obj);
2227 objTypeName = objType->qmlTypeName();
2230 if (!type || objTypeName != type->qmlTypeName())
2233 QString enumValue = parts.at(1);
2235 if (prop.isFlagType()) {
2236 value = prop.enumerator().keysToValue(enumValue.toUtf8().constData());
2238 value = prop.enumerator().keyToValue(enumValue.toUtf8().constData());
2242 v->type = Value::Literal;
2243 v->value = QDeclarativeParser::Variant(enumValue);
2244 *isAssignment = true;
2249 // Similar logic to above, but not knowing target property.
2250 int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const
2252 int dot = script.indexOf('.');
2254 QDeclarativeType *type = 0;
2255 unit->imports().resolveType(script.left(dot), &type, 0, 0, 0, 0);
2258 const QMetaObject *mo = type->metaObject();
2259 const char *key = script.constData() + dot+1;
2260 int i = mo->enumeratorCount();
2262 int v = mo->enumerator(i).keyToValue(key);
2270 const QMetaObject *QDeclarativeCompiler::resolveType(const QByteArray& name) const
2272 QDeclarativeType *qmltype = 0;
2273 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2277 return qmltype->metaObject();
2280 // similar to logic of completeComponentBuild, but also sticks data
2281 // into datas at the end
2282 int QDeclarativeCompiler::rewriteBinding(const QString& expression, const QByteArray& name)
2284 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2285 rewriteBinding.setName('$' + name.mid(name.lastIndexOf('.') + 1));
2286 bool isSharable = false;
2287 QString rewrite = rewriteBinding(expression, 0, &isSharable);
2289 quint32 length = rewrite.length();
2293 pc = output->cachedClosures.count();
2295 output->cachedClosures.append(0);
2297 pc = output->cachedPrograms.length();
2298 output->cachedPrograms.append(0);
2301 QByteArray compiledData =
2302 QByteArray((const char *)&pc, sizeof(quint32)) +
2303 QByteArray((const char *)&length, sizeof(quint32)) +
2304 QByteArray((const char *)rewrite.constData(),
2305 rewrite.length() * sizeof(QChar));
2307 return output->indexForByteArray(compiledData);
2310 // Ensures that the dynamic meta specification on obj is valid
2311 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj)
2313 QSet<QByteArray> propNames;
2314 QSet<QByteArray> methodNames;
2315 bool seenDefaultProperty = false;
2318 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2319 const QDeclarativeParser::Object::DynamicProperty &prop =
2320 obj->dynamicProperties.at(ii);
2322 if (prop.isDefaultProperty) {
2323 if (seenDefaultProperty)
2324 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2325 seenDefaultProperty = true;
2328 if (propNames.contains(prop.name))
2329 COMPILE_EXCEPTION(&prop, tr("Duplicate property name"));
2331 QString propName = QString::fromUtf8(prop.name);
2332 if (propName.at(0).isUpper())
2333 COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
2335 if (enginePrivate->globalClass->illegalNames().contains(propName))
2336 COMPILE_EXCEPTION(&prop, tr("Illegal property name"));
2338 propNames.insert(prop.name);
2341 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2342 QByteArray name = obj->dynamicSignals.at(ii).name;
2343 if (methodNames.contains(name))
2344 COMPILE_EXCEPTION(obj, tr("Duplicate signal name"));
2345 QString nameStr = QString::fromUtf8(name);
2346 if (nameStr.at(0).isUpper())
2347 COMPILE_EXCEPTION(obj, tr("Signal names cannot begin with an upper case letter"));
2348 if (enginePrivate->globalClass->illegalNames().contains(nameStr))
2349 COMPILE_EXCEPTION(obj, tr("Illegal signal name"));
2350 methodNames.insert(name);
2352 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2353 QByteArray name = obj->dynamicSlots.at(ii).name;
2354 if (methodNames.contains(name))
2355 COMPILE_EXCEPTION(obj, tr("Duplicate method name"));
2356 QString nameStr = QString::fromUtf8(name);
2357 if (nameStr.at(0).isUpper())
2358 COMPILE_EXCEPTION(obj, tr("Method names cannot begin with an upper case letter"));
2359 if (enginePrivate->globalClass->illegalNames().contains(nameStr))
2360 COMPILE_EXCEPTION(obj, tr("Illegal method name"));
2361 methodNames.insert(name);
2367 bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeParser::Object *obj)
2369 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2370 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2372 if (!p.defaultValue || p.type == Object::DynamicProperty::Alias)
2375 Property *property = 0;
2376 if (p.isDefaultProperty) {
2377 property = obj->getDefaultProperty();
2379 property = obj->getProperty(p.name);
2380 if (!property->values.isEmpty())
2381 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2384 if (property->value)
2385 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2387 for (int ii = 0; ii < p.defaultValue->values.count(); ++ii) {
2388 QDeclarativeParser::Value *v = p.defaultValue->values.at(ii);
2390 property->values.append(v);
2396 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2398 bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, DynamicMetaMode mode)
2401 Q_ASSERT(obj->metatype);
2403 if (mode != ForceCreation &&
2404 obj->dynamicProperties.isEmpty() &&
2405 obj->dynamicSignals.isEmpty() &&
2406 obj->dynamicSlots.isEmpty())
2409 QByteArray dynamicData(sizeof(QDeclarativeVMEMetaData), (char)0);
2411 QByteArray newClassName = obj->metatype->className();
2412 newClassName.append("_QML_");
2413 int idx = classIndexCounter()->fetchAndAddRelaxed(1);
2414 newClassName.append(QByteArray::number(idx));
2415 if (compileState.root == obj) {
2416 QString path = output->url.path();
2417 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2418 if (lastSlash > -1) {
2419 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2420 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2421 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(idx);
2425 QMetaObjectBuilder builder;
2426 builder.setClassName(newClassName);
2427 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
2429 bool hasAlias = false;
2430 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2431 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2433 int propIdx = obj->metaObject()->indexOfProperty(p.name.constData());
2434 if (-1 != propIdx) {
2435 QMetaProperty prop = obj->metaObject()->property(propIdx);
2437 COMPILE_EXCEPTION(&p, tr("Cannot override FINAL property"));
2440 if (p.isDefaultProperty &&
2441 (p.type != Object::DynamicProperty::Alias ||
2442 mode == ResolveAliases))
2443 builder.addClassInfo("DefaultProperty", p.name);
2446 int propertyType = 0;
2447 bool readonly = false;
2449 case Object::DynamicProperty::Alias:
2453 case Object::DynamicProperty::CustomList:
2454 case Object::DynamicProperty::Custom:
2456 QByteArray customTypeName;
2457 QDeclarativeType *qmltype = 0;
2459 if (!unit->imports().resolveType(p.customType, &qmltype, &url, 0, 0, 0))
2460 COMPILE_EXCEPTION(&p, tr("Invalid property type"));
2463 QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(url);
2465 Q_ASSERT(tdata->isComplete());
2467 QDeclarativeCompiledData *data = tdata->compiledData();
2468 customTypeName = data->root->className();
2472 customTypeName = qmltype->typeName();
2475 if (p.type == Object::DynamicProperty::Custom) {
2476 type = customTypeName + '*';
2477 propertyType = QMetaType::QObjectStar;
2480 type = "QDeclarativeListProperty<";
2481 type.append(customTypeName);
2483 propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
2487 case Object::DynamicProperty::Variant:
2491 case Object::DynamicProperty::Int:
2492 propertyType = QVariant::Int;
2495 case Object::DynamicProperty::Bool:
2496 propertyType = QVariant::Bool;
2499 case Object::DynamicProperty::Real:
2500 propertyType = QVariant::Double;
2503 case Object::DynamicProperty::String:
2504 propertyType = QVariant::String;
2507 case Object::DynamicProperty::Url:
2508 propertyType = QVariant::Url;
2511 case Object::DynamicProperty::Color:
2512 propertyType = QVariant::Color;
2515 case Object::DynamicProperty::Time:
2516 propertyType = QVariant::Time;
2519 case Object::DynamicProperty::Date:
2520 propertyType = QVariant::Date;
2523 case Object::DynamicProperty::DateTime:
2524 propertyType = QVariant::DateTime;
2529 ((QDeclarativeVMEMetaData *)dynamicData.data())->propertyCount++;
2530 QDeclarativeVMEMetaData::PropertyData propertyData = { propertyType };
2531 dynamicData.append((char *)&propertyData, sizeof(propertyData));
2533 builder.addSignal(p.name + "Changed()");
2534 QMetaPropertyBuilder propBuilder =
2535 builder.addProperty(p.name, type, builder.methodCount() - 1);
2536 propBuilder.setWritable(!readonly);
2539 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2540 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2542 if (p.type == Object::DynamicProperty::Alias) {
2543 if (mode == ResolveAliases) {
2544 ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++;
2545 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, p));
2547 // Need a fake signal so that the metaobject remains consistent across
2548 // the resolve and non-resolve alias runs
2549 builder.addSignal(p.name + "Changed()");
2554 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2555 const Object::DynamicSignal &s = obj->dynamicSignals.at(ii);
2556 QByteArray sig(s.name + '(');
2557 for (int jj = 0; jj < s.parameterTypes.count(); ++jj) {
2558 if (jj) sig.append(',');
2559 sig.append(s.parameterTypes.at(jj));
2562 QMetaMethodBuilder b = builder.addSignal(sig);
2563 b.setParameterNames(s.parameterNames);
2564 ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++;
2567 QStringList funcScripts;
2569 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2570 Object::DynamicSlot &s = obj->dynamicSlots[ii];
2571 QByteArray sig(s.name + '(');
2572 QString funcScript(QLatin1String("(function ") + s.name + QLatin1Char('('));
2574 for (int jj = 0; jj < s.parameterNames.count(); ++jj) {
2577 funcScript.append(QLatin1Char(','));
2579 funcScript.append(QLatin1String(s.parameterNames.at(jj)));
2580 sig.append("QVariant");
2583 funcScript.append(QLatin1Char(')'));
2584 funcScript.append(s.body);
2585 funcScript.append(QLatin1Char(')'));
2586 funcScripts << funcScript;
2588 QMetaMethodBuilder b = builder.addSlot(sig);
2589 b.setReturnType("QVariant");
2590 b.setParameterNames(s.parameterNames);
2592 ((QDeclarativeVMEMetaData *)dynamicData.data())->methodCount++;
2593 QDeclarativeVMEMetaData::MethodData methodData =
2594 { s.parameterNames.count(), 0, funcScript.length(), s.location.start.line };
2596 dynamicData.append((char *)&methodData, sizeof(methodData));
2599 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2600 const QString &funcScript = funcScripts.at(ii);
2601 QDeclarativeVMEMetaData::MethodData *data =
2602 ((QDeclarativeVMEMetaData *)dynamicData.data())->methodData() + ii;
2604 data->bodyOffset = dynamicData.size();
2606 dynamicData.append((const char *)funcScript.constData(),
2607 (funcScript.length() * sizeof(QChar)));
2610 obj->metadata = builder.toRelocatableData();
2611 builder.fromRelocatableData(&obj->extObject, obj->metatype, obj->metadata);
2613 if (mode == IgnoreAliases && hasAlias)
2614 compileState.aliasingObjects << obj;
2616 obj->synthdata = dynamicData;
2618 if (obj->synthCache) {
2619 obj->synthCache->release();
2620 obj->synthCache = 0;
2623 if (obj->type != -1) {
2624 QDeclarativePropertyCache *cache = output->types[obj->type].createPropertyCache(engine)->copy();
2625 cache->append(engine, &obj->extObject, QDeclarativePropertyCache::Data::NoFlags,
2626 QDeclarativePropertyCache::Data::IsVMEFunction,
2627 QDeclarativePropertyCache::Data::IsVMESignal);
2628 obj->synthCache = cache;
2634 bool QDeclarativeCompiler::checkValidId(QDeclarativeParser::Value *v, const QString &val)
2637 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
2639 if (val.at(0).isLetter() && !val.at(0).isLower())
2640 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
2642 QChar u(QLatin1Char('_'));
2643 for (int ii = 0; ii < val.count(); ++ii) {
2645 if (ii == 0 && !val.at(ii).isLetter() && val.at(ii) != u) {
2646 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
2647 } else if (ii != 0 && !val.at(ii).isLetterOrNumber() && val.at(ii) != u) {
2648 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
2653 if (enginePrivate->globalClass->illegalNames().contains(val))
2654 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
2659 #include <qdeclarativejsparser_p.h>
2661 static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node)
2663 if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) {
2665 static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name->asString();
2666 return QStringList() << name;
2667 } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) {
2668 QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node);
2670 QStringList rv = astNodeToStringList(expr->base);
2673 rv.append(expr->name->asString());
2676 return QStringList();
2679 bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder,
2681 QDeclarativeParser::Object *obj,
2682 const Object::DynamicProperty &prop)
2684 if (!prop.defaultValue)
2685 COMPILE_EXCEPTION(obj, tr("No property alias location"));
2687 if (prop.defaultValue->values.count() != 1 ||
2688 prop.defaultValue->values.at(0)->object ||
2689 !prop.defaultValue->values.at(0)->value.isScript())
2690 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2692 QDeclarativeJS::AST::Node *node = prop.defaultValue->values.at(0)->value.asAST();
2694 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
2696 QStringList alias = astNodeToStringList(node);
2698 if (alias.count() < 1 || alias.count() > 3)
2699 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
2701 if (!compileState.ids.contains(alias.at(0)))
2702 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
2704 QDeclarativeParser::Object *idObject = compileState.ids[alias.at(0)];
2706 QByteArray typeName;
2710 bool writable = false;
2711 if (alias.count() == 2 || alias.count() == 3) {
2712 propIdx = indexOfProperty(idObject, alias.at(1).toUtf8());
2714 if (-1 == propIdx) {
2715 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2716 } else if (propIdx > 0xFFFF) {
2717 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
2720 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
2721 if (!aliasProperty.isScriptable())
2722 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2724 writable = aliasProperty.isWritable();
2726 if (alias.count() == 3) {
2727 QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
2729 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2731 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
2733 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
2734 if (valueTypeIndex == -1)
2735 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2736 Q_ASSERT(valueTypeIndex <= 0xFF);
2738 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
2739 propIdx |= (valueTypeIndex << 16);
2742 if (aliasProperty.isEnumType())
2743 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
2745 typeName = aliasProperty.typeName();
2747 typeName = idObject->metaObject()->className();
2749 //use the base type since it has been registered with metatype system
2750 int index = typeName.indexOf("_QML_");
2752 typeName = typeName.left(index);
2754 index = typeName.indexOf("_QMLTYPE_");
2755 const QMetaObject *mo = idObject->metaObject();
2756 while (index != -1 && mo) {
2757 typeName = mo->superClass()->className();
2758 index = typeName.indexOf("_QMLTYPE_");
2759 mo = mo->superClass();
2766 if (typeName.endsWith('*'))
2767 flags |= QML_ALIAS_FLAG_PTR;
2769 data.append((const char *)&idObject->idIndex, sizeof(idObject->idIndex));
2770 data.append((const char *)&propIdx, sizeof(propIdx));
2771 data.append((const char *)&flags, sizeof(flags));
2773 builder.addSignal(prop.name + "Changed()");
2774 QMetaPropertyBuilder propBuilder =
2775 builder.addProperty(prop.name, typeName.constData(), builder.methodCount() - 1);
2776 propBuilder.setWritable(writable);
2780 bool QDeclarativeCompiler::buildBinding(QDeclarativeParser::Value *value,
2781 QDeclarativeParser::Property *prop,
2782 const BindingContext &ctxt)
2784 Q_ASSERT(prop->index != -1);
2785 Q_ASSERT(prop->parent);
2786 Q_ASSERT(prop->parent->metaObject());
2788 QMetaProperty mp = prop->parent->metaObject()->property(prop->index);
2789 if (!mp.isWritable() && !QDeclarativeMetaType::isList(prop->type))
2790 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2792 BindingReference reference;
2793 reference.expression = value->value;
2794 reference.property = prop;
2795 reference.value = value;
2796 reference.bindingContext = ctxt;
2797 addBindingReference(reference);
2802 void QDeclarativeCompiler::genBindingAssignment(QDeclarativeParser::Value *binding,
2803 QDeclarativeParser::Property *prop,
2804 QDeclarativeParser::Object *obj,
2805 QDeclarativeParser::Property *valueTypeProperty)
2808 Q_ASSERT(compileState.bindings.contains(binding));
2810 const BindingReference &ref = compileState.bindings.value(binding);
2811 if (ref.dataType == BindingReference::Experimental) {
2812 QDeclarativeInstruction store;
2813 store.type = QDeclarativeInstruction::StoreCompiledBinding;
2814 store.assignBinding.value = ref.compiledIndex;
2815 store.assignBinding.context = ref.bindingContext.stack;
2816 store.assignBinding.owner = ref.bindingContext.owner;
2817 if (valueTypeProperty)
2818 store.assignBinding.property = (valueTypeProperty->index & 0xFFFF) |
2819 ((valueTypeProperty->type & 0xFF)) << 16 |
2820 ((prop->index & 0xFF) << 24);
2822 store.assignBinding.property = prop->index;
2823 store.line = binding->location.start.line;
2824 output->bytecode << store;
2828 QDeclarativeInstruction store;
2830 store.type = QDeclarativeInstruction::StoreBinding;
2832 store.type = QDeclarativeInstruction::StoreBindingOnAlias;
2833 store.assignBinding.value = output->indexForByteArray(ref.compiledData);
2834 store.assignBinding.context = ref.bindingContext.stack;
2835 store.assignBinding.owner = ref.bindingContext.owner;
2836 store.line = binding->location.start.line;
2838 Q_ASSERT(ref.bindingContext.owner == 0 ||
2839 (ref.bindingContext.owner != 0 && valueTypeProperty));
2840 if (ref.bindingContext.owner) {
2841 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
2843 store.assignBinding.property = genPropertyData(prop);
2846 output->bytecode << store;
2849 int QDeclarativeCompiler::genContextCache()
2851 if (compileState.ids.count() == 0)
2854 QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache(engine);
2856 for (QHash<QString, QDeclarativeParser::Object *>::ConstIterator iter = compileState.ids.begin();
2857 iter != compileState.ids.end();
2859 cache->add(iter.key(), (*iter)->idIndex);
2861 output->contextCaches.append(cache);
2862 return output->contextCaches.count() - 1;
2865 int QDeclarativeCompiler::genValueTypeData(QDeclarativeParser::Property *valueTypeProp,
2866 QDeclarativeParser::Property *prop)
2869 QDeclarativePropertyPrivate::saveValueType(prop->parent->metaObject(), prop->index,
2870 enginePrivate->valueTypes[prop->type]->metaObject(),
2871 valueTypeProp->index);
2872 // valueTypeProp->index, valueTypeProp->type);
2874 return output->indexForByteArray(data);
2877 int QDeclarativeCompiler::genPropertyData(QDeclarativeParser::Property *prop)
2879 return output->indexForByteArray(QDeclarativePropertyPrivate::saveProperty(prop->parent->metaObject(), prop->index));
2882 bool QDeclarativeCompiler::completeComponentBuild()
2884 componentStat.ids = compileState.ids.count();
2886 for (int ii = 0; ii < compileState.aliasingObjects.count(); ++ii) {
2887 QDeclarativeParser::Object *aliasObject = compileState.aliasingObjects.at(ii);
2888 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
2891 QDeclarativeBindingCompiler::Expression expr;
2892 expr.component = compileState.root;
2893 expr.ids = compileState.ids;
2895 QDeclarativeBindingCompiler bindingCompiler;
2897 for (QHash<QDeclarativeParser::Value*,BindingReference>::Iterator iter = compileState.bindings.begin();
2898 iter != compileState.bindings.end(); ++iter) {
2900 BindingReference &binding = *iter;
2902 expr.context = binding.bindingContext.object;
2903 expr.property = binding.property;
2904 expr.expression = binding.expression;
2905 expr.imports = unit->imports();
2907 // ### We don't currently optimize for bindings on alias's - because
2908 // of the solution to QTBUG-13719
2909 if (!binding.property->isAlias) {
2910 int index = bindingCompiler.compile(expr, enginePrivate);
2912 binding.dataType = BindingReference::Experimental;
2913 binding.compiledIndex = index;
2914 componentStat.optimizedBindings.append(iter.key()->location);
2919 binding.dataType = BindingReference::QtScript;
2921 // Pre-rewrite the expression
2922 QString expression = binding.expression.asScript();
2924 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2925 rewriteBinding.setName('$'+binding.property->name);
2926 bool isSharable = false;
2927 expression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
2929 quint32 length = expression.length();
2933 pc = output->cachedClosures.count();
2935 output->cachedClosures.append(0);
2937 pc = output->cachedPrograms.length();
2938 output->cachedPrograms.append(0);
2941 binding.compiledData =
2942 QByteArray((const char *)&pc, sizeof(quint32)) +
2943 QByteArray((const char *)&length, sizeof(quint32)) +
2944 QByteArray((const char *)expression.constData(),
2945 expression.length() * sizeof(QChar));
2947 componentStat.scriptBindings.append(iter.key()->location);
2950 if (bindingCompiler.isValid()) {
2951 compileState.compiledBindingData = bindingCompiler.program();
2953 QDeclarativeBindingCompiler::dump(compileState.compiledBindingData);
2956 saveComponentState();
2961 void QDeclarativeCompiler::dumpStats()
2963 qWarning().nospace() << "QML Document: " << output->url.toString();
2964 for (int ii = 0; ii < savedComponentStats.count(); ++ii) {
2965 const ComponentStat &stat = savedComponentStats.at(ii);
2966 qWarning().nospace() << " Component Line " << stat.lineNumber;
2967 qWarning().nospace() << " Total Objects: " << stat.objects;
2968 qWarning().nospace() << " IDs Used: " << stat.ids;
2969 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
2973 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
2974 if (0 == (ii % 10)) {
2975 if (ii) output.append("\n");
2980 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
2982 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
2983 output.append(") ");
2985 if (!output.isEmpty())
2986 qWarning().nospace() << output.constData();
2989 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
2992 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
2993 if (0 == (ii % 10)) {
2994 if (ii) output.append("\n");
2999 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3001 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3002 output.append(") ");
3004 if (!output.isEmpty())
3005 qWarning().nospace() << output.constData();
3011 Returns true if from can be assigned to a (QObject) property of type
3014 bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeParser::Object *from)
3016 const QMetaObject *toMo =
3017 enginePrivate->rawMetaObjectForType(to);
3018 const QMetaObject *fromMo = from->metaObject();
3021 if (QDeclarativePropertyPrivate::equal(fromMo, toMo))
3023 fromMo = fromMo->superClass();
3028 QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeParser::Object *from)
3031 const QMetaObject *mo = from->metatype;
3032 QDeclarativeType *type = 0;
3033 while (!type && mo) {
3034 type = QDeclarativeMetaType::qmlType(mo);
3035 mo = mo->superClass();
3040 QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeParser::Object *obj)
3042 const QMetaObject *mo = obj->metatype;
3044 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3046 return QStringList();
3048 QMetaClassInfo classInfo = mo->classInfo(idx);
3049 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3053 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3054 int QDeclarativeCompiler::indexOfSignal(QDeclarativeParser::Object *object, const QByteArray &name,
3055 bool *notInRevision)
3057 if (notInRevision) *notInRevision = false;
3059 if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) {
3061 QString strName(QString::fromUtf8(name));
3062 QDeclarativePropertyCache *cache =
3063 object->synthCache?object->synthCache:output->types.at(object->type).propertyCache();
3065 QDeclarativePropertyCache::Data *d = cache->property(strName);
3066 if (notInRevision) *notInRevision = false;
3068 while (d && !(d->flags & QDeclarativePropertyCache::Data::IsFunction))
3069 d = cache->overrideData(d);
3071 if (d && !cache->isAllowedInRevision(d)) {
3072 if (notInRevision) *notInRevision = true;
3075 return d->coreIndex;
3078 if (name.endsWith("Changed")) {
3079 QByteArray propName = name.mid(0, name.length() - 7);
3081 int propIndex = indexOfProperty(object, propName, notInRevision);
3082 if (propIndex != -1) {
3083 d = cache->property(propIndex);
3084 return d->notifyIndex;
3090 return QDeclarativePropertyPrivate::findSignalByName(object->metaObject(), name).methodIndex();
3095 int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QByteArray &name,
3096 bool *notInRevision)
3098 if (notInRevision) *notInRevision = false;
3100 if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) {
3102 QString strName(QString::fromUtf8(name));
3103 QDeclarativePropertyCache *cache =
3104 object->synthCache?object->synthCache:output->types.at(object->type).propertyCache();
3106 QDeclarativePropertyCache::Data *d = cache->property(strName);
3107 // Find the first property
3108 while (d && d->flags & QDeclarativePropertyCache::Data::IsFunction)
3109 d = cache->overrideData(d);
3111 if (d && !cache->isAllowedInRevision(d)) {
3112 if (notInRevision) *notInRevision = true;
3115 return d?d->coreIndex:-1;
3118 const QMetaObject *mo = object->metaObject();
3119 return mo->indexOfProperty(name.constData());