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/qdeclarativev4compiler_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);
83 using namespace QDeclarativeParser;
86 Instantiate a new QDeclarativeCompiler.
88 QDeclarativeCompiler::QDeclarativeCompiler()
89 : output(0), engine(0), unitRoot(0), unit(0)
94 Returns true if the last call to compile() caused errors.
98 bool QDeclarativeCompiler::isError() const
100 return !exceptions.isEmpty();
104 Return the list of errors from the last call to compile(), or an empty list
105 if there were no errors.
107 QList<QDeclarativeError> QDeclarativeCompiler::errors() const
113 Returns true if \a name refers to an attached property, false otherwise.
115 Attached property names are those that start with a capital letter.
117 bool QDeclarativeCompiler::isAttachedPropertyName(const QByteArray &name)
119 return !name.isEmpty() && name.at(0) >= 'A' && name.at(0) <= 'Z';
123 Returns true if \a name refers to a signal property, false otherwise.
125 Signal property names are those that start with "on", followed by a capital
128 bool QDeclarativeCompiler::isSignalPropertyName(const QByteArray &name)
130 return name.length() >= 3 && name.startsWith("on") &&
131 'A' <= name.at(2) && 'Z' >= name.at(2);
135 \macro COMPILE_EXCEPTION
137 Inserts an error into the QDeclarativeCompiler error list, and returns false
140 \a token is used to source the error line and column, and \a desc is the
141 error itself. \a desc can be an expression that can be piped into QDebug.
146 COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(QString::fromUtf8(property->name)));
149 #define COMPILE_EXCEPTION(token, desc) \
151 QString exceptionDescription; \
152 QDeclarativeError error; \
153 error.setUrl(output->url); \
154 error.setLine((token)->location.start.line); \
155 error.setColumn((token)->location.start.column); \
156 error.setDescription(desc.trimmed()); \
157 exceptions << error; \
164 Returns false if \a is false, otherwise does nothing.
166 #define COMPILE_CHECK(a) \
168 if (!a) return false; \
172 Returns true if literal \a v can be assigned to property \a prop, otherwise
175 This test corresponds to action taken by genLiteralAssignment(). Any change
176 made here, must have a corresponding action in genLiteralAssigment().
178 bool QDeclarativeCompiler::testLiteralAssignment(const QMetaProperty &prop,
179 QDeclarativeParser::Value *v)
181 QString string = v->value.asString();
183 if (!prop.isWritable())
184 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
186 if (prop.isEnumType()) {
188 if (prop.isFlagType()) {
189 value = prop.enumerator().keysToValue(string.toUtf8().constData());
191 value = prop.enumerator().keyToValue(string.toUtf8().constData());
193 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration"));
196 int type = prop.userType();
200 case QVariant::String:
201 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
203 case QVariant::ByteArray:
204 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected"));
207 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected"));
211 bool ok = v->value.isNumber();
213 double n = v->value.asNumber();
214 if (double(uint(n)) != n)
217 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected"));
222 bool ok = v->value.isNumber();
224 double n = v->value.asNumber();
225 if (double(int(n)) != n)
228 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected"));
231 case QMetaType::Float:
232 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
234 case QVariant::Double:
235 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
237 case QVariant::Color:
240 QDeclarativeStringConverters::colorFromString(string, &ok);
241 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected"));
244 #ifndef QT_NO_DATESTRING
248 QDeclarativeStringConverters::dateFromString(string, &ok);
249 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected"));
255 QDeclarativeStringConverters::timeFromString(string, &ok);
256 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected"));
259 case QVariant::DateTime:
262 QDeclarativeStringConverters::dateTimeFromString(string, &ok);
263 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected"));
266 #endif // QT_NO_DATESTRING
267 case QVariant::Point:
268 case QVariant::PointF:
271 QPointF point = QDeclarativeStringConverters::pointFFromString(string, &ok);
272 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected"));
276 case QVariant::SizeF:
279 QSizeF size = QDeclarativeStringConverters::sizeFFromString(string, &ok);
280 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected"));
284 case QVariant::RectF:
287 QRectF rect = QDeclarativeStringConverters::rectFFromString(string, &ok);
288 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected"));
293 if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected"));
296 case QVariant::Vector3D:
299 QDeclarativeStringConverters::vector3DFromString(string, &ok);
300 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected"));
305 int t = prop.userType();
306 QDeclarativeMetaType::StringConverter converter =
307 QDeclarativeMetaType::customStringConverter(t);
309 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName(prop.type()))));
317 Generate a store instruction for assigning literal \a v to property \a prop.
319 Any literal assignment that is approved in testLiteralAssignment() must have
320 a corresponding action in this method.
322 void QDeclarativeCompiler::genLiteralAssignment(const QMetaProperty &prop,
323 QDeclarativeParser::Value *v)
325 QDeclarativeInstruction instr;
326 if (prop.isEnumType()) {
328 if (v->value.isNumber()) {
330 value = (int)v->value.asNumber();
333 if (prop.isFlagType()) {
334 value = prop.enumerator().keysToValue(v->value.asString().toUtf8().constData());
336 value = prop.enumerator().keyToValue(v->value.asString().toUtf8().constData());
339 instr.type = QDeclarativeInstruction::StoreInteger;
340 instr.storeInteger.propertyIndex = prop.propertyIndex();
341 instr.storeInteger.value = value;
342 output->bytecode << instr;
346 QString string = v->value.asString();
348 int type = prop.userType();
352 if (v->value.isNumber()) {
353 double n = v->value.asNumber();
354 if (double(int(n)) == n) {
355 instr.type = QDeclarativeInstruction::StoreVariantInteger;
356 instr.storeInteger.propertyIndex = prop.propertyIndex();
357 instr.storeInteger.value = int(n);
359 instr.type = QDeclarativeInstruction::StoreVariantDouble;
360 instr.storeDouble.propertyIndex = prop.propertyIndex();
361 instr.storeDouble.value = n;
363 } else if(v->value.isBoolean()) {
364 instr.type = QDeclarativeInstruction::StoreVariantBool;
365 instr.storeBool.propertyIndex = prop.propertyIndex();
366 instr.storeBool.value = v->value.asBoolean();
368 instr.type = QDeclarativeInstruction::StoreVariant;
369 instr.storeString.propertyIndex = prop.propertyIndex();
370 instr.storeString.value = output->indexForString(string);
374 case QVariant::String:
376 instr.type = QDeclarativeInstruction::StoreString;
377 instr.storeString.propertyIndex = prop.propertyIndex();
378 instr.storeString.value = output->indexForString(string);
381 case QVariant::ByteArray:
383 instr.type = QDeclarativeInstruction::StoreByteArray;
384 instr.storeByteArray.propertyIndex = prop.propertyIndex();
385 instr.storeByteArray.value = output->indexForByteArray(string.toLatin1());
390 instr.type = QDeclarativeInstruction::StoreUrl;
391 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
392 instr.storeUrl.propertyIndex = prop.propertyIndex();
393 instr.storeUrl.value = output->indexForUrl(u);
398 instr.type = QDeclarativeInstruction::StoreInteger;
399 instr.storeInteger.propertyIndex = prop.propertyIndex();
400 instr.storeInteger.value = uint(v->value.asNumber());
405 instr.type = QDeclarativeInstruction::StoreInteger;
406 instr.storeInteger.propertyIndex = prop.propertyIndex();
407 instr.storeInteger.value = int(v->value.asNumber());
410 case QMetaType::Float:
412 instr.type = QDeclarativeInstruction::StoreFloat;
413 instr.storeFloat.propertyIndex = prop.propertyIndex();
414 instr.storeFloat.value = float(v->value.asNumber());
417 case QVariant::Double:
419 instr.type = QDeclarativeInstruction::StoreDouble;
420 instr.storeDouble.propertyIndex = prop.propertyIndex();
421 instr.storeDouble.value = v->value.asNumber();
424 case QVariant::Color:
426 QColor c = QDeclarativeStringConverters::colorFromString(string);
427 instr.type = QDeclarativeInstruction::StoreColor;
428 instr.storeColor.propertyIndex = prop.propertyIndex();
429 instr.storeColor.value = c.rgba();
432 #ifndef QT_NO_DATESTRING
435 QDate d = QDeclarativeStringConverters::dateFromString(string);
436 instr.type = QDeclarativeInstruction::StoreDate;
437 instr.storeDate.propertyIndex = prop.propertyIndex();
438 instr.storeDate.value = d.toJulianDay();
443 QTime time = QDeclarativeStringConverters::timeFromString(string);
444 int data[] = { time.hour(), time.minute(),
445 time.second(), time.msec() };
446 int index = output->indexForInt(data, 4);
447 instr.type = QDeclarativeInstruction::StoreTime;
448 instr.storeTime.propertyIndex = prop.propertyIndex();
449 instr.storeTime.valueIndex = index;
452 case QVariant::DateTime:
454 QDateTime dateTime = QDeclarativeStringConverters::dateTimeFromString(string);
455 int data[] = { dateTime.date().toJulianDay(),
456 dateTime.time().hour(),
457 dateTime.time().minute(),
458 dateTime.time().second(),
459 dateTime.time().msec() };
460 int index = output->indexForInt(data, 5);
461 instr.type = QDeclarativeInstruction::StoreDateTime;
462 instr.storeDateTime.propertyIndex = prop.propertyIndex();
463 instr.storeDateTime.valueIndex = index;
466 #endif // QT_NO_DATESTRING
467 case QVariant::Point:
468 case QVariant::PointF:
472 QDeclarativeStringConverters::pointFFromString(string, &ok);
473 float data[] = { float(point.x()), float(point.y()) };
474 int index = output->indexForFloat(data, 2);
475 if (type == QVariant::PointF)
476 instr.type = QDeclarativeInstruction::StorePointF;
478 instr.type = QDeclarativeInstruction::StorePoint;
479 instr.storeRealPair.propertyIndex = prop.propertyIndex();
480 instr.storeRealPair.valueIndex = index;
484 case QVariant::SizeF:
487 QSizeF size = QDeclarativeStringConverters::sizeFFromString(string, &ok);
488 float data[] = { float(size.width()), float(size.height()) };
489 int index = output->indexForFloat(data, 2);
490 if (type == QVariant::SizeF)
491 instr.type = QDeclarativeInstruction::StoreSizeF;
493 instr.type = QDeclarativeInstruction::StoreSize;
494 instr.storeRealPair.propertyIndex = prop.propertyIndex();
495 instr.storeRealPair.valueIndex = index;
499 case QVariant::RectF:
502 QRectF rect = QDeclarativeStringConverters::rectFFromString(string, &ok);
503 float data[] = { float(rect.x()), float(rect.y()),
504 float(rect.width()), float(rect.height()) };
505 int index = output->indexForFloat(data, 4);
506 if (type == QVariant::RectF)
507 instr.type = QDeclarativeInstruction::StoreRectF;
509 instr.type = QDeclarativeInstruction::StoreRect;
510 instr.storeRect.propertyIndex = prop.propertyIndex();
511 instr.storeRect.valueIndex = index;
516 bool b = v->value.asBoolean();
517 instr.type = QDeclarativeInstruction::StoreBool;
518 instr.storeBool.propertyIndex = prop.propertyIndex();
519 instr.storeBool.value = b;
522 case QVariant::Vector3D:
526 QDeclarativeStringConverters::vector3DFromString(string, &ok);
527 float data[] = { float(vector.x()), float(vector.y()), float(vector.z()) };
528 int index = output->indexForFloat(data, 3);
529 instr.type = QDeclarativeInstruction::StoreVector3D;
530 instr.storeRealPair.propertyIndex = prop.propertyIndex();
531 instr.storeRealPair.valueIndex = index;
536 int t = prop.userType();
537 int index = output->customTypeData.count();
538 instr.type = QDeclarativeInstruction::AssignCustomType;
539 instr.assignCustomType.propertyIndex = prop.propertyIndex();
540 instr.assignCustomType.valueIndex = index;
541 instr.assignCustomType.line = v->location.start.line;
543 QDeclarativeCompiledData::CustomTypeData data;
544 data.index = output->indexForString(string);
546 output->customTypeData << data;
550 output->bytecode << instr;
554 Resets data by clearing the lists that the QDeclarativeCompiler modifies.
556 void QDeclarativeCompiler::reset(QDeclarativeCompiledData *data)
559 data->primitives.clear();
560 data->floatData.clear();
561 data->intData.clear();
562 data->customTypeData.clear();
564 data->bytecode.clear();
568 Compile \a unit, and store the output in \a out. \a engine is the QDeclarativeEngine
569 with which the QDeclarativeCompiledData will be associated.
571 Returns true on success, false on failure. On failure, the compile errors
572 are available from errors().
574 If the environment variant QML_COMPILER_DUMP is set
575 (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
576 on a successful compiler.
578 bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine,
579 QDeclarativeTypeData *unit,
580 QDeclarativeCompiledData *out)
590 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
591 QList<QDeclarativeScriptParser::TypeReference *> referencedTypes = unit->parser().referencedTypes();
593 for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
594 QDeclarativeCompiledData::TypeReference ref;
596 const QDeclarativeTypeData::TypeReference &tref = resolvedTypes.at(ii);
597 QDeclarativeScriptParser::TypeReference *parserRef = referencedTypes.at(ii);
600 ref.type = tref.type;
601 if (!ref.type->isCreatable()) {
602 QString err = ref.type->noCreationReason();
604 err = tr( "Element is not creatable.");
605 COMPILE_EXCEPTION(parserRef->refObjects.first(), err);
608 if (ref.type->containsRevisionedAttributes()) {
609 QDeclarativeError cacheError;
610 ref.typePropertyCache =
611 QDeclarativeEnginePrivate::get(engine)->cache(ref.type, resolvedTypes.at(ii).minorVersion, cacheError);
613 if (!ref.typePropertyCache) {
614 COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description());
616 ref.typePropertyCache->addref();
619 } else if (tref.typeData) {
620 ref.component = tref.typeData->compiledData();
622 ref.className = parserRef->name.toUtf8();
626 QDeclarativeParser::Object *root = unit->parser().tree();
629 this->engine = engine;
630 this->enginePrivate = QDeclarativeEnginePrivate::get(engine);
632 this->unitRoot = root;
637 out->dumpInstructions();
638 if (compilerStatDump())
644 compileState = ComponentCompileState();
645 savedCompileStates.clear();
648 this->enginePrivate = 0;
655 void QDeclarativeCompiler::compileTree(QDeclarativeParser::Object *tree)
657 compileState.root = tree;
658 componentStat.lineNumber = tree->location.start.line;
660 // Build global import scripts
661 QStringList importedScriptIndexes;
663 foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
664 importedScriptIndexes.append(script.qualifier);
666 QDeclarativeInstruction import;
667 import.type = QDeclarativeInstruction::StoreImportedScript;
668 import.storeScript.value = output->scripts.count();
670 QDeclarativeScriptData *scriptData = script.script->scriptData();
671 scriptData->addref();
672 output->scripts << scriptData;
673 output->bytecode << import;
676 // We generate the importCache before we build the tree so that
677 // it can be used in the binding compiler. Given we "expect" the
678 // QML compilation to succeed, this isn't a waste.
679 output->importCache = new QDeclarativeTypeNameCache(engine);
680 for (int ii = 0; ii < importedScriptIndexes.count(); ++ii)
681 output->importCache->add(importedScriptIndexes.at(ii), ii);
682 unit->imports().populateCache(output->importCache, engine);
684 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
687 QDeclarativeInstruction init;
688 init.type = QDeclarativeInstruction::Init;
689 init.init.bindingsSize = compileState.bindings.count();
690 init.init.parserStatusSize = compileState.parserStatusCount;
691 init.init.contextCache = genContextCache();
692 if (compileState.compiledBindingData.isEmpty())
693 init.init.compiledBinding = -1;
695 init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData);
696 output->bytecode << init;
700 QDeclarativeInstruction def;
701 def.type = QDeclarativeInstruction::SetDefault;
702 output->bytecode << def;
704 Q_ASSERT(tree->metatype);
706 if (tree->metadata.isEmpty()) {
707 output->root = tree->metatype;
709 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
710 output->root = &output->rootData;
712 if (!tree->metadata.isEmpty())
713 enginePrivate->registerCompositeType(output);
716 static bool ValuePtrLessThan(const QDeclarativeParser::Value *t1, const QDeclarativeParser::Value *t2)
718 return t1->location.start.line < t2->location.start.line ||
719 (t1->location.start.line == t2->location.start.line &&
720 t1->location.start.column < t2->location.start.column);
723 bool QDeclarativeCompiler::buildObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
725 componentStat.objects++;
727 Q_ASSERT (obj->type != -1);
728 const QDeclarativeCompiledData::TypeReference &tr =
729 output->types.at(obj->type);
730 obj->metatype = tr.metaObject();
733 obj->url = tr.component->url;
735 obj->typeName = tr.type->qmlTypeName();
736 obj->className = tr.className;
738 // This object is a "Component" element
739 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
740 COMPILE_CHECK(buildComponent(obj, ctxt));
744 // Object instantiations reset the binding context
745 BindingContext objCtxt(obj);
747 // Create the synthesized meta object, ignoring aliases
748 COMPILE_CHECK(checkDynamicMeta(obj));
749 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
750 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
752 // Find the native type and check for the QDeclarativeParserStatus interface
753 QDeclarativeType *type = toQmlType(obj);
755 obj->parserStatusCast = type->parserStatusCast();
756 if (obj->parserStatusCast != -1)
757 compileState.parserStatusCount++;
759 // Check if this is a custom parser type. Custom parser types allow
760 // assignments to non-existent properties. These assignments are then
761 // compiled by the type.
762 bool isCustomParser = output->types.at(obj->type).type &&
763 output->types.at(obj->type).type->customParser() != 0;
764 QList<QDeclarativeCustomParserProperty> customProps;
766 // Fetch the list of deferred properties
767 QStringList deferredList = deferredProperties(obj);
769 // Must do id property first. This is to ensure that the id given to any
770 // id reference created matches the order in which the objects are
772 foreach(Property *prop, obj->properties) {
773 if (prop->name == "id") {
774 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
780 Property *defaultProperty = 0;
781 Property *skipProperty = 0;
782 if (obj->defaultProperty) {
783 const QMetaObject *metaObject = obj->metaObject();
784 Q_ASSERT(metaObject);
785 QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
787 Property *explicitProperty = obj->getProperty(p.name(), false);
788 if (explicitProperty && !explicitProperty->value) {
789 skipProperty = explicitProperty;
791 defaultProperty = new Property;
792 defaultProperty->parent = obj;
793 defaultProperty->isDefault = true;
794 defaultProperty->location = obj->defaultProperty->location;
795 defaultProperty->listValueRange = obj->defaultProperty->listValueRange;
796 defaultProperty->listCommaPositions = obj->defaultProperty->listCommaPositions;
798 defaultProperty->values = obj->defaultProperty->values;
799 defaultProperty->values += explicitProperty->values;
800 foreach(QDeclarativeParser::Value *value, defaultProperty->values)
802 qSort(defaultProperty->values.begin(), defaultProperty->values.end(), ValuePtrLessThan);
805 defaultProperty = obj->defaultProperty;
806 defaultProperty->addref();
809 defaultProperty = obj->defaultProperty;
810 defaultProperty->addref();
814 QDeclarativeCustomParser *cp = 0;
816 cp = output->types.at(obj->type).type->customParser();
818 // Build all explicit properties specified
819 foreach(Property *prop, obj->properties) {
821 if (prop == skipProperty)
823 if (prop->name == "id")
826 bool canDefer = false;
827 if (isCustomParser) {
828 if (doesPropertyExist(prop, obj) &&
829 (!(cp->flags() & QDeclarativeCustomParser::AcceptsAttachedProperties) ||
830 !isAttachedPropertyName(prop->name))) {
831 int ids = compileState.ids.count();
832 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
833 canDefer = ids == compileState.ids.count();
835 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
838 if (isSignalPropertyName(prop->name)) {
839 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
841 int ids = compileState.ids.count();
842 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
843 canDefer = ids == compileState.ids.count();
847 if (canDefer && !deferredList.isEmpty() &&
848 deferredList.contains(QString::fromUtf8(prop->name)))
849 prop->isDeferred = true;
853 // Build the default property
854 if (defaultProperty) {
855 Property *prop = defaultProperty;
857 bool canDefer = false;
858 if (isCustomParser) {
859 if (doesPropertyExist(prop, obj)) {
860 int ids = compileState.ids.count();
861 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
862 canDefer = ids == compileState.ids.count();
864 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
867 int ids = compileState.ids.count();
868 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
869 canDefer = ids == compileState.ids.count();
872 if (canDefer && !deferredList.isEmpty() &&
873 deferredList.contains(QString::fromUtf8(prop->name)))
874 prop->isDeferred = true;
878 defaultProperty->release();
880 // Compile custom parser parts
881 if (isCustomParser && !customProps.isEmpty()) {
885 obj->custom = cp->compile(customProps);
888 foreach (QDeclarativeError err, cp->errors()) {
889 err.setUrl(output->url);
897 void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj)
899 QDeclarativeCompiledData::TypeReference &tr = output->types[obj->type];
900 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
906 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
907 !output->types.at(obj->type).type->isExtendedType() && obj != compileState.root) {
909 QDeclarativeInstruction create;
910 create.type = QDeclarativeInstruction::CreateSimpleObject;
911 create.createSimple.create = output->types.at(obj->type).type->createFunction();
912 create.createSimple.typeSize = output->types.at(obj->type).type->createSize();
913 create.createSimple.type = obj->type;
914 create.createSimple.line = obj->location.start.line;
915 create.createSimple.column = obj->location.start.column;
916 output->bytecode << create;
920 QDeclarativeInstruction create;
921 create.type = QDeclarativeInstruction::CreateObject;
922 create.create.line = obj->location.start.line;
923 create.create.column = obj->location.start.column;
924 create.create.data = -1;
925 if (!obj->custom.isEmpty())
926 create.create.data = output->indexForByteArray(obj->custom);
927 create.create.type = obj->type;
928 if (!output->types.at(create.create.type).type &&
929 !obj->bindingBitmask.isEmpty()) {
930 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
931 create.create.bindingBits =
932 output->indexForByteArray(obj->bindingBitmask);
934 create.create.bindingBits = -1;
936 output->bytecode << create;
940 // Setup the synthesized meta object if necessary
941 if (!obj->metadata.isEmpty()) {
942 QDeclarativeInstruction meta;
943 meta.type = QDeclarativeInstruction::StoreMetaObject;
944 meta.storeMeta.data = output->indexForByteArray(obj->metadata);
945 meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata);
946 meta.storeMeta.propertyCache = output->propertyCaches.count();
948 QDeclarativePropertyCache *propertyCache = obj->synthCache;
949 Q_ASSERT(propertyCache);
950 propertyCache->addref();
952 // Add flag for alias properties
953 if (!obj->synthdata.isEmpty()) {
954 const QDeclarativeVMEMetaData *vmeMetaData =
955 reinterpret_cast<const QDeclarativeVMEMetaData *>(obj->synthdata.constData());
956 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
957 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
958 propertyCache->property(index)->flags |= QDeclarativePropertyCache::Data::IsAlias;
962 if (obj == unitRoot) {
963 propertyCache->addref();
964 output->rootPropertyCache = propertyCache;
967 output->propertyCaches << propertyCache;
968 output->bytecode << meta;
969 } else if (obj == unitRoot) {
970 output->rootPropertyCache = tr.createPropertyCache(engine);
971 output->rootPropertyCache->addref();
975 if (!obj->id.isEmpty()) {
976 QDeclarativeInstruction id;
977 id.type = QDeclarativeInstruction::SetId;
978 id.setId.value = output->indexForString(obj->id);
979 id.setId.index = obj->idIndex;
980 output->bytecode << id;
984 if (tr.type && obj->parserStatusCast != -1) {
985 QDeclarativeInstruction begin;
986 begin.type = QDeclarativeInstruction::BeginObject;
987 begin.begin.castValue = obj->parserStatusCast;
988 output->bytecode << begin;
994 void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj)
996 typedef QPair<Property *, int> PropPair;
997 foreach(const PropPair &prop, obj->scriptStringProperties) {
998 QDeclarativeInstruction ss;
999 ss.type = QDeclarativeInstruction::StoreScriptString;
1000 ss.storeScriptString.propertyIndex = prop.first->index;
1001 ss.storeScriptString.value =
1002 output->indexForString(prop.first->values.at(0)->value.asScript());
1003 ss.storeScriptString.scope = prop.second;
1004 output->bytecode << ss;
1007 bool seenDefer = false;
1008 foreach(Property *prop, obj->valueProperties) {
1009 if (prop->isDeferred) {
1014 genValueProperty(prop, obj);
1017 QDeclarativeInstruction defer;
1018 defer.type = QDeclarativeInstruction::Defer;
1019 defer.defer.deferCount = 0;
1020 int deferIdx = output->bytecode.count();
1021 output->bytecode << defer;
1023 QDeclarativeInstruction init;
1024 init.type = QDeclarativeInstruction::Init;
1025 init.init.bindingsSize = compileState.bindings.count(); // XXX - bigger than necessary
1026 init.init.parserStatusSize = compileState.parserStatusCount; // XXX - bigger than necessary
1027 init.init.contextCache = -1;
1028 init.init.compiledBinding = -1;
1029 output->bytecode << init;
1031 foreach(Property *prop, obj->valueProperties) {
1032 if (!prop->isDeferred)
1034 genValueProperty(prop, obj);
1037 output->bytecode[deferIdx].defer.deferCount =
1038 output->bytecode.count() - deferIdx - 1;
1041 foreach(Property *prop, obj->signalProperties) {
1043 QDeclarativeParser::Value *v = prop->values.at(0);
1045 if (v->type == Value::SignalObject) {
1047 genObject(v->object);
1049 QDeclarativeInstruction assign;
1050 assign.type = QDeclarativeInstruction::AssignSignalObject;
1051 assign.assignSignalObject.line = v->location.start.line;
1052 assign.assignSignalObject.signal =
1053 output->indexForByteArray(prop->name);
1054 output->bytecode << assign;
1056 } else if (v->type == Value::SignalExpression) {
1058 BindingContext ctxt = compileState.signalExpressions.value(v);
1060 QDeclarativeInstruction store;
1061 store.type = QDeclarativeInstruction::StoreSignal;
1062 store.storeSignal.signalIndex = prop->index;
1063 store.storeSignal.value =
1064 output->indexForString(v->value.asScript().trimmed());
1065 store.storeSignal.context = ctxt.stack;
1066 store.storeSignal.name = output->indexForByteArray(prop->name);
1067 store.storeSignal.line = v->location.start.line;
1068 output->bytecode << store;
1074 foreach(Property *prop, obj->attachedProperties) {
1075 QDeclarativeInstruction fetch;
1076 fetch.type = QDeclarativeInstruction::FetchAttached;
1077 fetch.fetchAttached.id = prop->index;
1078 fetch.fetchAttached.line = prop->location.start.line;
1079 output->bytecode << fetch;
1081 genObjectBody(prop->value);
1083 QDeclarativeInstruction pop;
1084 pop.type = QDeclarativeInstruction::PopFetchedObject;
1085 output->bytecode << pop;
1088 foreach(Property *prop, obj->groupedProperties) {
1089 QDeclarativeInstruction fetch;
1090 fetch.type = QDeclarativeInstruction::FetchObject;
1091 fetch.fetch.property = prop->index;
1092 fetch.fetch.line = prop->location.start.line;
1093 output->bytecode << fetch;
1095 if (!prop->value->metadata.isEmpty()) {
1096 QDeclarativeInstruction meta;
1097 meta.type = QDeclarativeInstruction::StoreMetaObject;
1098 meta.storeMeta.data = output->indexForByteArray(prop->value->metadata);
1099 meta.storeMeta.aliasData = output->indexForByteArray(prop->value->synthdata);
1100 meta.storeMeta.propertyCache = -1;
1101 output->bytecode << meta;
1104 genObjectBody(prop->value);
1106 QDeclarativeInstruction pop;
1107 pop.type = QDeclarativeInstruction::PopFetchedObject;
1108 output->bytecode << pop;
1111 foreach(Property *prop, obj->valueTypeProperties) {
1113 genValueTypeProperty(obj, prop);
1116 foreach(Property *prop, obj->valueProperties) {
1117 if (prop->isDeferred)
1120 genValueProperty(prop, obj);
1123 foreach(Property *prop, obj->valueTypeProperties) {
1125 genValueTypeProperty(obj, prop);
1129 void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeParser::Object *obj,QDeclarativeParser::Property *prop)
1131 QDeclarativeInstruction fetch;
1132 fetch.type = QDeclarativeInstruction::FetchValueType;
1133 fetch.fetchValue.property = prop->index;
1134 fetch.fetchValue.type = prop->type;
1135 fetch.fetchValue.bindingSkipList = 0;
1137 if (obj->type == -1 || output->types.at(obj->type).component) {
1138 // We only have to do this if this is a composite type. If it is a builtin
1139 // type it can't possibly already have bindings that need to be cleared.
1140 foreach(Property *vprop, prop->value->valueProperties) {
1141 if (!vprop->values.isEmpty()) {
1142 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1143 fetch.fetchValue.bindingSkipList |= (1 << vprop->index);
1148 output->bytecode << fetch;
1150 foreach(Property *vprop, prop->value->valueProperties) {
1151 genPropertyAssignment(vprop, prop->value, prop);
1154 QDeclarativeInstruction pop;
1155 pop.type = QDeclarativeInstruction::PopValueType;
1156 pop.fetchValue.property = prop->index;
1157 pop.fetchValue.type = prop->type;
1158 pop.fetchValue.bindingSkipList = 0;
1159 output->bytecode << pop;
1162 void QDeclarativeCompiler::genComponent(QDeclarativeParser::Object *obj)
1164 QDeclarativeParser::Object *root = obj->defaultProperty->values.at(0)->object;
1167 QDeclarativeInstruction create;
1168 create.type = QDeclarativeInstruction::CreateComponent;
1169 create.createComponent.line = root->location.start.line;
1170 create.createComponent.column = root->location.start.column;
1171 create.createComponent.endLine = root->location.end.line;
1172 output->bytecode << create;
1173 int count = output->bytecode.count();
1175 ComponentCompileState oldCompileState = compileState;
1176 compileState = componentState(root);
1178 QDeclarativeInstruction init;
1179 init.type = QDeclarativeInstruction::Init;
1180 init.init.bindingsSize = compileState.bindings.count();
1181 init.init.parserStatusSize = compileState.parserStatusCount;
1182 init.init.contextCache = genContextCache();
1183 if (compileState.compiledBindingData.isEmpty())
1184 init.init.compiledBinding = -1;
1186 init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData);
1187 output->bytecode << init;
1191 QDeclarativeInstruction def;
1192 def.type = QDeclarativeInstruction::SetDefault;
1193 output->bytecode << def;
1195 output->bytecode[count - 1].createComponent.count =
1196 output->bytecode.count() - count;
1198 compileState = oldCompileState;
1200 if (!obj->id.isEmpty()) {
1201 QDeclarativeInstruction id;
1202 id.type = QDeclarativeInstruction::SetId;
1203 id.setId.value = output->indexForString(obj->id);
1204 id.setId.index = obj->idIndex;
1205 output->bytecode << id;
1209 bool QDeclarativeCompiler::buildComponent(QDeclarativeParser::Object *obj,
1210 const BindingContext &ctxt)
1212 // The special "Component" element can only have the id property and a
1213 // default property, that actually defines the component's tree
1215 // Find, check and set the "id" property (if any)
1216 Property *idProp = 0;
1217 if (obj->properties.count() > 1 ||
1218 (obj->properties.count() == 1 && obj->properties.begin().key() != "id"))
1219 COMPILE_EXCEPTION(*obj->properties.begin(), tr("Component elements may not contain properties other than id"));
1221 if (obj->properties.count())
1222 idProp = *obj->properties.begin();
1225 if (idProp->value || idProp->values.count() > 1 || idProp->values.at(0)->object)
1226 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1227 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1229 QString idVal = idProp->values.first()->primitive();
1231 if (compileState.ids.contains(idVal))
1232 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1238 // Check the Component tree is well formed
1239 if (obj->defaultProperty &&
1240 (obj->defaultProperty->value || obj->defaultProperty->values.count() > 1 ||
1241 (obj->defaultProperty->values.count() == 1 && !obj->defaultProperty->values.first()->object)))
1242 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1244 if (!obj->dynamicProperties.isEmpty())
1245 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1246 if (!obj->dynamicSignals.isEmpty())
1247 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1248 if (!obj->dynamicSlots.isEmpty())
1249 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1251 QDeclarativeParser::Object *root = 0;
1252 if (obj->defaultProperty && obj->defaultProperty->values.count())
1253 root = obj->defaultProperty->values.first()->object;
1256 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1258 // Build the component tree
1259 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1264 bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeParser::Object *obj,
1265 const BindingContext &ctxt)
1267 ComponentCompileState oldComponentCompileState = compileState;
1268 ComponentStat oldComponentStat = componentStat;
1270 compileState = ComponentCompileState();
1271 compileState.root = obj;
1272 compileState.nested = true;
1274 componentStat = ComponentStat();
1275 componentStat.lineNumber = obj->location.start.line;
1278 COMPILE_CHECK(buildObject(obj, ctxt));
1280 COMPILE_CHECK(completeComponentBuild());
1282 compileState = oldComponentCompileState;
1283 componentStat = oldComponentStat;
1289 // Build a sub-object. A sub-object is one that was not created directly by
1290 // QML - such as a grouped property object, or an attached object. Sub-object's
1291 // can't have an id, involve a custom parser, have attached properties etc.
1292 bool QDeclarativeCompiler::buildSubObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
1294 Q_ASSERT(obj->metatype);
1295 Q_ASSERT(!obj->defaultProperty);
1296 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1299 foreach(Property *prop, obj->properties) {
1300 if (isSignalPropertyName(prop->name)) {
1301 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1303 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1310 int QDeclarativeCompiler::componentTypeRef()
1312 QDeclarativeType *t = QDeclarativeMetaType::qmlType("QtQuick/Component",1,0);
1313 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1314 if (output->types.at(ii).type == t)
1317 QDeclarativeCompiledData::TypeReference ref;
1318 ref.className = "Component";
1320 output->types << ref;
1321 return output->types.count() - 1;
1324 bool QDeclarativeCompiler::buildSignal(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj,
1325 const BindingContext &ctxt)
1327 Q_ASSERT(obj->metaObject());
1329 QByteArray name = prop->name;
1330 Q_ASSERT(name.startsWith("on"));
1332 if(name[0] >= 'A' && name[0] <= 'Z')
1333 name[0] = name[0] - 'A' + 'a';
1335 bool notInRevision = false;
1336 int sigIdx = indexOfSignal(obj, name, ¬InRevision);
1340 if (notInRevision && -1 == indexOfProperty(obj, prop->name, 0)) {
1341 Q_ASSERT(obj->type != -1);
1342 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1343 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1345 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));
1347 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)));
1351 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1353 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1357 if (prop->value || prop->values.count() != 1)
1358 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1360 prop->index = sigIdx;
1361 obj->addSignalProperty(prop);
1363 if (prop->values.at(0)->object) {
1364 COMPILE_CHECK(buildObject(prop->values.at(0)->object, ctxt));
1365 prop->values.at(0)->type = Value::SignalObject;
1367 prop->values.at(0)->type = Value::SignalExpression;
1369 if (!prop->values.at(0)->value.isScript())
1370 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1372 QString script = prop->values.at(0)->value.asScript().trimmed();
1373 if (script.isEmpty())
1374 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1376 compileState.signalExpressions.insert(prop->values.at(0), ctxt);
1385 Returns true if (value) property \a prop exists on obj, false otherwise.
1387 bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeParser::Property *prop,
1388 QDeclarativeParser::Object *obj)
1390 if(isAttachedPropertyName(prop->name) || prop->name == "id")
1393 const QMetaObject *mo = obj->metaObject();
1395 if (prop->isDefault) {
1396 QMetaProperty p = QDeclarativeMetaType::defaultProperty(mo);
1397 return p.name() != 0;
1399 int idx = indexOfProperty(obj, prop->name);
1400 return idx != -1 && mo->property(idx).isScriptable();
1407 bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop,
1408 QDeclarativeParser::Object *obj,
1409 const BindingContext &ctxt)
1411 if (prop->isEmpty())
1412 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1414 const QMetaObject *metaObject = obj->metaObject();
1415 Q_ASSERT(metaObject);
1417 if (isAttachedPropertyName(prop->name)) {
1418 // Setup attached property data
1420 if (ctxt.isSubContext()) {
1421 // Attached properties cannot be used on sub-objects. Sub-objects
1422 // always exist in a binding sub-context, which is what we test
1424 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1427 QDeclarativeType *type = 0;
1428 QDeclarativeImportedNamespace *typeNamespace = 0;
1429 unit->imports().resolveType(prop->name, &type, 0, 0, 0, &typeNamespace);
1431 if (typeNamespace) {
1432 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1435 } else if (!type || !type->attachedPropertiesType()) {
1436 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1440 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1442 Q_ASSERT(type->attachedPropertiesFunction());
1443 prop->index = type->attachedPropertiesId();
1444 prop->value->metatype = type->attachedPropertiesType();
1446 // Setup regular property data
1449 if (prop->isDefault) {
1450 p = QDeclarativeMetaType::defaultProperty(metaObject);
1453 prop->index = p.propertyIndex();
1454 prop->name = p.name();
1458 bool notInRevision = false;
1459 prop->index = indexOfProperty(obj, prop->name, ¬InRevision);
1460 if (prop->index == -1 && notInRevision) {
1461 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1462 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1464 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));
1466 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)));
1470 if (prop->index != -1) {
1471 p = metaObject->property(prop->index);
1474 if (!p.isScriptable()) {
1476 p = QMetaProperty();
1481 // We can't error here as the "id" property does not require a
1482 // successful index resolution
1484 prop->type = p.userType();
1486 // Check if this is an alias
1487 if (prop->index != -1 &&
1489 prop->parent->type != -1 &&
1490 output->types.at(prop->parent->type).component) {
1492 QDeclarativePropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1493 if (cache && cache->property(prop->index) &&
1494 cache->property(prop->index)->flags & QDeclarativePropertyCache::Data::IsAlias)
1495 prop->isAlias = true;
1498 if (prop->index != -1 && !prop->values.isEmpty())
1499 prop->parent->setBindingBit(prop->index);
1502 if (!prop->isDefault && prop->name == "id" && !ctxt.isSubContext()) {
1504 // The magic "id" behavior doesn't apply when "id" is resolved as a
1505 // default property or to sub-objects (which are always in binding
1507 COMPILE_CHECK(buildIdProperty(prop, obj));
1508 if (prop->type == QVariant::String &&
1509 prop->values.at(0)->value.isString())
1510 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1512 } else if (isAttachedPropertyName(prop->name)) {
1514 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1516 } else if (prop->index == -1) {
1518 if (prop->isDefault) {
1519 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1521 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1524 } else if (prop->value) {
1526 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1528 } else if (enginePrivate->isList(prop->type)) {
1530 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1532 } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) {
1534 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1538 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1545 bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
1546 QDeclarativeParser::Property *nsProp,
1547 QDeclarativeParser::Object *obj,
1548 const BindingContext &ctxt)
1551 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1553 foreach (Property *prop, nsProp->value->properties) {
1555 if (!isAttachedPropertyName(prop->name))
1556 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1558 // Setup attached property data
1560 QDeclarativeType *type = 0;
1561 unit->imports().resolveType(ns, prop->name, &type, 0, 0, 0);
1563 if (!type || !type->attachedPropertiesType())
1564 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1567 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1569 Q_ASSERT(type->attachedPropertiesFunction());
1570 prop->index = type->index();
1571 prop->value->metatype = type->attachedPropertiesType();
1573 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1579 void QDeclarativeCompiler::genValueProperty(QDeclarativeParser::Property *prop,
1580 QDeclarativeParser::Object *obj)
1582 if (enginePrivate->isList(prop->type)) {
1583 genListProperty(prop, obj);
1585 genPropertyAssignment(prop, obj);
1589 void QDeclarativeCompiler::genListProperty(QDeclarativeParser::Property *prop,
1590 QDeclarativeParser::Object *obj)
1592 int listType = enginePrivate->listType(prop->type);
1594 QDeclarativeInstruction fetch;
1595 fetch.type = QDeclarativeInstruction::FetchQList;
1596 fetch.fetchQmlList.property = prop->index;
1597 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1598 fetch.fetchQmlList.type = listType;
1599 output->bytecode << fetch;
1601 for (int ii = 0; ii < prop->values.count(); ++ii) {
1602 QDeclarativeParser::Value *v = prop->values.at(ii);
1604 if (v->type == Value::CreatedObject) {
1606 genObject(v->object);
1607 if (listTypeIsInterface) {
1608 QDeclarativeInstruction assign;
1609 assign.type = QDeclarativeInstruction::AssignObjectList;
1610 assign.assignObjectList.line = prop->location.start.line;
1611 output->bytecode << assign;
1613 QDeclarativeInstruction store;
1614 store.type = QDeclarativeInstruction::StoreObjectQList;
1615 output->bytecode << store;
1618 } else if (v->type == Value::PropertyBinding) {
1620 genBindingAssignment(v, prop, obj);
1626 QDeclarativeInstruction pop;
1627 pop.type = QDeclarativeInstruction::PopQList;
1628 output->bytecode << pop;
1631 void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *prop,
1632 QDeclarativeParser::Object *obj,
1633 QDeclarativeParser::Property *valueTypeProperty)
1635 for (int ii = 0; ii < prop->values.count(); ++ii) {
1636 QDeclarativeParser::Value *v = prop->values.at(ii);
1638 Q_ASSERT(v->type == Value::CreatedObject ||
1639 v->type == Value::PropertyBinding ||
1640 v->type == Value::Literal);
1642 if (v->type == Value::CreatedObject) {
1644 genObject(v->object);
1646 if (QDeclarativeMetaType::isInterface(prop->type)) {
1648 QDeclarativeInstruction store;
1649 store.type = QDeclarativeInstruction::StoreInterface;
1650 store.storeObject.line = v->object->location.start.line;
1651 store.storeObject.propertyIndex = prop->index;
1652 output->bytecode << store;
1654 } else if (prop->type == -1) {
1656 QDeclarativeInstruction store;
1657 store.type = QDeclarativeInstruction::StoreVariantObject;
1658 store.storeObject.line = v->object->location.start.line;
1659 store.storeObject.propertyIndex = prop->index;
1660 output->bytecode << store;
1664 QDeclarativeInstruction store;
1665 store.type = QDeclarativeInstruction::StoreObject;
1666 store.storeObject.line = v->object->location.start.line;
1667 store.storeObject.propertyIndex = prop->index;
1668 output->bytecode << store;
1671 } else if (v->type == Value::PropertyBinding) {
1673 genBindingAssignment(v, prop, obj, valueTypeProperty);
1675 } else if (v->type == Value::Literal) {
1677 QMetaProperty mp = obj->metaObject()->property(prop->index);
1678 genLiteralAssignment(mp, v);
1684 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
1686 QDeclarativeParser::Value *v = prop->onValues.at(ii);
1688 Q_ASSERT(v->type == Value::ValueSource ||
1689 v->type == Value::ValueInterceptor);
1691 if (v->type == Value::ValueSource) {
1692 genObject(v->object);
1694 QDeclarativeInstruction store;
1695 store.type = QDeclarativeInstruction::StoreValueSource;
1696 if (valueTypeProperty) {
1697 store.assignValueSource.property = genValueTypeData(prop, valueTypeProperty);
1698 store.assignValueSource.owner = 1;
1700 store.assignValueSource.property = genPropertyData(prop);
1701 store.assignValueSource.owner = 0;
1703 QDeclarativeType *valueType = toQmlType(v->object);
1704 store.assignValueSource.castValue = valueType->propertyValueSourceCast();
1705 output->bytecode << store;
1707 } else if (v->type == Value::ValueInterceptor) {
1708 genObject(v->object);
1710 QDeclarativeInstruction store;
1711 store.type = QDeclarativeInstruction::StoreValueInterceptor;
1712 if (valueTypeProperty) {
1713 store.assignValueInterceptor.property = genValueTypeData(prop, valueTypeProperty);
1714 store.assignValueInterceptor.owner = 1;
1716 store.assignValueInterceptor.property = genPropertyData(prop);
1717 store.assignValueInterceptor.owner = 0;
1719 QDeclarativeType *valueType = toQmlType(v->object);
1720 store.assignValueInterceptor.castValue = valueType->propertyValueInterceptorCast();
1721 output->bytecode << store;
1727 bool QDeclarativeCompiler::buildIdProperty(QDeclarativeParser::Property *prop,
1728 QDeclarativeParser::Object *obj)
1731 prop->values.count() > 1 ||
1732 prop->values.at(0)->object)
1733 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
1735 QDeclarativeParser::Value *idValue = prop->values.at(0);
1736 QString val = idValue->primitive();
1738 COMPILE_CHECK(checkValidId(idValue, val));
1740 if (compileState.ids.contains(val))
1741 COMPILE_EXCEPTION(prop, tr("id is not unique"));
1743 prop->values.at(0)->type = Value::Id;
1751 void QDeclarativeCompiler::addId(const QString &id, QDeclarativeParser::Object *obj)
1753 Q_ASSERT(!compileState.ids.contains(id));
1754 Q_ASSERT(obj->id == id);
1755 obj->idIndex = compileState.ids.count();
1756 compileState.ids.insert(id, obj);
1757 compileState.idIndexes.insert(obj->idIndex, obj);
1760 void QDeclarativeCompiler::addBindingReference(const BindingReference &ref)
1762 Q_ASSERT(ref.value && !compileState.bindings.contains(ref.value));
1763 compileState.bindings.insert(ref.value, ref);
1766 void QDeclarativeCompiler::saveComponentState()
1768 Q_ASSERT(compileState.root);
1769 Q_ASSERT(!savedCompileStates.contains(compileState.root));
1771 savedCompileStates.insert(compileState.root, compileState);
1772 savedComponentStats.append(componentStat);
1775 QDeclarativeCompiler::ComponentCompileState
1776 QDeclarativeCompiler::componentState(QDeclarativeParser::Object *obj)
1778 Q_ASSERT(savedCompileStates.contains(obj));
1779 return savedCompileStates.value(obj);
1782 // Build attached property object. In this example,
1786 // GridView is an attached property object.
1787 bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeParser::Property *prop,
1788 QDeclarativeParser::Object *obj,
1789 const BindingContext &ctxt)
1791 Q_ASSERT(prop->value);
1792 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
1794 obj->addAttachedProperty(prop);
1796 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1802 // Build "grouped" properties. In this example:
1804 // font.pointSize: 12
1805 // font.family: "Helvetica"
1807 // font is a nested property. pointSize and family are not.
1808 bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeParser::Property *prop,
1809 QDeclarativeParser::Object *obj,
1810 const BindingContext &ctxt)
1812 Q_ASSERT(prop->type != 0);
1813 Q_ASSERT(prop->index != -1);
1815 if (QDeclarativeValueTypeFactory::isValueType(prop->type)) {
1816 if (prop->type >= 0 /* QVariant == -1 */ && enginePrivate->valueTypes[prop->type]) {
1818 if (prop->values.count()) {
1819 if (prop->values.at(0)->location < prop->value->location) {
1820 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
1822 COMPILE_EXCEPTION(prop->values.at(0), tr( "Property has already been assigned a value"));
1826 if (!obj->metaObject()->property(prop->index).isWritable()) {
1827 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
1831 if (prop->isAlias) {
1832 foreach (Property *vtProp, prop->value->properties)
1833 vtProp->isAlias = true;
1836 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
1837 prop->value, obj, ctxt.incr()));
1838 obj->addValueTypeProperty(prop);
1840 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1844 // Load the nested property's meta type
1845 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
1846 if (!prop->value->metatype)
1847 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1849 if (prop->values.count())
1850 COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign a value directly to a grouped property"));
1852 obj->addGroupedProperty(prop);
1854 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1860 bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
1861 QDeclarativeParser::Object *obj,
1862 QDeclarativeParser::Object *baseObj,
1863 const BindingContext &ctxt)
1865 if (obj->defaultProperty)
1866 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
1867 obj->metatype = type->metaObject();
1869 foreach (Property *prop, obj->properties) {
1870 int idx = type->metaObject()->indexOfProperty(prop->name.constData());
1872 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1873 QMetaProperty p = type->metaObject()->property(idx);
1874 if (!p.isScriptable())
1875 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1877 prop->type = p.userType();
1878 prop->isValueTypeSubProperty = true;
1881 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
1883 if (prop->values.count() > 1) {
1884 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
1885 } else if (prop->values.count()) {
1886 QDeclarativeParser::Value *value = prop->values.at(0);
1888 if (value->object) {
1889 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
1890 } else if (value->value.isScript()) {
1891 // ### Check for writability
1893 //optimization for <Type>.<EnumValue> enum assignments
1894 bool isEnumAssignment = false;
1895 COMPILE_CHECK(testQualifiedEnumAssignment(p, obj, value, &isEnumAssignment));
1896 if (isEnumAssignment) {
1897 value->type = Value::Literal;
1899 BindingReference reference;
1900 reference.expression = value->value;
1901 reference.property = prop;
1902 reference.value = value;
1903 reference.bindingContext = ctxt;
1904 reference.bindingContext.owner++;
1905 addBindingReference(reference);
1906 value->type = Value::PropertyBinding;
1909 COMPILE_CHECK(testLiteralAssignment(p, value));
1910 value->type = Value::Literal;
1914 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
1915 QDeclarativeParser::Value *v = prop->onValues.at(ii);
1916 Q_ASSERT(v->object);
1918 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
1921 obj->addValueProperty(prop);
1927 // Build assignments to QML lists. QML lists are properties of type
1928 // QDeclarativeListProperty<T>. List properties can accept a list of
1929 // objects, or a single binding.
1930 bool QDeclarativeCompiler::buildListProperty(QDeclarativeParser::Property *prop,
1931 QDeclarativeParser::Object *obj,
1932 const BindingContext &ctxt)
1934 Q_ASSERT(enginePrivate->isList(prop->type));
1938 obj->addValueProperty(prop);
1940 int listType = enginePrivate->listType(t);
1941 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1943 bool assignedBinding = false;
1944 for (int ii = 0; ii < prop->values.count(); ++ii) {
1945 QDeclarativeParser::Value *v = prop->values.at(ii);
1947 v->type = Value::CreatedObject;
1948 COMPILE_CHECK(buildObject(v->object, ctxt));
1950 // We check object coercian here. We check interface assignment
1952 if (!listTypeIsInterface) {
1953 if (!canCoerce(listType, v->object)) {
1954 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
1958 } else if (v->value.isScript()) {
1959 if (assignedBinding)
1960 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
1962 assignedBinding = true;
1963 COMPILE_CHECK(buildBinding(v, prop, ctxt));
1964 v->type = Value::PropertyBinding;
1966 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
1973 // Compiles an assignment to a QDeclarativeScriptString property
1974 bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeParser::Property *prop,
1975 QDeclarativeParser::Object *obj,
1976 const BindingContext &ctxt)
1978 if (prop->values.count() > 1)
1979 COMPILE_EXCEPTION(prop->values.at(1), tr( "Cannot assign multiple values to a script property"));
1981 if (prop->values.at(0)->object)
1982 COMPILE_EXCEPTION(prop->values.at(0), tr( "Invalid property assignment: script expected"));
1984 obj->addScriptStringProperty(prop, ctxt.stack);
1989 // Compile regular property assignments of the form "property: <value>"
1990 bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeParser::Property *prop,
1991 QDeclarativeParser::Object *obj,
1992 const BindingContext &ctxt)
1994 obj->addValueProperty(prop);
1996 if (prop->values.count() > 1)
1997 COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign multiple values to a singular property") );
1999 for (int ii = 0; ii < prop->values.count(); ++ii) {
2000 QDeclarativeParser::Value *v = prop->values.at(ii);
2003 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2007 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2012 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
2013 QDeclarativeParser::Value *v = prop->onValues.at(ii);
2015 Q_ASSERT(v->object);
2016 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2022 // Compile assigning a single object instance to a regular property
2023 bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeParser::Property *prop,
2024 QDeclarativeParser::Object *obj,
2025 QDeclarativeParser::Value *v,
2026 const BindingContext &ctxt)
2028 Q_ASSERT(prop->index != -1);
2029 Q_ASSERT(v->object->type != -1);
2031 if (!obj->metaObject()->property(prop->index).isWritable())
2032 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2034 if (QDeclarativeMetaType::isInterface(prop->type)) {
2036 // Assigning an object to an interface ptr property
2037 COMPILE_CHECK(buildObject(v->object, ctxt));
2039 v->type = Value::CreatedObject;
2041 } else if (prop->type == -1) {
2043 // Assigning an object to a QVariant
2044 COMPILE_CHECK(buildObject(v->object, ctxt));
2046 v->type = Value::CreatedObject;
2048 // Normally buildObject() will set this up, but we need the static
2049 // meta object earlier to test for assignability. It doesn't matter
2050 // that there may still be outstanding synthesized meta object changes
2051 // on this type, as they are not relevant for assignability testing
2052 v->object->metatype = output->types.at(v->object->type).metaObject();
2053 Q_ASSERT(v->object->metaObject());
2055 // We want to raw metaObject here as the raw metaobject is the
2056 // actual property type before we applied any extensions that might
2057 // effect the properties on the type, but don't effect assignability
2058 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2060 // Will be true if the assgned type inherits propertyMetaObject
2061 bool isAssignable = false;
2062 // Determine isAssignable value
2063 if (propertyMetaObject) {
2064 const QMetaObject *c = v->object->metatype;
2066 isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject));
2067 c = c->superClass();
2072 // Simple assignment
2073 COMPILE_CHECK(buildObject(v->object, ctxt));
2075 v->type = Value::CreatedObject;
2076 } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) {
2077 // Automatic "Component" insertion
2078 QDeclarativeParser::Object *root = v->object;
2079 QDeclarativeParser::Object *component = new QDeclarativeParser::Object;
2080 component->type = componentTypeRef();
2081 component->typeName = "Qt/Component";
2082 component->metatype = &QDeclarativeComponent::staticMetaObject;
2083 component->location = root->location;
2084 QDeclarativeParser::Value *componentValue = new QDeclarativeParser::Value;
2085 componentValue->object = root;
2086 component->getDefaultProperty()->addValue(componentValue);
2087 v->object = component;
2088 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2090 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2097 // Compile assigning a single object instance to a regular property using the "on" syntax.
2101 // NumberAnimation on x { }
2103 bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeParser::Property *prop,
2104 QDeclarativeParser::Object *obj,
2105 QDeclarativeParser::Object *baseObj,
2106 QDeclarativeParser::Value *v,
2107 const BindingContext &ctxt)
2109 Q_ASSERT(prop->index != -1);
2110 Q_ASSERT(v->object->type != -1);
2112 if (!obj->metaObject()->property(prop->index).isWritable())
2113 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2116 // Normally buildObject() will set this up, but we need the static
2117 // meta object earlier to test for assignability. It doesn't matter
2118 // that there may still be outstanding synthesized meta object changes
2119 // on this type, as they are not relevant for assignability testing
2120 v->object->metatype = output->types.at(v->object->type).metaObject();
2121 Q_ASSERT(v->object->metaObject());
2123 // Will be true if the assigned type inherits QDeclarativePropertyValueSource
2124 bool isPropertyValue = false;
2125 // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor
2126 bool isPropertyInterceptor = false;
2127 if (QDeclarativeType *valueType = toQmlType(v->object)) {
2128 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2129 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2132 if (isPropertyValue || isPropertyInterceptor) {
2133 // Assign as a property value source
2134 COMPILE_CHECK(buildObject(v->object, ctxt));
2136 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2137 buildDynamicMeta(baseObj, ForceCreation);
2138 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2140 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(QString::fromUtf8(v->object->typeName)).arg(QString::fromUtf8(prop->name.constData())));
2146 // Compile assigning a literal or binding to a regular property
2147 bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeParser::Property *prop,
2148 QDeclarativeParser::Object *obj,
2149 QDeclarativeParser::Value *v,
2150 const BindingContext &ctxt)
2152 Q_ASSERT(prop->index != -1);
2154 if (v->value.isScript()) {
2156 //optimization for <Type>.<EnumValue> enum assignments
2157 bool isEnumAssignment = false;
2158 COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj, v, &isEnumAssignment));
2159 if (isEnumAssignment) {
2160 v->type = Value::Literal;
2164 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2166 v->type = Value::PropertyBinding;
2170 COMPILE_CHECK(testLiteralAssignment(obj->metaObject()->property(prop->index), v));
2172 v->type = Value::Literal;
2178 bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop,
2179 QDeclarativeParser::Object *obj,
2180 QDeclarativeParser::Value *v,
2183 *isAssignment = false;
2184 if (!prop.isEnumType())
2187 if (!prop.isWritable())
2188 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
2190 QString string = v->value.asString();
2191 if (!string.at(0).isUpper())
2194 QStringList parts = string.split(QLatin1Char('.'));
2195 if (parts.count() != 2)
2198 QString typeName = parts.at(0);
2199 QDeclarativeType *type = 0;
2200 unit->imports().resolveType(typeName.toUtf8(), &type, 0, 0, 0, 0);
2202 //handle enums on value types (where obj->typeName is empty)
2203 QByteArray objTypeName = obj->typeName;
2204 if (objTypeName.isEmpty()) {
2205 QDeclarativeType *objType = toQmlType(obj);
2207 objTypeName = objType->qmlTypeName();
2213 QString enumValue = parts.at(1);
2216 if (objTypeName == type->qmlTypeName()) {
2217 // When these two match, we can short cut the search
2218 if (prop.isFlagType()) {
2219 value = prop.enumerator().keysToValue(enumValue.toUtf8().constData());
2221 value = prop.enumerator().keyToValue(enumValue.toUtf8().constData());
2224 // Otherwise we have to search the whole type
2225 // This matches the logic in QDeclarativeTypeNameScriptClass
2226 QByteArray enumName = enumValue.toUtf8();
2227 const QMetaObject *metaObject = type->baseMetaObject();
2228 for (int ii = metaObject->enumeratorCount() - 1; value == -1 && ii >= 0; --ii) {
2229 QMetaEnum e = metaObject->enumerator(ii);
2230 value = e.keyToValue(enumName.constData());
2237 v->type = Value::Literal;
2238 v->value = QDeclarativeParser::Variant((double)value);
2239 *isAssignment = true;
2244 // Similar logic to above, but not knowing target property.
2245 int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const
2247 int dot = script.indexOf('.');
2249 QDeclarativeType *type = 0;
2250 unit->imports().resolveType(script.left(dot), &type, 0, 0, 0, 0);
2253 const QMetaObject *mo = type->metaObject();
2254 const char *key = script.constData() + dot+1;
2255 int i = mo->enumeratorCount();
2257 int v = mo->enumerator(i).keyToValue(key);
2265 const QMetaObject *QDeclarativeCompiler::resolveType(const QByteArray& name) const
2267 QDeclarativeType *qmltype = 0;
2268 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2272 return qmltype->metaObject();
2275 // similar to logic of completeComponentBuild, but also sticks data
2276 // into datas at the end
2277 int QDeclarativeCompiler::rewriteBinding(const QString& expression, const QByteArray& name)
2279 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2280 rewriteBinding.setName('$' + name.mid(name.lastIndexOf('.') + 1));
2281 bool isSharable = false;
2282 QString rewrite = rewriteBinding(expression, 0, &isSharable);
2284 quint32 length = rewrite.length();
2288 pc = output->cachedClosures.count();
2290 output->cachedClosures.append(0);
2292 pc = output->cachedPrograms.length();
2293 output->cachedPrograms.append(0);
2296 QByteArray compiledData =
2297 QByteArray((const char *)&pc, sizeof(quint32)) +
2298 QByteArray((const char *)&length, sizeof(quint32)) +
2299 QByteArray((const char *)rewrite.constData(),
2300 rewrite.length() * sizeof(QChar));
2302 return output->indexForByteArray(compiledData);
2305 // Ensures that the dynamic meta specification on obj is valid
2306 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj)
2308 QSet<QByteArray> propNames;
2309 QSet<QByteArray> methodNames;
2310 bool seenDefaultProperty = false;
2313 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2314 const QDeclarativeParser::Object::DynamicProperty &prop =
2315 obj->dynamicProperties.at(ii);
2317 if (prop.isDefaultProperty) {
2318 if (seenDefaultProperty)
2319 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2320 seenDefaultProperty = true;
2323 if (propNames.contains(prop.name))
2324 COMPILE_EXCEPTION(&prop, tr("Duplicate property name"));
2326 QString propName = QString::fromUtf8(prop.name);
2327 if (propName.at(0).isUpper())
2328 COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
2330 if (enginePrivate->globalClass->illegalNames().contains(propName))
2331 COMPILE_EXCEPTION(&prop, tr("Illegal property name"));
2333 propNames.insert(prop.name);
2336 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2337 QByteArray name = obj->dynamicSignals.at(ii).name;
2338 if (methodNames.contains(name))
2339 COMPILE_EXCEPTION(obj, tr("Duplicate signal name"));
2340 QString nameStr = QString::fromUtf8(name);
2341 if (nameStr.at(0).isUpper())
2342 COMPILE_EXCEPTION(obj, tr("Signal names cannot begin with an upper case letter"));
2343 if (enginePrivate->globalClass->illegalNames().contains(nameStr))
2344 COMPILE_EXCEPTION(obj, tr("Illegal signal name"));
2345 methodNames.insert(name);
2347 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2348 QByteArray name = obj->dynamicSlots.at(ii).name;
2349 if (methodNames.contains(name))
2350 COMPILE_EXCEPTION(obj, tr("Duplicate method name"));
2351 QString nameStr = QString::fromUtf8(name);
2352 if (nameStr.at(0).isUpper())
2353 COMPILE_EXCEPTION(obj, tr("Method names cannot begin with an upper case letter"));
2354 if (enginePrivate->globalClass->illegalNames().contains(nameStr))
2355 COMPILE_EXCEPTION(obj, tr("Illegal method name"));
2356 methodNames.insert(name);
2362 bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeParser::Object *obj)
2364 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2365 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2367 if (!p.defaultValue || p.type == Object::DynamicProperty::Alias)
2370 Property *property = 0;
2371 if (p.isDefaultProperty) {
2372 property = obj->getDefaultProperty();
2374 property = obj->getProperty(p.name);
2375 if (!property->values.isEmpty())
2376 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2379 if (property->value)
2380 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2382 for (int ii = 0; ii < p.defaultValue->values.count(); ++ii) {
2383 QDeclarativeParser::Value *v = p.defaultValue->values.at(ii);
2385 property->values.append(v);
2391 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2393 bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, DynamicMetaMode mode)
2396 Q_ASSERT(obj->metatype);
2398 if (mode != ForceCreation &&
2399 obj->dynamicProperties.isEmpty() &&
2400 obj->dynamicSignals.isEmpty() &&
2401 obj->dynamicSlots.isEmpty())
2404 QByteArray dynamicData(sizeof(QDeclarativeVMEMetaData), (char)0);
2406 QByteArray newClassName = obj->metatype->className();
2407 newClassName.append("_QML_");
2408 int idx = classIndexCounter()->fetchAndAddRelaxed(1);
2409 newClassName.append(QByteArray::number(idx));
2410 if (compileState.root == obj && !compileState.nested) {
2411 QString path = output->url.path();
2412 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2413 if (lastSlash > -1) {
2414 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2415 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2416 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(idx);
2420 QMetaObjectBuilder builder;
2421 builder.setClassName(newClassName);
2422 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
2424 bool hasAlias = false;
2425 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2426 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2428 int propIdx = obj->metaObject()->indexOfProperty(p.name.constData());
2429 if (-1 != propIdx) {
2430 QMetaProperty prop = obj->metaObject()->property(propIdx);
2432 COMPILE_EXCEPTION(&p, tr("Cannot override FINAL property"));
2435 if (p.isDefaultProperty &&
2436 (p.type != Object::DynamicProperty::Alias ||
2437 mode == ResolveAliases))
2438 builder.addClassInfo("DefaultProperty", p.name);
2441 int propertyType = 0;
2442 bool readonly = false;
2444 case Object::DynamicProperty::Alias:
2448 case Object::DynamicProperty::CustomList:
2449 case Object::DynamicProperty::Custom:
2451 QByteArray customTypeName;
2452 QDeclarativeType *qmltype = 0;
2454 if (!unit->imports().resolveType(p.customType, &qmltype, &url, 0, 0, 0))
2455 COMPILE_EXCEPTION(&p, tr("Invalid property type"));
2458 QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(url);
2460 Q_ASSERT(tdata->isComplete());
2462 QDeclarativeCompiledData *data = tdata->compiledData();
2463 customTypeName = data->root->className();
2467 customTypeName = qmltype->typeName();
2470 if (p.type == Object::DynamicProperty::Custom) {
2471 type = customTypeName + '*';
2472 propertyType = QMetaType::QObjectStar;
2475 type = "QDeclarativeListProperty<";
2476 type.append(customTypeName);
2478 propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
2482 case Object::DynamicProperty::Variant:
2486 case Object::DynamicProperty::Int:
2487 propertyType = QVariant::Int;
2490 case Object::DynamicProperty::Bool:
2491 propertyType = QVariant::Bool;
2494 case Object::DynamicProperty::Real:
2495 propertyType = QVariant::Double;
2498 case Object::DynamicProperty::String:
2499 propertyType = QVariant::String;
2502 case Object::DynamicProperty::Url:
2503 propertyType = QVariant::Url;
2506 case Object::DynamicProperty::Color:
2507 propertyType = QVariant::Color;
2510 case Object::DynamicProperty::Time:
2511 propertyType = QVariant::Time;
2514 case Object::DynamicProperty::Date:
2515 propertyType = QVariant::Date;
2518 case Object::DynamicProperty::DateTime:
2519 propertyType = QVariant::DateTime;
2524 ((QDeclarativeVMEMetaData *)dynamicData.data())->propertyCount++;
2525 QDeclarativeVMEMetaData::PropertyData propertyData = { propertyType };
2526 dynamicData.append((char *)&propertyData, sizeof(propertyData));
2528 builder.addSignal(p.name + "Changed()");
2529 QMetaPropertyBuilder propBuilder =
2530 builder.addProperty(p.name, type, builder.methodCount() - 1);
2531 propBuilder.setWritable(!readonly);
2534 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2535 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2537 if (p.type == Object::DynamicProperty::Alias) {
2538 if (mode == ResolveAliases) {
2539 ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++;
2540 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, p));
2542 // Need a fake signal so that the metaobject remains consistent across
2543 // the resolve and non-resolve alias runs
2544 builder.addSignal(p.name + "Changed()");
2549 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2550 const Object::DynamicSignal &s = obj->dynamicSignals.at(ii);
2551 QByteArray sig(s.name + '(');
2552 for (int jj = 0; jj < s.parameterTypes.count(); ++jj) {
2553 if (jj) sig.append(',');
2554 sig.append(s.parameterTypes.at(jj));
2557 QMetaMethodBuilder b = builder.addSignal(sig);
2558 b.setParameterNames(s.parameterNames);
2559 ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++;
2562 QStringList funcScripts;
2564 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2565 Object::DynamicSlot &s = obj->dynamicSlots[ii];
2566 QByteArray sig(s.name + '(');
2567 QString funcScript(QLatin1String("(function ") + s.name + QLatin1Char('('));
2569 for (int jj = 0; jj < s.parameterNames.count(); ++jj) {
2572 funcScript.append(QLatin1Char(','));
2574 funcScript.append(QLatin1String(s.parameterNames.at(jj)));
2575 sig.append("QVariant");
2578 funcScript.append(QLatin1Char(')'));
2579 funcScript.append(s.body);
2580 funcScript.append(QLatin1Char(')'));
2581 funcScripts << funcScript;
2583 QMetaMethodBuilder b = builder.addSlot(sig);
2584 b.setReturnType("QVariant");
2585 b.setParameterNames(s.parameterNames);
2587 ((QDeclarativeVMEMetaData *)dynamicData.data())->methodCount++;
2588 QDeclarativeVMEMetaData::MethodData methodData =
2589 { s.parameterNames.count(), 0, funcScript.length(), s.location.start.line };
2591 dynamicData.append((char *)&methodData, sizeof(methodData));
2594 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2595 const QString &funcScript = funcScripts.at(ii);
2596 QDeclarativeVMEMetaData::MethodData *data =
2597 ((QDeclarativeVMEMetaData *)dynamicData.data())->methodData() + ii;
2599 data->bodyOffset = dynamicData.size();
2601 dynamicData.append((const char *)funcScript.constData(),
2602 (funcScript.length() * sizeof(QChar)));
2605 obj->metadata = builder.toRelocatableData();
2606 builder.fromRelocatableData(&obj->extObject, obj->metatype, obj->metadata);
2608 if (mode == IgnoreAliases && hasAlias)
2609 compileState.aliasingObjects << obj;
2611 obj->synthdata = dynamicData;
2613 if (obj->synthCache) {
2614 obj->synthCache->release();
2615 obj->synthCache = 0;
2618 if (obj->type != -1) {
2619 QDeclarativePropertyCache *cache = output->types[obj->type].createPropertyCache(engine)->copy();
2620 cache->append(engine, &obj->extObject, QDeclarativePropertyCache::Data::NoFlags,
2621 QDeclarativePropertyCache::Data::IsVMEFunction,
2622 QDeclarativePropertyCache::Data::IsVMESignal);
2623 obj->synthCache = cache;
2629 bool QDeclarativeCompiler::checkValidId(QDeclarativeParser::Value *v, const QString &val)
2632 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
2634 if (val.at(0).isLetter() && !val.at(0).isLower())
2635 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
2637 QChar u(QLatin1Char('_'));
2638 for (int ii = 0; ii < val.count(); ++ii) {
2640 if (ii == 0 && !val.at(ii).isLetter() && val.at(ii) != u) {
2641 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
2642 } else if (ii != 0 && !val.at(ii).isLetterOrNumber() && val.at(ii) != u) {
2643 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
2648 if (enginePrivate->globalClass->illegalNames().contains(val))
2649 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
2654 #include <qdeclarativejsparser_p.h>
2656 static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node)
2658 if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) {
2660 static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name->asString();
2661 return QStringList() << name;
2662 } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) {
2663 QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node);
2665 QStringList rv = astNodeToStringList(expr->base);
2668 rv.append(expr->name->asString());
2671 return QStringList();
2674 bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder,
2676 QDeclarativeParser::Object *obj,
2677 const Object::DynamicProperty &prop)
2679 if (!prop.defaultValue)
2680 COMPILE_EXCEPTION(obj, tr("No property alias location"));
2682 if (prop.defaultValue->values.count() != 1 ||
2683 prop.defaultValue->values.at(0)->object ||
2684 !prop.defaultValue->values.at(0)->value.isScript())
2685 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2687 QDeclarativeJS::AST::Node *node = prop.defaultValue->values.at(0)->value.asAST();
2689 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
2691 QStringList alias = astNodeToStringList(node);
2693 if (alias.count() < 1 || alias.count() > 3)
2694 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
2696 if (!compileState.ids.contains(alias.at(0)))
2697 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
2699 QDeclarativeParser::Object *idObject = compileState.ids[alias.at(0)];
2701 QByteArray typeName;
2705 bool writable = false;
2706 if (alias.count() == 2 || alias.count() == 3) {
2707 propIdx = indexOfProperty(idObject, alias.at(1).toUtf8());
2709 if (-1 == propIdx) {
2710 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2711 } else if (propIdx > 0xFFFF) {
2712 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
2715 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
2716 if (!aliasProperty.isScriptable())
2717 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2719 writable = aliasProperty.isWritable();
2721 if (alias.count() == 3) {
2722 QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
2724 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2726 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
2728 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
2729 if (valueTypeIndex == -1)
2730 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2731 Q_ASSERT(valueTypeIndex <= 0xFF);
2733 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
2734 propIdx |= (valueTypeIndex << 16);
2737 if (aliasProperty.isEnumType())
2738 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
2740 typeName = aliasProperty.typeName();
2742 typeName = idObject->metaObject()->className();
2744 //use the base type since it has been registered with metatype system
2745 int index = typeName.indexOf("_QML_");
2747 typeName = typeName.left(index);
2749 index = typeName.indexOf("_QMLTYPE_");
2750 const QMetaObject *mo = idObject->metaObject();
2751 while (index != -1 && mo) {
2752 typeName = mo->superClass()->className();
2753 index = typeName.indexOf("_QMLTYPE_");
2754 mo = mo->superClass();
2761 if (typeName.endsWith('*'))
2762 flags |= QML_ALIAS_FLAG_PTR;
2764 data.append((const char *)&idObject->idIndex, sizeof(idObject->idIndex));
2765 data.append((const char *)&propIdx, sizeof(propIdx));
2766 data.append((const char *)&flags, sizeof(flags));
2768 builder.addSignal(prop.name + "Changed()");
2769 QMetaPropertyBuilder propBuilder =
2770 builder.addProperty(prop.name, typeName.constData(), builder.methodCount() - 1);
2771 propBuilder.setWritable(writable);
2775 bool QDeclarativeCompiler::buildBinding(QDeclarativeParser::Value *value,
2776 QDeclarativeParser::Property *prop,
2777 const BindingContext &ctxt)
2779 Q_ASSERT(prop->index != -1);
2780 Q_ASSERT(prop->parent);
2781 Q_ASSERT(prop->parent->metaObject());
2783 QMetaProperty mp = prop->parent->metaObject()->property(prop->index);
2784 if (!mp.isWritable() && !QDeclarativeMetaType::isList(prop->type))
2785 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2787 BindingReference reference;
2788 reference.expression = value->value;
2789 reference.property = prop;
2790 reference.value = value;
2791 reference.bindingContext = ctxt;
2792 addBindingReference(reference);
2797 void QDeclarativeCompiler::genBindingAssignment(QDeclarativeParser::Value *binding,
2798 QDeclarativeParser::Property *prop,
2799 QDeclarativeParser::Object *obj,
2800 QDeclarativeParser::Property *valueTypeProperty)
2803 Q_ASSERT(compileState.bindings.contains(binding));
2805 const BindingReference &ref = compileState.bindings.value(binding);
2806 if (ref.dataType == BindingReference::Experimental) {
2807 QDeclarativeInstruction store;
2808 store.type = QDeclarativeInstruction::StoreCompiledBinding;
2809 store.assignBinding.value = ref.compiledIndex;
2810 store.assignBinding.context = ref.bindingContext.stack;
2811 store.assignBinding.owner = ref.bindingContext.owner;
2812 if (valueTypeProperty)
2813 store.assignBinding.property = (valueTypeProperty->index & 0xFFFF) |
2814 ((valueTypeProperty->type & 0xFF)) << 16 |
2815 ((prop->index & 0xFF) << 24);
2817 store.assignBinding.property = prop->index;
2818 store.assignBinding.line = binding->location.start.line;
2819 output->bytecode << store;
2823 QDeclarativeInstruction store;
2825 store.type = QDeclarativeInstruction::StoreBinding;
2827 store.type = QDeclarativeInstruction::StoreBindingOnAlias;
2828 store.assignBinding.value = output->indexForByteArray(ref.compiledData);
2829 store.assignBinding.context = ref.bindingContext.stack;
2830 store.assignBinding.owner = ref.bindingContext.owner;
2831 store.assignBinding.line = binding->location.start.line;
2833 Q_ASSERT(ref.bindingContext.owner == 0 ||
2834 (ref.bindingContext.owner != 0 && valueTypeProperty));
2835 if (ref.bindingContext.owner) {
2836 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
2838 store.assignBinding.property = genPropertyData(prop);
2841 output->bytecode << store;
2844 int QDeclarativeCompiler::genContextCache()
2846 if (compileState.ids.count() == 0)
2849 QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache(engine);
2851 for (QHash<QString, QDeclarativeParser::Object *>::ConstIterator iter = compileState.ids.begin();
2852 iter != compileState.ids.end();
2854 cache->add(iter.key(), (*iter)->idIndex);
2856 output->contextCaches.append(cache);
2857 return output->contextCaches.count() - 1;
2860 int QDeclarativeCompiler::genValueTypeData(QDeclarativeParser::Property *valueTypeProp,
2861 QDeclarativeParser::Property *prop)
2864 QDeclarativePropertyPrivate::saveValueType(prop->parent->metaObject(), prop->index,
2865 enginePrivate->valueTypes[prop->type]->metaObject(),
2866 valueTypeProp->index);
2867 // valueTypeProp->index, valueTypeProp->type);
2869 return output->indexForByteArray(data);
2872 int QDeclarativeCompiler::genPropertyData(QDeclarativeParser::Property *prop)
2874 return output->indexForByteArray(QDeclarativePropertyPrivate::saveProperty(prop->parent->metaObject(), prop->index));
2877 bool QDeclarativeCompiler::completeComponentBuild()
2879 componentStat.ids = compileState.ids.count();
2881 for (int ii = 0; ii < compileState.aliasingObjects.count(); ++ii) {
2882 QDeclarativeParser::Object *aliasObject = compileState.aliasingObjects.at(ii);
2883 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
2886 QDeclarativeV4Compiler::Expression expr;
2887 expr.component = compileState.root;
2888 expr.ids = compileState.ids;
2889 expr.importCache = output->importCache;
2890 expr.imports = unit->imports();
2892 QDeclarativeV4Compiler bindingCompiler;
2894 for (QHash<QDeclarativeParser::Value*,BindingReference>::Iterator iter = compileState.bindings.begin();
2895 iter != compileState.bindings.end(); ++iter) {
2897 BindingReference &binding = *iter;
2899 // ### We don't currently optimize for bindings on alias's - because
2900 // of the solution to QTBUG-13719
2901 if (!binding.property->isAlias) {
2902 expr.context = binding.bindingContext.object;
2903 expr.property = binding.property;
2904 expr.expression = binding.expression;
2906 int index = bindingCompiler.compile(expr, enginePrivate);
2908 binding.dataType = BindingReference::Experimental;
2909 binding.compiledIndex = index;
2910 componentStat.optimizedBindings.append(iter.key()->location);
2915 binding.dataType = BindingReference::QtScript;
2917 // Pre-rewrite the expression
2918 QString expression = binding.expression.asScript();
2920 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2921 rewriteBinding.setName('$'+binding.property->name);
2922 bool isSharable = false;
2923 expression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
2925 quint32 length = expression.length();
2929 pc = output->cachedClosures.count();
2931 output->cachedClosures.append(0);
2933 pc = output->cachedPrograms.length();
2934 output->cachedPrograms.append(0);
2937 binding.compiledData =
2938 QByteArray((const char *)&pc, sizeof(quint32)) +
2939 QByteArray((const char *)&length, sizeof(quint32)) +
2940 QByteArray((const char *)expression.constData(),
2941 expression.length() * sizeof(QChar));
2943 componentStat.scriptBindings.append(iter.key()->location);
2946 if (bindingCompiler.isValid())
2947 compileState.compiledBindingData = bindingCompiler.program();
2949 saveComponentState();
2954 void QDeclarativeCompiler::dumpStats()
2956 qWarning().nospace() << "QML Document: " << output->url.toString();
2957 for (int ii = 0; ii < savedComponentStats.count(); ++ii) {
2958 const ComponentStat &stat = savedComponentStats.at(ii);
2959 qWarning().nospace() << " Component Line " << stat.lineNumber;
2960 qWarning().nospace() << " Total Objects: " << stat.objects;
2961 qWarning().nospace() << " IDs Used: " << stat.ids;
2962 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
2966 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
2967 if (0 == (ii % 10)) {
2968 if (ii) output.append("\n");
2973 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
2975 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
2976 output.append(") ");
2978 if (!output.isEmpty())
2979 qWarning().nospace() << output.constData();
2982 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
2985 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
2986 if (0 == (ii % 10)) {
2987 if (ii) output.append("\n");
2992 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
2994 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
2995 output.append(") ");
2997 if (!output.isEmpty())
2998 qWarning().nospace() << output.constData();
3004 Returns true if from can be assigned to a (QObject) property of type
3007 bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeParser::Object *from)
3009 const QMetaObject *toMo =
3010 enginePrivate->rawMetaObjectForType(to);
3011 const QMetaObject *fromMo = from->metaObject();
3014 if (QDeclarativePropertyPrivate::equal(fromMo, toMo))
3016 fromMo = fromMo->superClass();
3021 QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeParser::Object *from)
3024 const QMetaObject *mo = from->metatype;
3025 QDeclarativeType *type = 0;
3026 while (!type && mo) {
3027 type = QDeclarativeMetaType::qmlType(mo);
3028 mo = mo->superClass();
3033 QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeParser::Object *obj)
3035 const QMetaObject *mo = obj->metatype;
3037 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3039 return QStringList();
3041 QMetaClassInfo classInfo = mo->classInfo(idx);
3042 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3046 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3047 int QDeclarativeCompiler::indexOfSignal(QDeclarativeParser::Object *object, const QByteArray &name,
3048 bool *notInRevision)
3050 if (notInRevision) *notInRevision = false;
3052 if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) {
3054 QString strName(QString::fromUtf8(name));
3055 QDeclarativePropertyCache *cache =
3056 object->synthCache?object->synthCache:output->types.at(object->type).propertyCache();
3058 QDeclarativePropertyCache::Data *d = cache->property(strName);
3059 if (notInRevision) *notInRevision = false;
3061 while (d && !(d->flags & QDeclarativePropertyCache::Data::IsFunction))
3062 d = cache->overrideData(d);
3064 if (d && !cache->isAllowedInRevision(d)) {
3065 if (notInRevision) *notInRevision = true;
3068 return d->coreIndex;
3071 if (name.endsWith("Changed")) {
3072 QByteArray propName = name.mid(0, name.length() - 7);
3074 int propIndex = indexOfProperty(object, propName, notInRevision);
3075 if (propIndex != -1) {
3076 d = cache->property(propIndex);
3077 return d->notifyIndex;
3083 return QDeclarativePropertyPrivate::findSignalByName(object->metaObject(), name).methodIndex();
3088 int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QByteArray &name,
3089 bool *notInRevision)
3091 if (notInRevision) *notInRevision = false;
3093 if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) {
3095 QString strName(QString::fromUtf8(name));
3096 QDeclarativePropertyCache *cache =
3097 object->synthCache?object->synthCache:output->types.at(object->type).propertyCache();
3099 QDeclarativePropertyCache::Data *d = cache->property(strName);
3100 // Find the first property
3101 while (d && d->flags & QDeclarativePropertyCache::Data::IsFunction)
3102 d = cache->overrideData(d);
3104 if (d && !cache->isAllowedInRevision(d)) {
3105 if (notInRevision) *notInRevision = true;
3108 return d?d->coreIndex:-1;
3111 const QMetaObject *mo = object->metaObject();
3112 return mo->indexOfProperty(name.constData());