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.setType(QDeclarativeInstruction::StoreInteger);
340 instr.storeInteger.propertyIndex = prop.propertyIndex();
341 instr.storeInteger.value = value;
342 output->addInstruction(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.setType(QDeclarativeInstruction::StoreVariantInteger);
356 instr.storeInteger.propertyIndex = prop.propertyIndex();
357 instr.storeInteger.value = int(n);
359 instr.setType(QDeclarativeInstruction::StoreVariantDouble);
360 instr.storeDouble.propertyIndex = prop.propertyIndex();
361 instr.storeDouble.value = n;
363 } else if(v->value.isBoolean()) {
364 instr.setType(QDeclarativeInstruction::StoreVariantBool);
365 instr.storeBool.propertyIndex = prop.propertyIndex();
366 instr.storeBool.value = v->value.asBoolean();
368 instr.setType(QDeclarativeInstruction::StoreVariant);
369 instr.storeString.propertyIndex = prop.propertyIndex();
370 instr.storeString.value = output->indexForString(string);
374 case QVariant::String:
376 instr.setType(QDeclarativeInstruction::StoreString);
377 instr.storeString.propertyIndex = prop.propertyIndex();
378 instr.storeString.value = output->indexForString(string);
381 case QVariant::ByteArray:
383 instr.setType(QDeclarativeInstruction::StoreByteArray);
384 instr.storeByteArray.propertyIndex = prop.propertyIndex();
385 instr.storeByteArray.value = output->indexForByteArray(string.toLatin1());
390 instr.setType(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.setType(QDeclarativeInstruction::StoreInteger);
399 instr.storeInteger.propertyIndex = prop.propertyIndex();
400 instr.storeInteger.value = uint(v->value.asNumber());
405 instr.setType(QDeclarativeInstruction::StoreInteger);
406 instr.storeInteger.propertyIndex = prop.propertyIndex();
407 instr.storeInteger.value = int(v->value.asNumber());
410 case QMetaType::Float:
412 instr.setType(QDeclarativeInstruction::StoreFloat);
413 instr.storeFloat.propertyIndex = prop.propertyIndex();
414 instr.storeFloat.value = float(v->value.asNumber());
417 case QVariant::Double:
419 instr.setType(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.setType(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.setType(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.setType(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.setType(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.setType(QDeclarativeInstruction::StorePointF);
478 instr.setType(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.setType(QDeclarativeInstruction::StoreSizeF);
493 instr.setType(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.setType(QDeclarativeInstruction::StoreRectF);
509 instr.setType(QDeclarativeInstruction::StoreRect);
510 instr.storeRect.propertyIndex = prop.propertyIndex();
511 instr.storeRect.valueIndex = index;
516 bool b = v->value.asBoolean();
517 instr.setType(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.setType(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.setType(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->addInstruction(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.setType(QDeclarativeInstruction::StoreImportedScript);
668 import.storeScript.value = output->scripts.count();
670 QDeclarativeScriptData *scriptData = script.script->scriptData();
671 scriptData->addref();
672 output->scripts << scriptData;
673 output->addInstruction(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.setType(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->addInstruction(init);
700 QDeclarativeInstruction def;
701 def.setType(QDeclarativeInstruction::SetDefault);
702 output->addInstruction(def);
704 QDeclarativeInstruction done;
705 done.setType(QDeclarativeInstruction::Done);
706 output->addInstruction(done);
708 Q_ASSERT(tree->metatype);
710 if (tree->metadata.isEmpty()) {
711 output->root = tree->metatype;
713 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
714 output->root = &output->rootData;
716 if (!tree->metadata.isEmpty())
717 enginePrivate->registerCompositeType(output);
720 static bool ValuePtrLessThan(const QDeclarativeParser::Value *t1, const QDeclarativeParser::Value *t2)
722 return t1->location.start.line < t2->location.start.line ||
723 (t1->location.start.line == t2->location.start.line &&
724 t1->location.start.column < t2->location.start.column);
727 bool QDeclarativeCompiler::buildObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
729 componentStat.objects++;
731 Q_ASSERT (obj->type != -1);
732 const QDeclarativeCompiledData::TypeReference &tr =
733 output->types.at(obj->type);
734 obj->metatype = tr.metaObject();
737 obj->url = tr.component->url;
739 obj->typeName = tr.type->qmlTypeName();
740 obj->className = tr.className;
742 // This object is a "Component" element
743 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
744 COMPILE_CHECK(buildComponent(obj, ctxt));
748 // Object instantiations reset the binding context
749 BindingContext objCtxt(obj);
751 // Create the synthesized meta object, ignoring aliases
752 COMPILE_CHECK(checkDynamicMeta(obj));
753 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
754 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
756 // Find the native type and check for the QDeclarativeParserStatus interface
757 QDeclarativeType *type = toQmlType(obj);
759 obj->parserStatusCast = type->parserStatusCast();
760 if (obj->parserStatusCast != -1)
761 compileState.parserStatusCount++;
763 // Check if this is a custom parser type. Custom parser types allow
764 // assignments to non-existent properties. These assignments are then
765 // compiled by the type.
766 bool isCustomParser = output->types.at(obj->type).type &&
767 output->types.at(obj->type).type->customParser() != 0;
768 QList<QDeclarativeCustomParserProperty> customProps;
770 // Fetch the list of deferred properties
771 QStringList deferredList = deferredProperties(obj);
773 // Must do id property first. This is to ensure that the id given to any
774 // id reference created matches the order in which the objects are
776 foreach(Property *prop, obj->properties) {
777 if (prop->name == "id") {
778 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
784 Property *defaultProperty = 0;
785 Property *skipProperty = 0;
786 if (obj->defaultProperty) {
787 const QMetaObject *metaObject = obj->metaObject();
788 Q_ASSERT(metaObject);
789 QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
791 Property *explicitProperty = obj->getProperty(p.name(), false);
792 if (explicitProperty && !explicitProperty->value) {
793 skipProperty = explicitProperty;
795 defaultProperty = new Property;
796 defaultProperty->parent = obj;
797 defaultProperty->isDefault = true;
798 defaultProperty->location = obj->defaultProperty->location;
799 defaultProperty->listValueRange = obj->defaultProperty->listValueRange;
800 defaultProperty->listCommaPositions = obj->defaultProperty->listCommaPositions;
802 defaultProperty->values = obj->defaultProperty->values;
803 defaultProperty->values += explicitProperty->values;
804 foreach(QDeclarativeParser::Value *value, defaultProperty->values)
806 qSort(defaultProperty->values.begin(), defaultProperty->values.end(), ValuePtrLessThan);
809 defaultProperty = obj->defaultProperty;
810 defaultProperty->addref();
813 defaultProperty = obj->defaultProperty;
814 defaultProperty->addref();
818 QDeclarativeCustomParser *cp = 0;
820 cp = output->types.at(obj->type).type->customParser();
822 // Build all explicit properties specified
823 foreach(Property *prop, obj->properties) {
825 if (prop == skipProperty)
827 if (prop->name == "id")
830 bool canDefer = false;
831 if (isCustomParser) {
832 if (doesPropertyExist(prop, obj) &&
833 (!(cp->flags() & QDeclarativeCustomParser::AcceptsAttachedProperties) ||
834 !isAttachedPropertyName(prop->name))) {
835 int ids = compileState.ids.count();
836 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
837 canDefer = ids == compileState.ids.count();
839 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
842 if (isSignalPropertyName(prop->name)) {
843 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
845 int ids = compileState.ids.count();
846 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
847 canDefer = ids == compileState.ids.count();
851 if (canDefer && !deferredList.isEmpty() &&
852 deferredList.contains(QString::fromUtf8(prop->name)))
853 prop->isDeferred = true;
857 // Build the default property
858 if (defaultProperty) {
859 Property *prop = defaultProperty;
861 bool canDefer = false;
862 if (isCustomParser) {
863 if (doesPropertyExist(prop, obj)) {
864 int ids = compileState.ids.count();
865 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
866 canDefer = ids == compileState.ids.count();
868 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
871 int ids = compileState.ids.count();
872 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
873 canDefer = ids == compileState.ids.count();
876 if (canDefer && !deferredList.isEmpty() &&
877 deferredList.contains(QString::fromUtf8(prop->name)))
878 prop->isDeferred = true;
882 defaultProperty->release();
884 // Compile custom parser parts
885 if (isCustomParser && !customProps.isEmpty()) {
889 obj->custom = cp->compile(customProps);
892 foreach (QDeclarativeError err, cp->errors()) {
893 err.setUrl(output->url);
901 void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj)
903 QDeclarativeCompiledData::TypeReference &tr = output->types[obj->type];
904 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
910 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
911 !output->types.at(obj->type).type->isExtendedType() && obj != compileState.root) {
913 QDeclarativeInstruction create;
914 create.setType(QDeclarativeInstruction::CreateSimpleObject);
915 create.createSimple.create = output->types.at(obj->type).type->createFunction();
916 create.createSimple.typeSize = output->types.at(obj->type).type->createSize();
917 create.createSimple.type = obj->type;
918 create.createSimple.line = obj->location.start.line;
919 create.createSimple.column = obj->location.start.column;
920 output->addInstruction(create);
924 QDeclarativeInstruction create;
925 create.setType(QDeclarativeInstruction::CreateObject);
926 create.create.line = obj->location.start.line;
927 create.create.column = obj->location.start.column;
928 create.create.data = -1;
929 if (!obj->custom.isEmpty())
930 create.create.data = output->indexForByteArray(obj->custom);
931 create.create.type = obj->type;
932 if (!output->types.at(create.create.type).type &&
933 !obj->bindingBitmask.isEmpty()) {
934 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
935 create.create.bindingBits =
936 output->indexForByteArray(obj->bindingBitmask);
938 create.create.bindingBits = -1;
940 output->addInstruction(create);
944 // Setup the synthesized meta object if necessary
945 if (!obj->metadata.isEmpty()) {
946 QDeclarativeInstruction meta;
947 meta.setType(QDeclarativeInstruction::StoreMetaObject);
948 meta.storeMeta.data = output->indexForByteArray(obj->metadata);
949 meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata);
950 meta.storeMeta.propertyCache = output->propertyCaches.count();
952 QDeclarativePropertyCache *propertyCache = obj->synthCache;
953 Q_ASSERT(propertyCache);
954 propertyCache->addref();
956 // Add flag for alias properties
957 if (!obj->synthdata.isEmpty()) {
958 const QDeclarativeVMEMetaData *vmeMetaData =
959 reinterpret_cast<const QDeclarativeVMEMetaData *>(obj->synthdata.constData());
960 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
961 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
962 propertyCache->property(index)->flags |= QDeclarativePropertyCache::Data::IsAlias;
966 if (obj == unitRoot) {
967 propertyCache->addref();
968 output->rootPropertyCache = propertyCache;
971 output->propertyCaches << propertyCache;
972 output->addInstruction(meta);
973 } else if (obj == unitRoot) {
974 output->rootPropertyCache = tr.createPropertyCache(engine);
975 output->rootPropertyCache->addref();
979 if (!obj->id.isEmpty()) {
980 QDeclarativeInstruction id;
981 id.setType(QDeclarativeInstruction::SetId);
982 id.setId.value = output->indexForString(obj->id);
983 id.setId.index = obj->idIndex;
984 output->addInstruction(id);
988 if (tr.type && obj->parserStatusCast != -1) {
989 QDeclarativeInstruction begin;
990 begin.setType(QDeclarativeInstruction::BeginObject);
991 begin.begin.castValue = obj->parserStatusCast;
992 output->addInstruction(begin);
998 void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj)
1000 typedef QPair<Property *, int> PropPair;
1001 foreach(const PropPair &prop, obj->scriptStringProperties) {
1002 QDeclarativeInstruction ss;
1003 ss.setType(QDeclarativeInstruction::StoreScriptString);
1004 ss.storeScriptString.propertyIndex = prop.first->index;
1005 ss.storeScriptString.value =
1006 output->indexForString(prop.first->values.at(0)->value.asScript());
1007 ss.storeScriptString.scope = prop.second;
1008 output->addInstruction(ss);
1011 bool seenDefer = false;
1012 foreach(Property *prop, obj->valueProperties) {
1013 if (prop->isDeferred) {
1018 genValueProperty(prop, obj);
1021 QDeclarativeInstruction defer;
1022 defer.setType(QDeclarativeInstruction::Defer);
1023 defer.defer.deferCount = 0;
1024 int deferIdx = output->addInstruction(defer);
1025 int nextInstructionIndex = output->nextInstructionIndex();
1027 QDeclarativeInstruction init;
1028 init.setType(QDeclarativeInstruction::Init);
1029 init.init.bindingsSize = compileState.bindings.count(); // XXX - bigger than necessary
1030 init.init.parserStatusSize = compileState.parserStatusCount; // XXX - bigger than necessary
1031 init.init.contextCache = -1;
1032 init.init.compiledBinding = -1;
1033 output->addInstruction(init);
1035 foreach(Property *prop, obj->valueProperties) {
1036 if (!prop->isDeferred)
1038 genValueProperty(prop, obj);
1041 QDeclarativeInstruction done;
1042 done.setType(QDeclarativeInstruction::Done);
1043 output->addInstruction(done);
1045 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1048 foreach(Property *prop, obj->signalProperties) {
1050 QDeclarativeParser::Value *v = prop->values.at(0);
1052 if (v->type == Value::SignalObject) {
1054 genObject(v->object);
1056 QDeclarativeInstruction assign;
1057 assign.setType(QDeclarativeInstruction::AssignSignalObject);
1058 assign.assignSignalObject.line = v->location.start.line;
1059 assign.assignSignalObject.signal =
1060 output->indexForByteArray(prop->name);
1061 output->addInstruction(assign);
1063 } else if (v->type == Value::SignalExpression) {
1065 BindingContext ctxt = compileState.signalExpressions.value(v);
1067 QDeclarativeInstruction store;
1068 store.setType(QDeclarativeInstruction::StoreSignal);
1069 store.storeSignal.signalIndex = prop->index;
1070 store.storeSignal.value =
1071 output->indexForString(v->value.asScript().trimmed());
1072 store.storeSignal.context = ctxt.stack;
1073 store.storeSignal.name = output->indexForByteArray(prop->name);
1074 store.storeSignal.line = v->location.start.line;
1075 output->addInstruction(store);
1081 foreach(Property *prop, obj->attachedProperties) {
1082 QDeclarativeInstruction fetch;
1083 fetch.setType(QDeclarativeInstruction::FetchAttached);
1084 fetch.fetchAttached.id = prop->index;
1085 fetch.fetchAttached.line = prop->location.start.line;
1086 output->addInstruction(fetch);
1088 genObjectBody(prop->value);
1090 QDeclarativeInstruction pop;
1091 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1092 output->addInstruction(pop);
1095 foreach(Property *prop, obj->groupedProperties) {
1096 QDeclarativeInstruction fetch;
1097 fetch.setType(QDeclarativeInstruction::FetchObject);
1098 fetch.fetch.property = prop->index;
1099 fetch.fetch.line = prop->location.start.line;
1100 output->addInstruction(fetch);
1102 if (!prop->value->metadata.isEmpty()) {
1103 QDeclarativeInstruction meta;
1104 meta.setType(QDeclarativeInstruction::StoreMetaObject);
1105 meta.storeMeta.data = output->indexForByteArray(prop->value->metadata);
1106 meta.storeMeta.aliasData = output->indexForByteArray(prop->value->synthdata);
1107 meta.storeMeta.propertyCache = -1;
1108 output->addInstruction(meta);
1111 genObjectBody(prop->value);
1113 QDeclarativeInstruction pop;
1114 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1115 output->addInstruction(pop);
1118 foreach(Property *prop, obj->valueTypeProperties) {
1120 genValueTypeProperty(obj, prop);
1123 foreach(Property *prop, obj->valueProperties) {
1124 if (prop->isDeferred)
1127 genValueProperty(prop, obj);
1130 foreach(Property *prop, obj->valueTypeProperties) {
1132 genValueTypeProperty(obj, prop);
1136 void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeParser::Object *obj,QDeclarativeParser::Property *prop)
1138 QDeclarativeInstruction fetch;
1139 fetch.setType(QDeclarativeInstruction::FetchValueType);
1140 fetch.fetchValue.property = prop->index;
1141 fetch.fetchValue.type = prop->type;
1142 fetch.fetchValue.bindingSkipList = 0;
1144 if (obj->type == -1 || output->types.at(obj->type).component) {
1145 // We only have to do this if this is a composite type. If it is a builtin
1146 // type it can't possibly already have bindings that need to be cleared.
1147 foreach(Property *vprop, prop->value->valueProperties) {
1148 if (!vprop->values.isEmpty()) {
1149 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1150 fetch.fetchValue.bindingSkipList |= (1 << vprop->index);
1155 output->addInstruction(fetch);
1157 foreach(Property *vprop, prop->value->valueProperties) {
1158 genPropertyAssignment(vprop, prop->value, prop);
1161 QDeclarativeInstruction pop;
1162 pop.setType(QDeclarativeInstruction::PopValueType);
1163 pop.fetchValue.property = prop->index;
1164 pop.fetchValue.type = prop->type;
1165 pop.fetchValue.bindingSkipList = 0;
1166 output->addInstruction(pop);
1169 void QDeclarativeCompiler::genComponent(QDeclarativeParser::Object *obj)
1171 QDeclarativeParser::Object *root = obj->defaultProperty->values.at(0)->object;
1174 QDeclarativeInstruction create;
1175 create.setType(QDeclarativeInstruction::CreateComponent);
1176 create.createComponent.line = root->location.start.line;
1177 create.createComponent.column = root->location.start.column;
1178 create.createComponent.endLine = root->location.end.line;
1179 int createInstruction = output->addInstruction(create);
1180 int nextInstructionIndex = output->nextInstructionIndex();
1182 ComponentCompileState oldCompileState = compileState;
1183 compileState = componentState(root);
1185 QDeclarativeInstruction init;
1186 init.setType(QDeclarativeInstruction::Init);
1187 init.init.bindingsSize = compileState.bindings.count();
1188 init.init.parserStatusSize = compileState.parserStatusCount;
1189 init.init.contextCache = genContextCache();
1190 if (compileState.compiledBindingData.isEmpty())
1191 init.init.compiledBinding = -1;
1193 init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData);
1194 output->addInstruction(init);
1198 QDeclarativeInstruction def;
1199 def.setType(QDeclarativeInstruction::SetDefault);
1200 output->addInstruction(def);
1202 QDeclarativeInstruction done;
1203 done.setType(QDeclarativeInstruction::Done);
1204 output->addInstruction(done);
1206 output->instruction(createInstruction)->createComponent.count =
1207 output->nextInstructionIndex() - nextInstructionIndex;
1209 compileState = oldCompileState;
1211 if (!obj->id.isEmpty()) {
1212 QDeclarativeInstruction id;
1213 id.setType(QDeclarativeInstruction::SetId);
1214 id.setId.value = output->indexForString(obj->id);
1215 id.setId.index = obj->idIndex;
1216 output->addInstruction(id);
1220 bool QDeclarativeCompiler::buildComponent(QDeclarativeParser::Object *obj,
1221 const BindingContext &ctxt)
1223 // The special "Component" element can only have the id property and a
1224 // default property, that actually defines the component's tree
1226 // Find, check and set the "id" property (if any)
1227 Property *idProp = 0;
1228 if (obj->properties.count() > 1 ||
1229 (obj->properties.count() == 1 && obj->properties.begin().key() != "id"))
1230 COMPILE_EXCEPTION(*obj->properties.begin(), tr("Component elements may not contain properties other than id"));
1232 if (obj->properties.count())
1233 idProp = *obj->properties.begin();
1236 if (idProp->value || idProp->values.count() > 1 || idProp->values.at(0)->object)
1237 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1238 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1240 QString idVal = idProp->values.first()->primitive();
1242 if (compileState.ids.contains(idVal))
1243 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1249 // Check the Component tree is well formed
1250 if (obj->defaultProperty &&
1251 (obj->defaultProperty->value || obj->defaultProperty->values.count() > 1 ||
1252 (obj->defaultProperty->values.count() == 1 && !obj->defaultProperty->values.first()->object)))
1253 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1255 if (!obj->dynamicProperties.isEmpty())
1256 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1257 if (!obj->dynamicSignals.isEmpty())
1258 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1259 if (!obj->dynamicSlots.isEmpty())
1260 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1262 QDeclarativeParser::Object *root = 0;
1263 if (obj->defaultProperty && obj->defaultProperty->values.count())
1264 root = obj->defaultProperty->values.first()->object;
1267 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1269 // Build the component tree
1270 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1275 bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeParser::Object *obj,
1276 const BindingContext &ctxt)
1278 ComponentCompileState oldComponentCompileState = compileState;
1279 ComponentStat oldComponentStat = componentStat;
1281 compileState = ComponentCompileState();
1282 compileState.root = obj;
1283 compileState.nested = true;
1285 componentStat = ComponentStat();
1286 componentStat.lineNumber = obj->location.start.line;
1289 COMPILE_CHECK(buildObject(obj, ctxt));
1291 COMPILE_CHECK(completeComponentBuild());
1293 compileState = oldComponentCompileState;
1294 componentStat = oldComponentStat;
1300 // Build a sub-object. A sub-object is one that was not created directly by
1301 // QML - such as a grouped property object, or an attached object. Sub-object's
1302 // can't have an id, involve a custom parser, have attached properties etc.
1303 bool QDeclarativeCompiler::buildSubObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
1305 Q_ASSERT(obj->metatype);
1306 Q_ASSERT(!obj->defaultProperty);
1307 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1310 foreach(Property *prop, obj->properties) {
1311 if (isSignalPropertyName(prop->name)) {
1312 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1314 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1321 int QDeclarativeCompiler::componentTypeRef()
1323 QDeclarativeType *t = QDeclarativeMetaType::qmlType("QtQuick/Component",1,0);
1324 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1325 if (output->types.at(ii).type == t)
1328 QDeclarativeCompiledData::TypeReference ref;
1329 ref.className = "Component";
1331 output->types << ref;
1332 return output->types.count() - 1;
1335 bool QDeclarativeCompiler::buildSignal(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj,
1336 const BindingContext &ctxt)
1338 Q_ASSERT(obj->metaObject());
1340 QByteArray name = prop->name;
1341 Q_ASSERT(name.startsWith("on"));
1343 if(name[0] >= 'A' && name[0] <= 'Z')
1344 name[0] = name[0] - 'A' + 'a';
1346 bool notInRevision = false;
1347 int sigIdx = indexOfSignal(obj, name, ¬InRevision);
1351 if (notInRevision && -1 == indexOfProperty(obj, prop->name, 0)) {
1352 Q_ASSERT(obj->type != -1);
1353 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1354 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1356 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));
1358 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)));
1362 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1364 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1368 if (prop->value || prop->values.count() != 1)
1369 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1371 prop->index = sigIdx;
1372 obj->addSignalProperty(prop);
1374 if (prop->values.at(0)->object) {
1375 COMPILE_CHECK(buildObject(prop->values.at(0)->object, ctxt));
1376 prop->values.at(0)->type = Value::SignalObject;
1378 prop->values.at(0)->type = Value::SignalExpression;
1380 if (!prop->values.at(0)->value.isScript())
1381 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1383 QString script = prop->values.at(0)->value.asScript().trimmed();
1384 if (script.isEmpty())
1385 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1387 compileState.signalExpressions.insert(prop->values.at(0), ctxt);
1396 Returns true if (value) property \a prop exists on obj, false otherwise.
1398 bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeParser::Property *prop,
1399 QDeclarativeParser::Object *obj)
1401 if(isAttachedPropertyName(prop->name) || prop->name == "id")
1404 const QMetaObject *mo = obj->metaObject();
1406 if (prop->isDefault) {
1407 QMetaProperty p = QDeclarativeMetaType::defaultProperty(mo);
1408 return p.name() != 0;
1410 int idx = indexOfProperty(obj, prop->name);
1411 return idx != -1 && mo->property(idx).isScriptable();
1418 bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop,
1419 QDeclarativeParser::Object *obj,
1420 const BindingContext &ctxt)
1422 if (prop->isEmpty())
1423 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1425 const QMetaObject *metaObject = obj->metaObject();
1426 Q_ASSERT(metaObject);
1428 if (isAttachedPropertyName(prop->name)) {
1429 // Setup attached property data
1431 if (ctxt.isSubContext()) {
1432 // Attached properties cannot be used on sub-objects. Sub-objects
1433 // always exist in a binding sub-context, which is what we test
1435 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1438 QDeclarativeType *type = 0;
1439 QDeclarativeImportedNamespace *typeNamespace = 0;
1440 unit->imports().resolveType(prop->name, &type, 0, 0, 0, &typeNamespace);
1442 if (typeNamespace) {
1443 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1446 } else if (!type || !type->attachedPropertiesType()) {
1447 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1451 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1453 Q_ASSERT(type->attachedPropertiesFunction());
1454 prop->index = type->attachedPropertiesId();
1455 prop->value->metatype = type->attachedPropertiesType();
1457 // Setup regular property data
1460 if (prop->isDefault) {
1461 p = QDeclarativeMetaType::defaultProperty(metaObject);
1464 prop->index = p.propertyIndex();
1465 prop->name = p.name();
1469 bool notInRevision = false;
1470 prop->index = indexOfProperty(obj, prop->name, ¬InRevision);
1471 if (prop->index == -1 && notInRevision) {
1472 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1473 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1475 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));
1477 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)));
1481 if (prop->index != -1) {
1482 p = metaObject->property(prop->index);
1485 if (!p.isScriptable()) {
1487 p = QMetaProperty();
1492 // We can't error here as the "id" property does not require a
1493 // successful index resolution
1495 prop->type = p.userType();
1497 // Check if this is an alias
1498 if (prop->index != -1 &&
1500 prop->parent->type != -1 &&
1501 output->types.at(prop->parent->type).component) {
1503 QDeclarativePropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1504 if (cache && cache->property(prop->index) &&
1505 cache->property(prop->index)->flags & QDeclarativePropertyCache::Data::IsAlias)
1506 prop->isAlias = true;
1509 if (prop->index != -1 && !prop->values.isEmpty())
1510 prop->parent->setBindingBit(prop->index);
1513 if (!prop->isDefault && prop->name == "id" && !ctxt.isSubContext()) {
1515 // The magic "id" behavior doesn't apply when "id" is resolved as a
1516 // default property or to sub-objects (which are always in binding
1518 COMPILE_CHECK(buildIdProperty(prop, obj));
1519 if (prop->type == QVariant::String &&
1520 prop->values.at(0)->value.isString())
1521 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1523 } else if (isAttachedPropertyName(prop->name)) {
1525 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1527 } else if (prop->index == -1) {
1529 if (prop->isDefault) {
1530 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1532 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1535 } else if (prop->value) {
1537 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1539 } else if (enginePrivate->isList(prop->type)) {
1541 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1543 } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) {
1545 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1549 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1556 bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
1557 QDeclarativeParser::Property *nsProp,
1558 QDeclarativeParser::Object *obj,
1559 const BindingContext &ctxt)
1562 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1564 foreach (Property *prop, nsProp->value->properties) {
1566 if (!isAttachedPropertyName(prop->name))
1567 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1569 // Setup attached property data
1571 QDeclarativeType *type = 0;
1572 unit->imports().resolveType(ns, prop->name, &type, 0, 0, 0);
1574 if (!type || !type->attachedPropertiesType())
1575 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1578 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1580 Q_ASSERT(type->attachedPropertiesFunction());
1581 prop->index = type->index();
1582 prop->value->metatype = type->attachedPropertiesType();
1584 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1590 void QDeclarativeCompiler::genValueProperty(QDeclarativeParser::Property *prop,
1591 QDeclarativeParser::Object *obj)
1593 if (enginePrivate->isList(prop->type)) {
1594 genListProperty(prop, obj);
1596 genPropertyAssignment(prop, obj);
1600 void QDeclarativeCompiler::genListProperty(QDeclarativeParser::Property *prop,
1601 QDeclarativeParser::Object *obj)
1603 int listType = enginePrivate->listType(prop->type);
1605 QDeclarativeInstruction fetch;
1606 fetch.setType(QDeclarativeInstruction::FetchQList);
1607 fetch.fetchQmlList.property = prop->index;
1608 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1609 fetch.fetchQmlList.type = listType;
1610 output->addInstruction(fetch);
1612 for (int ii = 0; ii < prop->values.count(); ++ii) {
1613 QDeclarativeParser::Value *v = prop->values.at(ii);
1615 if (v->type == Value::CreatedObject) {
1617 genObject(v->object);
1618 if (listTypeIsInterface) {
1619 QDeclarativeInstruction assign;
1620 assign.setType(QDeclarativeInstruction::AssignObjectList);
1621 assign.assignObjectList.line = prop->location.start.line;
1622 output->addInstruction(assign);
1624 QDeclarativeInstruction store;
1625 store.setType(QDeclarativeInstruction::StoreObjectQList);
1626 output->addInstruction(store);
1629 } else if (v->type == Value::PropertyBinding) {
1631 genBindingAssignment(v, prop, obj);
1637 QDeclarativeInstruction pop;
1638 pop.setType(QDeclarativeInstruction::PopQList);
1639 output->addInstruction(pop);
1642 void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *prop,
1643 QDeclarativeParser::Object *obj,
1644 QDeclarativeParser::Property *valueTypeProperty)
1646 for (int ii = 0; ii < prop->values.count(); ++ii) {
1647 QDeclarativeParser::Value *v = prop->values.at(ii);
1649 Q_ASSERT(v->type == Value::CreatedObject ||
1650 v->type == Value::PropertyBinding ||
1651 v->type == Value::Literal);
1653 if (v->type == Value::CreatedObject) {
1655 genObject(v->object);
1657 if (QDeclarativeMetaType::isInterface(prop->type)) {
1659 QDeclarativeInstruction store;
1660 store.setType(QDeclarativeInstruction::StoreInterface);
1661 store.storeObject.line = v->object->location.start.line;
1662 store.storeObject.propertyIndex = prop->index;
1663 output->addInstruction(store);
1665 } else if (prop->type == -1) {
1667 QDeclarativeInstruction store;
1668 store.setType(QDeclarativeInstruction::StoreVariantObject);
1669 store.storeObject.line = v->object->location.start.line;
1670 store.storeObject.propertyIndex = prop->index;
1671 output->addInstruction(store);
1675 QDeclarativeInstruction store;
1676 store.setType(QDeclarativeInstruction::StoreObject);
1677 store.storeObject.line = v->object->location.start.line;
1678 store.storeObject.propertyIndex = prop->index;
1679 output->addInstruction(store);
1682 } else if (v->type == Value::PropertyBinding) {
1684 genBindingAssignment(v, prop, obj, valueTypeProperty);
1686 } else if (v->type == Value::Literal) {
1688 QMetaProperty mp = obj->metaObject()->property(prop->index);
1689 genLiteralAssignment(mp, v);
1695 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
1697 QDeclarativeParser::Value *v = prop->onValues.at(ii);
1699 Q_ASSERT(v->type == Value::ValueSource ||
1700 v->type == Value::ValueInterceptor);
1702 if (v->type == Value::ValueSource) {
1703 genObject(v->object);
1705 QDeclarativeInstruction store;
1706 store.setType(QDeclarativeInstruction::StoreValueSource);
1707 if (valueTypeProperty) {
1708 store.assignValueSource.property = genValueTypeData(prop, valueTypeProperty);
1709 store.assignValueSource.owner = 1;
1711 store.assignValueSource.property = genPropertyData(prop);
1712 store.assignValueSource.owner = 0;
1714 QDeclarativeType *valueType = toQmlType(v->object);
1715 store.assignValueSource.castValue = valueType->propertyValueSourceCast();
1716 output->addInstruction(store);
1718 } else if (v->type == Value::ValueInterceptor) {
1719 genObject(v->object);
1721 QDeclarativeInstruction store;
1722 store.setType(QDeclarativeInstruction::StoreValueInterceptor);
1723 if (valueTypeProperty) {
1724 store.assignValueInterceptor.property = genValueTypeData(prop, valueTypeProperty);
1725 store.assignValueInterceptor.owner = 1;
1727 store.assignValueInterceptor.property = genPropertyData(prop);
1728 store.assignValueInterceptor.owner = 0;
1730 QDeclarativeType *valueType = toQmlType(v->object);
1731 store.assignValueInterceptor.castValue = valueType->propertyValueInterceptorCast();
1732 output->addInstruction(store);
1738 bool QDeclarativeCompiler::buildIdProperty(QDeclarativeParser::Property *prop,
1739 QDeclarativeParser::Object *obj)
1742 prop->values.count() > 1 ||
1743 prop->values.at(0)->object)
1744 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
1746 QDeclarativeParser::Value *idValue = prop->values.at(0);
1747 QString val = idValue->primitive();
1749 COMPILE_CHECK(checkValidId(idValue, val));
1751 if (compileState.ids.contains(val))
1752 COMPILE_EXCEPTION(prop, tr("id is not unique"));
1754 prop->values.at(0)->type = Value::Id;
1762 void QDeclarativeCompiler::addId(const QString &id, QDeclarativeParser::Object *obj)
1764 Q_ASSERT(!compileState.ids.contains(id));
1765 Q_ASSERT(obj->id == id);
1766 obj->idIndex = compileState.ids.count();
1767 compileState.ids.insert(id, obj);
1768 compileState.idIndexes.insert(obj->idIndex, obj);
1771 void QDeclarativeCompiler::addBindingReference(const BindingReference &ref)
1773 Q_ASSERT(ref.value && !compileState.bindings.contains(ref.value));
1774 compileState.bindings.insert(ref.value, ref);
1777 void QDeclarativeCompiler::saveComponentState()
1779 Q_ASSERT(compileState.root);
1780 Q_ASSERT(!savedCompileStates.contains(compileState.root));
1782 savedCompileStates.insert(compileState.root, compileState);
1783 savedComponentStats.append(componentStat);
1786 QDeclarativeCompiler::ComponentCompileState
1787 QDeclarativeCompiler::componentState(QDeclarativeParser::Object *obj)
1789 Q_ASSERT(savedCompileStates.contains(obj));
1790 return savedCompileStates.value(obj);
1793 // Build attached property object. In this example,
1797 // GridView is an attached property object.
1798 bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeParser::Property *prop,
1799 QDeclarativeParser::Object *obj,
1800 const BindingContext &ctxt)
1802 Q_ASSERT(prop->value);
1803 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
1805 obj->addAttachedProperty(prop);
1807 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1813 // Build "grouped" properties. In this example:
1815 // font.pointSize: 12
1816 // font.family: "Helvetica"
1818 // font is a nested property. pointSize and family are not.
1819 bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeParser::Property *prop,
1820 QDeclarativeParser::Object *obj,
1821 const BindingContext &ctxt)
1823 Q_ASSERT(prop->type != 0);
1824 Q_ASSERT(prop->index != -1);
1826 if (QDeclarativeValueTypeFactory::isValueType(prop->type)) {
1827 if (prop->type >= 0 /* QVariant == -1 */ && enginePrivate->valueTypes[prop->type]) {
1829 if (prop->values.count()) {
1830 if (prop->values.at(0)->location < prop->value->location) {
1831 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
1833 COMPILE_EXCEPTION(prop->values.at(0), tr( "Property has already been assigned a value"));
1837 if (!obj->metaObject()->property(prop->index).isWritable()) {
1838 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
1842 if (prop->isAlias) {
1843 foreach (Property *vtProp, prop->value->properties)
1844 vtProp->isAlias = true;
1847 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
1848 prop->value, obj, ctxt.incr()));
1849 obj->addValueTypeProperty(prop);
1851 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1855 // Load the nested property's meta type
1856 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
1857 if (!prop->value->metatype)
1858 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1860 if (prop->values.count())
1861 COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign a value directly to a grouped property"));
1863 obj->addGroupedProperty(prop);
1865 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1871 bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
1872 QDeclarativeParser::Object *obj,
1873 QDeclarativeParser::Object *baseObj,
1874 const BindingContext &ctxt)
1876 if (obj->defaultProperty)
1877 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
1878 obj->metatype = type->metaObject();
1880 foreach (Property *prop, obj->properties) {
1881 int idx = type->metaObject()->indexOfProperty(prop->name.constData());
1883 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1884 QMetaProperty p = type->metaObject()->property(idx);
1885 if (!p.isScriptable())
1886 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1888 prop->type = p.userType();
1889 prop->isValueTypeSubProperty = true;
1892 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
1894 if (prop->values.count() > 1) {
1895 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
1896 } else if (prop->values.count()) {
1897 QDeclarativeParser::Value *value = prop->values.at(0);
1899 if (value->object) {
1900 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
1901 } else if (value->value.isScript()) {
1902 // ### Check for writability
1904 //optimization for <Type>.<EnumValue> enum assignments
1905 bool isEnumAssignment = false;
1906 COMPILE_CHECK(testQualifiedEnumAssignment(p, obj, value, &isEnumAssignment));
1907 if (isEnumAssignment) {
1908 value->type = Value::Literal;
1910 BindingReference reference;
1911 reference.expression = value->value;
1912 reference.property = prop;
1913 reference.value = value;
1914 reference.bindingContext = ctxt;
1915 reference.bindingContext.owner++;
1916 addBindingReference(reference);
1917 value->type = Value::PropertyBinding;
1920 COMPILE_CHECK(testLiteralAssignment(p, value));
1921 value->type = Value::Literal;
1925 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
1926 QDeclarativeParser::Value *v = prop->onValues.at(ii);
1927 Q_ASSERT(v->object);
1929 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
1932 obj->addValueProperty(prop);
1938 // Build assignments to QML lists. QML lists are properties of type
1939 // QDeclarativeListProperty<T>. List properties can accept a list of
1940 // objects, or a single binding.
1941 bool QDeclarativeCompiler::buildListProperty(QDeclarativeParser::Property *prop,
1942 QDeclarativeParser::Object *obj,
1943 const BindingContext &ctxt)
1945 Q_ASSERT(enginePrivate->isList(prop->type));
1949 obj->addValueProperty(prop);
1951 int listType = enginePrivate->listType(t);
1952 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1954 bool assignedBinding = false;
1955 for (int ii = 0; ii < prop->values.count(); ++ii) {
1956 QDeclarativeParser::Value *v = prop->values.at(ii);
1958 v->type = Value::CreatedObject;
1959 COMPILE_CHECK(buildObject(v->object, ctxt));
1961 // We check object coercian here. We check interface assignment
1963 if (!listTypeIsInterface) {
1964 if (!canCoerce(listType, v->object)) {
1965 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
1969 } else if (v->value.isScript()) {
1970 if (assignedBinding)
1971 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
1973 assignedBinding = true;
1974 COMPILE_CHECK(buildBinding(v, prop, ctxt));
1975 v->type = Value::PropertyBinding;
1977 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
1984 // Compiles an assignment to a QDeclarativeScriptString property
1985 bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeParser::Property *prop,
1986 QDeclarativeParser::Object *obj,
1987 const BindingContext &ctxt)
1989 if (prop->values.count() > 1)
1990 COMPILE_EXCEPTION(prop->values.at(1), tr( "Cannot assign multiple values to a script property"));
1992 if (prop->values.at(0)->object)
1993 COMPILE_EXCEPTION(prop->values.at(0), tr( "Invalid property assignment: script expected"));
1995 obj->addScriptStringProperty(prop, ctxt.stack);
2000 // Compile regular property assignments of the form "property: <value>"
2001 bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeParser::Property *prop,
2002 QDeclarativeParser::Object *obj,
2003 const BindingContext &ctxt)
2005 obj->addValueProperty(prop);
2007 if (prop->values.count() > 1)
2008 COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign multiple values to a singular property") );
2010 for (int ii = 0; ii < prop->values.count(); ++ii) {
2011 QDeclarativeParser::Value *v = prop->values.at(ii);
2014 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2018 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2023 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
2024 QDeclarativeParser::Value *v = prop->onValues.at(ii);
2026 Q_ASSERT(v->object);
2027 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2033 // Compile assigning a single object instance to a regular property
2034 bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeParser::Property *prop,
2035 QDeclarativeParser::Object *obj,
2036 QDeclarativeParser::Value *v,
2037 const BindingContext &ctxt)
2039 Q_ASSERT(prop->index != -1);
2040 Q_ASSERT(v->object->type != -1);
2042 if (!obj->metaObject()->property(prop->index).isWritable())
2043 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2045 if (QDeclarativeMetaType::isInterface(prop->type)) {
2047 // Assigning an object to an interface ptr property
2048 COMPILE_CHECK(buildObject(v->object, ctxt));
2050 v->type = Value::CreatedObject;
2052 } else if (prop->type == -1) {
2054 // Assigning an object to a QVariant
2055 COMPILE_CHECK(buildObject(v->object, ctxt));
2057 v->type = Value::CreatedObject;
2059 // Normally buildObject() will set this up, but we need the static
2060 // meta object earlier to test for assignability. It doesn't matter
2061 // that there may still be outstanding synthesized meta object changes
2062 // on this type, as they are not relevant for assignability testing
2063 v->object->metatype = output->types.at(v->object->type).metaObject();
2064 Q_ASSERT(v->object->metaObject());
2066 // We want to raw metaObject here as the raw metaobject is the
2067 // actual property type before we applied any extensions that might
2068 // effect the properties on the type, but don't effect assignability
2069 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2071 // Will be true if the assgned type inherits propertyMetaObject
2072 bool isAssignable = false;
2073 // Determine isAssignable value
2074 if (propertyMetaObject) {
2075 const QMetaObject *c = v->object->metatype;
2077 isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject));
2078 c = c->superClass();
2083 // Simple assignment
2084 COMPILE_CHECK(buildObject(v->object, ctxt));
2086 v->type = Value::CreatedObject;
2087 } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) {
2088 // Automatic "Component" insertion
2089 QDeclarativeParser::Object *root = v->object;
2090 QDeclarativeParser::Object *component = new QDeclarativeParser::Object;
2091 component->type = componentTypeRef();
2092 component->typeName = "Qt/Component";
2093 component->metatype = &QDeclarativeComponent::staticMetaObject;
2094 component->location = root->location;
2095 QDeclarativeParser::Value *componentValue = new QDeclarativeParser::Value;
2096 componentValue->object = root;
2097 component->getDefaultProperty()->addValue(componentValue);
2098 v->object = component;
2099 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2101 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2108 // Compile assigning a single object instance to a regular property using the "on" syntax.
2112 // NumberAnimation on x { }
2114 bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeParser::Property *prop,
2115 QDeclarativeParser::Object *obj,
2116 QDeclarativeParser::Object *baseObj,
2117 QDeclarativeParser::Value *v,
2118 const BindingContext &ctxt)
2120 Q_ASSERT(prop->index != -1);
2121 Q_ASSERT(v->object->type != -1);
2123 if (!obj->metaObject()->property(prop->index).isWritable())
2124 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2127 // Normally buildObject() will set this up, but we need the static
2128 // meta object earlier to test for assignability. It doesn't matter
2129 // that there may still be outstanding synthesized meta object changes
2130 // on this type, as they are not relevant for assignability testing
2131 v->object->metatype = output->types.at(v->object->type).metaObject();
2132 Q_ASSERT(v->object->metaObject());
2134 // Will be true if the assigned type inherits QDeclarativePropertyValueSource
2135 bool isPropertyValue = false;
2136 // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor
2137 bool isPropertyInterceptor = false;
2138 if (QDeclarativeType *valueType = toQmlType(v->object)) {
2139 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2140 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2143 if (isPropertyValue || isPropertyInterceptor) {
2144 // Assign as a property value source
2145 COMPILE_CHECK(buildObject(v->object, ctxt));
2147 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2148 buildDynamicMeta(baseObj, ForceCreation);
2149 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2151 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(QString::fromUtf8(v->object->typeName)).arg(QString::fromUtf8(prop->name.constData())));
2157 // Compile assigning a literal or binding to a regular property
2158 bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeParser::Property *prop,
2159 QDeclarativeParser::Object *obj,
2160 QDeclarativeParser::Value *v,
2161 const BindingContext &ctxt)
2163 Q_ASSERT(prop->index != -1);
2165 if (v->value.isScript()) {
2167 //optimization for <Type>.<EnumValue> enum assignments
2168 bool isEnumAssignment = false;
2169 COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj, v, &isEnumAssignment));
2170 if (isEnumAssignment) {
2171 v->type = Value::Literal;
2175 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2177 v->type = Value::PropertyBinding;
2181 COMPILE_CHECK(testLiteralAssignment(obj->metaObject()->property(prop->index), v));
2183 v->type = Value::Literal;
2189 bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop,
2190 QDeclarativeParser::Object *obj,
2191 QDeclarativeParser::Value *v,
2194 *isAssignment = false;
2195 if (!prop.isEnumType())
2198 if (!prop.isWritable())
2199 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
2201 QString string = v->value.asString();
2202 if (!string.at(0).isUpper())
2205 QStringList parts = string.split(QLatin1Char('.'));
2206 if (parts.count() != 2)
2209 QString typeName = parts.at(0);
2210 QDeclarativeType *type = 0;
2211 unit->imports().resolveType(typeName.toUtf8(), &type, 0, 0, 0, 0);
2213 //handle enums on value types (where obj->typeName is empty)
2214 QByteArray objTypeName = obj->typeName;
2215 if (objTypeName.isEmpty()) {
2216 QDeclarativeType *objType = toQmlType(obj);
2218 objTypeName = objType->qmlTypeName();
2224 QString enumValue = parts.at(1);
2227 if (objTypeName == type->qmlTypeName()) {
2228 // When these two match, we can short cut the search
2229 if (prop.isFlagType()) {
2230 value = prop.enumerator().keysToValue(enumValue.toUtf8().constData());
2232 value = prop.enumerator().keyToValue(enumValue.toUtf8().constData());
2235 // Otherwise we have to search the whole type
2236 // This matches the logic in QDeclarativeTypeNameScriptClass
2237 QByteArray enumName = enumValue.toUtf8();
2238 const QMetaObject *metaObject = type->baseMetaObject();
2239 for (int ii = metaObject->enumeratorCount() - 1; value == -1 && ii >= 0; --ii) {
2240 QMetaEnum e = metaObject->enumerator(ii);
2241 value = e.keyToValue(enumName.constData());
2248 v->type = Value::Literal;
2249 v->value = QDeclarativeParser::Variant((double)value);
2250 *isAssignment = true;
2255 // Similar logic to above, but not knowing target property.
2256 int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const
2258 int dot = script.indexOf('.');
2260 QDeclarativeType *type = 0;
2261 unit->imports().resolveType(script.left(dot), &type, 0, 0, 0, 0);
2264 const QMetaObject *mo = type->metaObject();
2265 const char *key = script.constData() + dot+1;
2266 int i = mo->enumeratorCount();
2268 int v = mo->enumerator(i).keyToValue(key);
2276 const QMetaObject *QDeclarativeCompiler::resolveType(const QByteArray& name) const
2278 QDeclarativeType *qmltype = 0;
2279 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2283 return qmltype->metaObject();
2286 // similar to logic of completeComponentBuild, but also sticks data
2287 // into datas at the end
2288 int QDeclarativeCompiler::rewriteBinding(const QString& expression, const QByteArray& name)
2290 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2291 rewriteBinding.setName('$' + name.mid(name.lastIndexOf('.') + 1));
2292 bool isSharable = false;
2293 QString rewrite = rewriteBinding(expression, 0, &isSharable);
2295 quint32 length = rewrite.length();
2299 pc = output->cachedClosures.count();
2301 output->cachedClosures.append(0);
2303 pc = output->cachedPrograms.length();
2304 output->cachedPrograms.append(0);
2307 QByteArray compiledData =
2308 QByteArray((const char *)&pc, sizeof(quint32)) +
2309 QByteArray((const char *)&length, sizeof(quint32)) +
2310 QByteArray((const char *)rewrite.constData(),
2311 rewrite.length() * sizeof(QChar));
2313 return output->indexForByteArray(compiledData);
2316 // Ensures that the dynamic meta specification on obj is valid
2317 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj)
2319 QSet<QByteArray> propNames;
2320 QSet<QByteArray> methodNames;
2321 bool seenDefaultProperty = false;
2324 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2325 const QDeclarativeParser::Object::DynamicProperty &prop =
2326 obj->dynamicProperties.at(ii);
2328 if (prop.isDefaultProperty) {
2329 if (seenDefaultProperty)
2330 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2331 seenDefaultProperty = true;
2334 if (propNames.contains(prop.name))
2335 COMPILE_EXCEPTION(&prop, tr("Duplicate property name"));
2337 QString propName = QString::fromUtf8(prop.name);
2338 if (propName.at(0).isUpper())
2339 COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
2341 if (enginePrivate->globalClass->illegalNames().contains(propName))
2342 COMPILE_EXCEPTION(&prop, tr("Illegal property name"));
2344 propNames.insert(prop.name);
2347 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2348 QByteArray name = obj->dynamicSignals.at(ii).name;
2349 if (methodNames.contains(name))
2350 COMPILE_EXCEPTION(obj, tr("Duplicate signal name"));
2351 QString nameStr = QString::fromUtf8(name);
2352 if (nameStr.at(0).isUpper())
2353 COMPILE_EXCEPTION(obj, tr("Signal names cannot begin with an upper case letter"));
2354 if (enginePrivate->globalClass->illegalNames().contains(nameStr))
2355 COMPILE_EXCEPTION(obj, tr("Illegal signal name"));
2356 methodNames.insert(name);
2358 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2359 QByteArray name = obj->dynamicSlots.at(ii).name;
2360 if (methodNames.contains(name))
2361 COMPILE_EXCEPTION(obj, tr("Duplicate method name"));
2362 QString nameStr = QString::fromUtf8(name);
2363 if (nameStr.at(0).isUpper())
2364 COMPILE_EXCEPTION(obj, tr("Method names cannot begin with an upper case letter"));
2365 if (enginePrivate->globalClass->illegalNames().contains(nameStr))
2366 COMPILE_EXCEPTION(obj, tr("Illegal method name"));
2367 methodNames.insert(name);
2373 bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeParser::Object *obj)
2375 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2376 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2378 if (!p.defaultValue || p.type == Object::DynamicProperty::Alias)
2381 Property *property = 0;
2382 if (p.isDefaultProperty) {
2383 property = obj->getDefaultProperty();
2385 property = obj->getProperty(p.name);
2386 if (!property->values.isEmpty())
2387 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2390 if (property->value)
2391 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2393 for (int ii = 0; ii < p.defaultValue->values.count(); ++ii) {
2394 QDeclarativeParser::Value *v = p.defaultValue->values.at(ii);
2396 property->values.append(v);
2402 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2404 bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, DynamicMetaMode mode)
2407 Q_ASSERT(obj->metatype);
2409 if (mode != ForceCreation &&
2410 obj->dynamicProperties.isEmpty() &&
2411 obj->dynamicSignals.isEmpty() &&
2412 obj->dynamicSlots.isEmpty())
2415 QByteArray dynamicData(sizeof(QDeclarativeVMEMetaData), (char)0);
2417 QByteArray newClassName = obj->metatype->className();
2418 newClassName.append("_QML_");
2419 int idx = classIndexCounter()->fetchAndAddRelaxed(1);
2420 newClassName.append(QByteArray::number(idx));
2421 if (compileState.root == obj && !compileState.nested) {
2422 QString path = output->url.path();
2423 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2424 if (lastSlash > -1) {
2425 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2426 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2427 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(idx);
2431 QMetaObjectBuilder builder;
2432 builder.setClassName(newClassName);
2433 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
2435 bool hasAlias = false;
2436 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2437 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2439 int propIdx = obj->metaObject()->indexOfProperty(p.name.constData());
2440 if (-1 != propIdx) {
2441 QMetaProperty prop = obj->metaObject()->property(propIdx);
2443 COMPILE_EXCEPTION(&p, tr("Cannot override FINAL property"));
2446 if (p.isDefaultProperty &&
2447 (p.type != Object::DynamicProperty::Alias ||
2448 mode == ResolveAliases))
2449 builder.addClassInfo("DefaultProperty", p.name);
2452 int propertyType = 0;
2453 bool readonly = false;
2455 case Object::DynamicProperty::Alias:
2459 case Object::DynamicProperty::CustomList:
2460 case Object::DynamicProperty::Custom:
2462 QByteArray customTypeName;
2463 QDeclarativeType *qmltype = 0;
2465 if (!unit->imports().resolveType(p.customType, &qmltype, &url, 0, 0, 0))
2466 COMPILE_EXCEPTION(&p, tr("Invalid property type"));
2469 QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(url);
2471 Q_ASSERT(tdata->isComplete());
2473 QDeclarativeCompiledData *data = tdata->compiledData();
2474 customTypeName = data->root->className();
2478 customTypeName = qmltype->typeName();
2481 if (p.type == Object::DynamicProperty::Custom) {
2482 type = customTypeName + '*';
2483 propertyType = QMetaType::QObjectStar;
2486 type = "QDeclarativeListProperty<";
2487 type.append(customTypeName);
2489 propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
2493 case Object::DynamicProperty::Variant:
2497 case Object::DynamicProperty::Int:
2498 propertyType = QVariant::Int;
2501 case Object::DynamicProperty::Bool:
2502 propertyType = QVariant::Bool;
2505 case Object::DynamicProperty::Real:
2506 propertyType = QVariant::Double;
2509 case Object::DynamicProperty::String:
2510 propertyType = QVariant::String;
2513 case Object::DynamicProperty::Url:
2514 propertyType = QVariant::Url;
2517 case Object::DynamicProperty::Color:
2518 propertyType = QVariant::Color;
2521 case Object::DynamicProperty::Time:
2522 propertyType = QVariant::Time;
2525 case Object::DynamicProperty::Date:
2526 propertyType = QVariant::Date;
2529 case Object::DynamicProperty::DateTime:
2530 propertyType = QVariant::DateTime;
2535 ((QDeclarativeVMEMetaData *)dynamicData.data())->propertyCount++;
2536 QDeclarativeVMEMetaData::PropertyData propertyData = { propertyType };
2537 dynamicData.append((char *)&propertyData, sizeof(propertyData));
2539 builder.addSignal(p.name + "Changed()");
2540 QMetaPropertyBuilder propBuilder =
2541 builder.addProperty(p.name, type, builder.methodCount() - 1);
2542 propBuilder.setWritable(!readonly);
2545 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2546 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2548 if (p.type == Object::DynamicProperty::Alias) {
2549 if (mode == ResolveAliases) {
2550 ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++;
2551 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, p));
2553 // Need a fake signal so that the metaobject remains consistent across
2554 // the resolve and non-resolve alias runs
2555 builder.addSignal(p.name + "Changed()");
2560 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2561 const Object::DynamicSignal &s = obj->dynamicSignals.at(ii);
2562 QByteArray sig(s.name + '(');
2563 for (int jj = 0; jj < s.parameterTypes.count(); ++jj) {
2564 if (jj) sig.append(',');
2565 sig.append(s.parameterTypes.at(jj));
2568 QMetaMethodBuilder b = builder.addSignal(sig);
2569 b.setParameterNames(s.parameterNames);
2570 ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++;
2573 QStringList funcScripts;
2575 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2576 Object::DynamicSlot &s = obj->dynamicSlots[ii];
2577 QByteArray sig(s.name + '(');
2578 QString funcScript(QLatin1String("(function ") + s.name + QLatin1Char('('));
2580 for (int jj = 0; jj < s.parameterNames.count(); ++jj) {
2583 funcScript.append(QLatin1Char(','));
2585 funcScript.append(QLatin1String(s.parameterNames.at(jj)));
2586 sig.append("QVariant");
2589 funcScript.append(QLatin1Char(')'));
2590 funcScript.append(s.body);
2591 funcScript.append(QLatin1Char(')'));
2592 funcScripts << funcScript;
2594 QMetaMethodBuilder b = builder.addSlot(sig);
2595 b.setReturnType("QVariant");
2596 b.setParameterNames(s.parameterNames);
2598 ((QDeclarativeVMEMetaData *)dynamicData.data())->methodCount++;
2599 QDeclarativeVMEMetaData::MethodData methodData =
2600 { s.parameterNames.count(), 0, funcScript.length(), s.location.start.line };
2602 dynamicData.append((char *)&methodData, sizeof(methodData));
2605 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2606 const QString &funcScript = funcScripts.at(ii);
2607 QDeclarativeVMEMetaData::MethodData *data =
2608 ((QDeclarativeVMEMetaData *)dynamicData.data())->methodData() + ii;
2610 data->bodyOffset = dynamicData.size();
2612 dynamicData.append((const char *)funcScript.constData(),
2613 (funcScript.length() * sizeof(QChar)));
2616 obj->metadata = builder.toRelocatableData();
2617 builder.fromRelocatableData(&obj->extObject, obj->metatype, obj->metadata);
2619 if (mode == IgnoreAliases && hasAlias)
2620 compileState.aliasingObjects << obj;
2622 obj->synthdata = dynamicData;
2624 if (obj->synthCache) {
2625 obj->synthCache->release();
2626 obj->synthCache = 0;
2629 if (obj->type != -1) {
2630 QDeclarativePropertyCache *cache = output->types[obj->type].createPropertyCache(engine)->copy();
2631 cache->append(engine, &obj->extObject, QDeclarativePropertyCache::Data::NoFlags,
2632 QDeclarativePropertyCache::Data::IsVMEFunction,
2633 QDeclarativePropertyCache::Data::IsVMESignal);
2634 obj->synthCache = cache;
2640 bool QDeclarativeCompiler::checkValidId(QDeclarativeParser::Value *v, const QString &val)
2643 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
2645 if (val.at(0).isLetter() && !val.at(0).isLower())
2646 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
2648 QChar u(QLatin1Char('_'));
2649 for (int ii = 0; ii < val.count(); ++ii) {
2651 if (ii == 0 && !val.at(ii).isLetter() && val.at(ii) != u) {
2652 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
2653 } else if (ii != 0 && !val.at(ii).isLetterOrNumber() && val.at(ii) != u) {
2654 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
2659 if (enginePrivate->globalClass->illegalNames().contains(val))
2660 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
2665 #include <qdeclarativejsparser_p.h>
2667 static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node)
2669 if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) {
2671 static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name->asString();
2672 return QStringList() << name;
2673 } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) {
2674 QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node);
2676 QStringList rv = astNodeToStringList(expr->base);
2679 rv.append(expr->name->asString());
2682 return QStringList();
2685 bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder,
2687 QDeclarativeParser::Object *obj,
2688 const Object::DynamicProperty &prop)
2690 if (!prop.defaultValue)
2691 COMPILE_EXCEPTION(obj, tr("No property alias location"));
2693 if (prop.defaultValue->values.count() != 1 ||
2694 prop.defaultValue->values.at(0)->object ||
2695 !prop.defaultValue->values.at(0)->value.isScript())
2696 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2698 QDeclarativeJS::AST::Node *node = prop.defaultValue->values.at(0)->value.asAST();
2700 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
2702 QStringList alias = astNodeToStringList(node);
2704 if (alias.count() < 1 || alias.count() > 3)
2705 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
2707 if (!compileState.ids.contains(alias.at(0)))
2708 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
2710 QDeclarativeParser::Object *idObject = compileState.ids[alias.at(0)];
2712 QByteArray typeName;
2716 bool writable = false;
2717 if (alias.count() == 2 || alias.count() == 3) {
2718 propIdx = indexOfProperty(idObject, alias.at(1).toUtf8());
2720 if (-1 == propIdx) {
2721 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2722 } else if (propIdx > 0xFFFF) {
2723 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
2726 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
2727 if (!aliasProperty.isScriptable())
2728 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2730 writable = aliasProperty.isWritable();
2732 if (alias.count() == 3) {
2733 QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
2735 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2737 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
2739 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
2740 if (valueTypeIndex == -1)
2741 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2742 Q_ASSERT(valueTypeIndex <= 0xFF);
2744 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
2745 propIdx |= (valueTypeIndex << 16);
2748 if (aliasProperty.isEnumType())
2749 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
2751 typeName = aliasProperty.typeName();
2753 typeName = idObject->metaObject()->className();
2755 //use the base type since it has been registered with metatype system
2756 int index = typeName.indexOf("_QML_");
2758 typeName = typeName.left(index);
2760 index = typeName.indexOf("_QMLTYPE_");
2761 const QMetaObject *mo = idObject->metaObject();
2762 while (index != -1 && mo) {
2763 typeName = mo->superClass()->className();
2764 index = typeName.indexOf("_QMLTYPE_");
2765 mo = mo->superClass();
2772 if (typeName.endsWith('*'))
2773 flags |= QML_ALIAS_FLAG_PTR;
2775 data.append((const char *)&idObject->idIndex, sizeof(idObject->idIndex));
2776 data.append((const char *)&propIdx, sizeof(propIdx));
2777 data.append((const char *)&flags, sizeof(flags));
2779 builder.addSignal(prop.name + "Changed()");
2780 QMetaPropertyBuilder propBuilder =
2781 builder.addProperty(prop.name, typeName.constData(), builder.methodCount() - 1);
2782 propBuilder.setWritable(writable);
2786 bool QDeclarativeCompiler::buildBinding(QDeclarativeParser::Value *value,
2787 QDeclarativeParser::Property *prop,
2788 const BindingContext &ctxt)
2790 Q_ASSERT(prop->index != -1);
2791 Q_ASSERT(prop->parent);
2792 Q_ASSERT(prop->parent->metaObject());
2794 QMetaProperty mp = prop->parent->metaObject()->property(prop->index);
2795 if (!mp.isWritable() && !QDeclarativeMetaType::isList(prop->type))
2796 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2798 BindingReference reference;
2799 reference.expression = value->value;
2800 reference.property = prop;
2801 reference.value = value;
2802 reference.bindingContext = ctxt;
2803 addBindingReference(reference);
2808 void QDeclarativeCompiler::genBindingAssignment(QDeclarativeParser::Value *binding,
2809 QDeclarativeParser::Property *prop,
2810 QDeclarativeParser::Object *obj,
2811 QDeclarativeParser::Property *valueTypeProperty)
2814 Q_ASSERT(compileState.bindings.contains(binding));
2816 const BindingReference &ref = compileState.bindings.value(binding);
2817 if (ref.dataType == BindingReference::Experimental) {
2818 QDeclarativeInstruction store;
2819 store.setType(QDeclarativeInstruction::StoreCompiledBinding);
2820 store.assignBinding.value = ref.compiledIndex;
2821 store.assignBinding.context = ref.bindingContext.stack;
2822 store.assignBinding.owner = ref.bindingContext.owner;
2823 if (valueTypeProperty)
2824 store.assignBinding.property = (valueTypeProperty->index & 0xFFFF) |
2825 ((valueTypeProperty->type & 0xFF)) << 16 |
2826 ((prop->index & 0xFF) << 24);
2828 store.assignBinding.property = prop->index;
2829 store.assignBinding.line = binding->location.start.line;
2830 output->addInstruction(store);
2834 QDeclarativeInstruction store;
2836 store.setType(QDeclarativeInstruction::StoreBinding);
2838 store.setType(QDeclarativeInstruction::StoreBindingOnAlias);
2839 store.assignBinding.value = output->indexForByteArray(ref.compiledData);
2840 store.assignBinding.context = ref.bindingContext.stack;
2841 store.assignBinding.owner = ref.bindingContext.owner;
2842 store.assignBinding.line = binding->location.start.line;
2844 Q_ASSERT(ref.bindingContext.owner == 0 ||
2845 (ref.bindingContext.owner != 0 && valueTypeProperty));
2846 if (ref.bindingContext.owner) {
2847 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
2849 store.assignBinding.property = genPropertyData(prop);
2852 output->addInstruction(store);
2855 int QDeclarativeCompiler::genContextCache()
2857 if (compileState.ids.count() == 0)
2860 QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache(engine);
2862 for (QHash<QString, QDeclarativeParser::Object *>::ConstIterator iter = compileState.ids.begin();
2863 iter != compileState.ids.end();
2865 cache->add(iter.key(), (*iter)->idIndex);
2867 output->contextCaches.append(cache);
2868 return output->contextCaches.count() - 1;
2871 int QDeclarativeCompiler::genValueTypeData(QDeclarativeParser::Property *valueTypeProp,
2872 QDeclarativeParser::Property *prop)
2875 QDeclarativePropertyPrivate::saveValueType(prop->parent->metaObject(), prop->index,
2876 enginePrivate->valueTypes[prop->type]->metaObject(),
2877 valueTypeProp->index);
2878 // valueTypeProp->index, valueTypeProp->type);
2880 return output->indexForByteArray(data);
2883 int QDeclarativeCompiler::genPropertyData(QDeclarativeParser::Property *prop)
2885 return output->indexForByteArray(QDeclarativePropertyPrivate::saveProperty(prop->parent->metaObject(), prop->index));
2888 bool QDeclarativeCompiler::completeComponentBuild()
2890 componentStat.ids = compileState.ids.count();
2892 for (int ii = 0; ii < compileState.aliasingObjects.count(); ++ii) {
2893 QDeclarativeParser::Object *aliasObject = compileState.aliasingObjects.at(ii);
2894 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
2897 QDeclarativeV4Compiler::Expression expr;
2898 expr.component = compileState.root;
2899 expr.ids = compileState.ids;
2900 expr.importCache = output->importCache;
2901 expr.imports = unit->imports();
2903 QDeclarativeV4Compiler bindingCompiler;
2905 for (QHash<QDeclarativeParser::Value*,BindingReference>::Iterator iter = compileState.bindings.begin();
2906 iter != compileState.bindings.end(); ++iter) {
2908 BindingReference &binding = *iter;
2910 // ### We don't currently optimize for bindings on alias's - because
2911 // of the solution to QTBUG-13719
2912 if (!binding.property->isAlias) {
2913 expr.context = binding.bindingContext.object;
2914 expr.property = binding.property;
2915 expr.expression = binding.expression;
2917 int index = bindingCompiler.compile(expr, enginePrivate);
2919 binding.dataType = BindingReference::Experimental;
2920 binding.compiledIndex = index;
2921 componentStat.optimizedBindings.append(iter.key()->location);
2926 binding.dataType = BindingReference::QtScript;
2928 // Pre-rewrite the expression
2929 QString expression = binding.expression.asScript();
2931 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2932 rewriteBinding.setName('$'+binding.property->name);
2933 bool isSharable = false;
2934 expression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
2936 quint32 length = expression.length();
2940 pc = output->cachedClosures.count();
2942 output->cachedClosures.append(0);
2944 pc = output->cachedPrograms.length();
2945 output->cachedPrograms.append(0);
2948 binding.compiledData =
2949 QByteArray((const char *)&pc, sizeof(quint32)) +
2950 QByteArray((const char *)&length, sizeof(quint32)) +
2951 QByteArray((const char *)expression.constData(),
2952 expression.length() * sizeof(QChar));
2954 componentStat.scriptBindings.append(iter.key()->location);
2957 if (bindingCompiler.isValid())
2958 compileState.compiledBindingData = bindingCompiler.program();
2960 saveComponentState();
2965 void QDeclarativeCompiler::dumpStats()
2967 qWarning().nospace() << "QML Document: " << output->url.toString();
2968 for (int ii = 0; ii < savedComponentStats.count(); ++ii) {
2969 const ComponentStat &stat = savedComponentStats.at(ii);
2970 qWarning().nospace() << " Component Line " << stat.lineNumber;
2971 qWarning().nospace() << " Total Objects: " << stat.objects;
2972 qWarning().nospace() << " IDs Used: " << stat.ids;
2973 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
2977 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
2978 if (0 == (ii % 10)) {
2979 if (ii) output.append("\n");
2984 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
2986 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
2987 output.append(") ");
2989 if (!output.isEmpty())
2990 qWarning().nospace() << output.constData();
2993 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
2996 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
2997 if (0 == (ii % 10)) {
2998 if (ii) output.append("\n");
3003 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3005 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3006 output.append(") ");
3008 if (!output.isEmpty())
3009 qWarning().nospace() << output.constData();
3015 Returns true if from can be assigned to a (QObject) property of type
3018 bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeParser::Object *from)
3020 const QMetaObject *toMo =
3021 enginePrivate->rawMetaObjectForType(to);
3022 const QMetaObject *fromMo = from->metaObject();
3025 if (QDeclarativePropertyPrivate::equal(fromMo, toMo))
3027 fromMo = fromMo->superClass();
3032 QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeParser::Object *from)
3035 const QMetaObject *mo = from->metatype;
3036 QDeclarativeType *type = 0;
3037 while (!type && mo) {
3038 type = QDeclarativeMetaType::qmlType(mo);
3039 mo = mo->superClass();
3044 QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeParser::Object *obj)
3046 const QMetaObject *mo = obj->metatype;
3048 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3050 return QStringList();
3052 QMetaClassInfo classInfo = mo->classInfo(idx);
3053 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3057 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3058 int QDeclarativeCompiler::indexOfSignal(QDeclarativeParser::Object *object, const QByteArray &name,
3059 bool *notInRevision)
3061 if (notInRevision) *notInRevision = false;
3063 if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) {
3065 QString strName(QString::fromUtf8(name));
3066 QDeclarativePropertyCache *cache =
3067 object->synthCache?object->synthCache:output->types.at(object->type).propertyCache();
3069 QDeclarativePropertyCache::Data *d = cache->property(strName);
3070 if (notInRevision) *notInRevision = false;
3072 while (d && !(d->flags & QDeclarativePropertyCache::Data::IsFunction))
3073 d = cache->overrideData(d);
3075 if (d && !cache->isAllowedInRevision(d)) {
3076 if (notInRevision) *notInRevision = true;
3079 return d->coreIndex;
3082 if (name.endsWith("Changed")) {
3083 QByteArray propName = name.mid(0, name.length() - 7);
3085 int propIndex = indexOfProperty(object, propName, notInRevision);
3086 if (propIndex != -1) {
3087 d = cache->property(propIndex);
3088 return d->notifyIndex;
3094 return QDeclarativePropertyPrivate::findSignalByName(object->metaObject(), name).methodIndex();
3099 int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QByteArray &name,
3100 bool *notInRevision)
3102 if (notInRevision) *notInRevision = false;
3104 if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) {
3106 QString strName(QString::fromUtf8(name));
3107 QDeclarativePropertyCache *cache =
3108 object->synthCache?object->synthCache:output->types.at(object->type).propertyCache();
3110 QDeclarativePropertyCache::Data *d = cache->property(strName);
3111 // Find the first property
3112 while (d && d->flags & QDeclarativePropertyCache::Data::IsFunction)
3113 d = cache->overrideData(d);
3115 if (d && !cache->isAllowedInRevision(d)) {
3116 if (notInRevision) *notInRevision = true;
3119 return d?d->coreIndex:-1;
3122 const QMetaObject *mo = object->metaObject();
3123 return mo->indexOfProperty(name.constData());