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 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
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"
74 #include <QtCore/qdebug.h>
75 #include <QtCore/qdatetime.h>
79 DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP);
80 DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS);
82 using namespace QDeclarativeParser;
85 Instantiate a new QDeclarativeCompiler.
87 QDeclarativeCompiler::QDeclarativeCompiler()
88 : output(0), engine(0), unitRoot(0), unit(0)
93 Returns true if the last call to compile() caused errors.
97 bool QDeclarativeCompiler::isError() const
99 return !exceptions.isEmpty();
103 Return the list of errors from the last call to compile(), or an empty list
104 if there were no errors.
106 QList<QDeclarativeError> QDeclarativeCompiler::errors() const
112 Returns true if \a name refers to an attached property, false otherwise.
114 Attached property names are those that start with a capital letter.
116 bool QDeclarativeCompiler::isAttachedPropertyName(const QByteArray &name)
118 return !name.isEmpty() && name.at(0) >= 'A' && name.at(0) <= 'Z';
122 Returns true if \a name refers to a signal property, false otherwise.
124 Signal property names are those that start with "on", followed by a first
125 character which is either a capital letter or one or more underscores followed
126 by a capital letter, which is then followed by other allowed characters.
128 Note that although ECMA-262r3 supports dollarsigns and escaped unicode
129 character codes in property names, for simplicity and performance reasons
130 QML only supports letters, numbers and underscores.
132 bool QDeclarativeCompiler::isSignalPropertyName(const QByteArray &name)
134 if (name.length() < 3) return false;
135 if (!name.startsWith("on")) return false;
136 int ns = name.size();
137 for (int i = 2; i < ns; ++i) {
138 char curr = name.at(i);
139 if (curr == '_') continue;
140 if (curr >= 'A' && curr <= 'Z') return true;
143 return false; // consists solely of underscores - invalid.
147 \macro COMPILE_EXCEPTION
149 Inserts an error into the QDeclarativeCompiler error list, and returns false
152 \a token is used to source the error line and column, and \a desc is the
153 error itself. \a desc can be an expression that can be piped into QDebug.
158 COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(QString::fromUtf8(property->name)));
161 #define COMPILE_EXCEPTION(token, desc) \
163 QString exceptionDescription; \
164 QDeclarativeError error; \
165 error.setUrl(output->url); \
166 error.setLine((token)->location.start.line); \
167 error.setColumn((token)->location.start.column); \
168 error.setDescription(desc.trimmed()); \
169 exceptions << error; \
176 Returns false if \a is false, otherwise does nothing.
178 #define COMPILE_CHECK(a) \
180 if (!a) return false; \
184 Returns true if literal \a v can be assigned to property \a prop, otherwise
187 This test corresponds to action taken by genLiteralAssignment(). Any change
188 made here, must have a corresponding action in genLiteralAssigment().
190 bool QDeclarativeCompiler::testLiteralAssignment(const QMetaProperty &prop,
191 QDeclarativeParser::Value *v)
193 QString string = v->value.asString();
195 if (!prop.isWritable())
196 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
198 if (prop.isEnumType()) {
200 if (prop.isFlagType()) {
201 value = prop.enumerator().keysToValue(string.toUtf8().constData());
203 value = prop.enumerator().keyToValue(string.toUtf8().constData());
205 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration"));
208 int type = prop.userType();
212 case QVariant::String:
213 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
215 case QVariant::ByteArray:
216 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected"));
219 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected"));
223 bool ok = v->value.isNumber();
225 double n = v->value.asNumber();
226 if (double(uint(n)) != n)
229 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected"));
234 bool ok = v->value.isNumber();
236 double n = v->value.asNumber();
237 if (double(int(n)) != n)
240 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected"));
243 case QMetaType::Float:
244 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
246 case QVariant::Double:
247 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
249 case QVariant::Color:
252 QDeclarativeStringConverters::colorFromString(string, &ok);
253 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected"));
256 #ifndef QT_NO_DATESTRING
260 QDeclarativeStringConverters::dateFromString(string, &ok);
261 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected"));
267 QDeclarativeStringConverters::timeFromString(string, &ok);
268 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected"));
271 case QVariant::DateTime:
274 QDeclarativeStringConverters::dateTimeFromString(string, &ok);
275 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected"));
278 #endif // QT_NO_DATESTRING
279 case QVariant::Point:
280 case QVariant::PointF:
283 QPointF point = QDeclarativeStringConverters::pointFFromString(string, &ok);
284 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected"));
288 case QVariant::SizeF:
291 QSizeF size = QDeclarativeStringConverters::sizeFFromString(string, &ok);
292 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected"));
296 case QVariant::RectF:
299 QRectF rect = QDeclarativeStringConverters::rectFFromString(string, &ok);
300 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected"));
305 if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected"));
308 case QVariant::Vector3D:
311 QDeclarativeStringConverters::vector3DFromString(string, &ok);
312 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected"));
317 int t = prop.userType();
318 QDeclarativeMetaType::StringConverter converter =
319 QDeclarativeMetaType::customStringConverter(t);
321 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName(prop.type()))));
329 Generate a store instruction for assigning literal \a v to property \a prop.
331 Any literal assignment that is approved in testLiteralAssignment() must have
332 a corresponding action in this method.
334 void QDeclarativeCompiler::genLiteralAssignment(const QMetaProperty &prop,
335 QDeclarativeParser::Value *v)
337 QDeclarativeInstruction instr;
338 if (prop.isEnumType()) {
340 if (v->value.isNumber()) {
342 value = (int)v->value.asNumber();
345 if (prop.isFlagType()) {
346 value = prop.enumerator().keysToValue(v->value.asString().toUtf8().constData());
348 value = prop.enumerator().keyToValue(v->value.asString().toUtf8().constData());
351 instr.setType(QDeclarativeInstruction::StoreInteger);
352 instr.storeInteger.propertyIndex = prop.propertyIndex();
353 instr.storeInteger.value = value;
354 output->addInstruction(instr);
358 QString string = v->value.asString();
360 int type = prop.userType();
364 if (v->value.isNumber()) {
365 double n = v->value.asNumber();
366 if (double(int(n)) == n) {
367 instr.setType(QDeclarativeInstruction::StoreVariantInteger);
368 instr.storeInteger.propertyIndex = prop.propertyIndex();
369 instr.storeInteger.value = int(n);
371 instr.setType(QDeclarativeInstruction::StoreVariantDouble);
372 instr.storeDouble.propertyIndex = prop.propertyIndex();
373 instr.storeDouble.value = n;
375 } else if(v->value.isBoolean()) {
376 instr.setType(QDeclarativeInstruction::StoreVariantBool);
377 instr.storeBool.propertyIndex = prop.propertyIndex();
378 instr.storeBool.value = v->value.asBoolean();
380 instr.setType(QDeclarativeInstruction::StoreVariant);
381 instr.storeString.propertyIndex = prop.propertyIndex();
382 instr.storeString.value = output->indexForString(string);
386 case QVariant::String:
388 instr.setType(QDeclarativeInstruction::StoreString);
389 instr.storeString.propertyIndex = prop.propertyIndex();
390 instr.storeString.value = output->indexForString(string);
393 case QVariant::ByteArray:
395 instr.setType(QDeclarativeInstruction::StoreByteArray);
396 instr.storeByteArray.propertyIndex = prop.propertyIndex();
397 instr.storeByteArray.value = output->indexForByteArray(string.toLatin1());
402 instr.setType(QDeclarativeInstruction::StoreUrl);
403 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
404 instr.storeUrl.propertyIndex = prop.propertyIndex();
405 instr.storeUrl.value = output->indexForUrl(u);
410 instr.setType(QDeclarativeInstruction::StoreInteger);
411 instr.storeInteger.propertyIndex = prop.propertyIndex();
412 instr.storeInteger.value = uint(v->value.asNumber());
417 instr.setType(QDeclarativeInstruction::StoreInteger);
418 instr.storeInteger.propertyIndex = prop.propertyIndex();
419 instr.storeInteger.value = int(v->value.asNumber());
422 case QMetaType::Float:
424 instr.setType(QDeclarativeInstruction::StoreFloat);
425 instr.storeFloat.propertyIndex = prop.propertyIndex();
426 instr.storeFloat.value = float(v->value.asNumber());
429 case QVariant::Double:
431 instr.setType(QDeclarativeInstruction::StoreDouble);
432 instr.storeDouble.propertyIndex = prop.propertyIndex();
433 instr.storeDouble.value = v->value.asNumber();
436 case QVariant::Color:
438 QColor c = QDeclarativeStringConverters::colorFromString(string);
439 instr.setType(QDeclarativeInstruction::StoreColor);
440 instr.storeColor.propertyIndex = prop.propertyIndex();
441 instr.storeColor.value = c.rgba();
444 #ifndef QT_NO_DATESTRING
447 QDate d = QDeclarativeStringConverters::dateFromString(string);
448 instr.setType(QDeclarativeInstruction::StoreDate);
449 instr.storeDate.propertyIndex = prop.propertyIndex();
450 instr.storeDate.value = d.toJulianDay();
455 QTime time = QDeclarativeStringConverters::timeFromString(string);
456 instr.setType(QDeclarativeInstruction::StoreTime);
457 instr.storeTime.propertyIndex = prop.propertyIndex();
458 Q_ASSERT(sizeof(instr.storeTime.time) == sizeof(QTime));
459 ::memcpy(&instr.storeTime.time, &time, sizeof(QTime));
462 case QVariant::DateTime:
464 QDateTime dateTime = QDeclarativeStringConverters::dateTimeFromString(string);
465 QTime time = dateTime.time();
466 instr.setType(QDeclarativeInstruction::StoreDateTime);
467 instr.storeDateTime.propertyIndex = prop.propertyIndex();
468 instr.storeDateTime.date = dateTime.date().toJulianDay();
469 Q_ASSERT(sizeof(instr.storeDateTime.time) == sizeof(QTime));
470 ::memcmp(&instr.storeDateTime.time, &time, sizeof(QTime));
473 #endif // QT_NO_DATESTRING
474 case QVariant::Point:
477 QPoint point = QDeclarativeStringConverters::pointFFromString(string, &ok).toPoint();
478 instr.setType(QDeclarativeInstruction::StorePoint);
479 instr.storePoint.propertyIndex = prop.propertyIndex();
480 instr.storePoint.point.xp = point.x();
481 instr.storePoint.point.yp = point.y();
484 case QVariant::PointF:
487 QPointF point = QDeclarativeStringConverters::pointFFromString(string, &ok);
488 instr.setType(QDeclarativeInstruction::StorePointF);
489 instr.storePointF.propertyIndex = prop.propertyIndex();
490 instr.storePointF.point.xp = point.x();
491 instr.storePointF.point.yp = point.y();
497 QSize size = QDeclarativeStringConverters::sizeFFromString(string, &ok).toSize();
498 instr.setType(QDeclarativeInstruction::StoreSize);
499 instr.storeSize.propertyIndex = prop.propertyIndex();
500 instr.storeSize.size.wd = size.width();
501 instr.storeSize.size.ht = size.height();
504 case QVariant::SizeF:
507 QSizeF size = QDeclarativeStringConverters::sizeFFromString(string, &ok);
508 instr.setType(QDeclarativeInstruction::StoreSizeF);
509 instr.storeSizeF.propertyIndex = prop.propertyIndex();
510 instr.storeSizeF.size.wd = size.width();
511 instr.storeSizeF.size.ht = size.height();
517 QRect rect = QDeclarativeStringConverters::rectFFromString(string, &ok).toRect();
518 instr.setType(QDeclarativeInstruction::StoreRect);
519 instr.storeRect.propertyIndex = prop.propertyIndex();
520 instr.storeRect.rect.x1 = rect.left();
521 instr.storeRect.rect.y1 = rect.top();
522 instr.storeRect.rect.x2 = rect.right();
523 instr.storeRect.rect.y2 = rect.bottom();
526 case QVariant::RectF:
529 QRectF rect = QDeclarativeStringConverters::rectFFromString(string, &ok);
530 instr.setType(QDeclarativeInstruction::StoreRectF);
531 instr.storeRectF.propertyIndex = prop.propertyIndex();
532 instr.storeRectF.rect.xp = rect.left();
533 instr.storeRectF.rect.yp = rect.top();
534 instr.storeRectF.rect.w = rect.width();
535 instr.storeRectF.rect.h = rect.height();
540 bool b = v->value.asBoolean();
541 instr.setType(QDeclarativeInstruction::StoreBool);
542 instr.storeBool.propertyIndex = prop.propertyIndex();
543 instr.storeBool.value = b;
546 case QVariant::Vector3D:
549 QVector3D vector = QDeclarativeStringConverters::vector3DFromString(string, &ok);
550 instr.setType(QDeclarativeInstruction::StoreVector3D);
551 instr.storeVector3D.propertyIndex = prop.propertyIndex();
552 instr.storeVector3D.vector.xp = vector.x();
553 instr.storeVector3D.vector.yp = vector.y();
554 instr.storeVector3D.vector.zp = vector.z();
559 int t = prop.userType();
560 instr.setType(QDeclarativeInstruction::AssignCustomType);
561 instr.assignCustomType.propertyIndex = prop.propertyIndex();
562 instr.assignCustomType.primitive = output->indexForString(string);
563 instr.assignCustomType.type = t;
567 output->addInstruction(instr);
571 Resets data by clearing the lists that the QDeclarativeCompiler modifies.
573 void QDeclarativeCompiler::reset(QDeclarativeCompiledData *data)
576 data->primitives.clear();
578 data->bytecode.clear();
582 Compile \a unit, and store the output in \a out. \a engine is the QDeclarativeEngine
583 with which the QDeclarativeCompiledData will be associated.
585 Returns true on success, false on failure. On failure, the compile errors
586 are available from errors().
588 If the environment variant QML_COMPILER_DUMP is set
589 (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
590 on a successful compiler.
592 bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine,
593 QDeclarativeTypeData *unit,
594 QDeclarativeCompiledData *out)
604 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
605 QList<QDeclarativeScriptParser::TypeReference *> referencedTypes = unit->parser().referencedTypes();
607 for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
608 QDeclarativeCompiledData::TypeReference ref;
610 const QDeclarativeTypeData::TypeReference &tref = resolvedTypes.at(ii);
611 QDeclarativeScriptParser::TypeReference *parserRef = referencedTypes.at(ii);
614 ref.type = tref.type;
615 if (!ref.type->isCreatable()) {
616 QString err = ref.type->noCreationReason();
618 err = tr( "Element is not creatable.");
619 COMPILE_EXCEPTION(parserRef->refObjects.first(), err);
622 if (ref.type->containsRevisionedAttributes()) {
623 QDeclarativeError cacheError;
624 ref.typePropertyCache =
625 QDeclarativeEnginePrivate::get(engine)->cache(ref.type, resolvedTypes.at(ii).minorVersion, cacheError);
627 if (!ref.typePropertyCache) {
628 COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description());
630 ref.typePropertyCache->addref();
633 } else if (tref.typeData) {
634 ref.component = tref.typeData->compiledData();
636 ref.className = parserRef->name.toUtf8();
640 QDeclarativeParser::Object *root = unit->parser().tree();
643 this->engine = engine;
644 this->enginePrivate = QDeclarativeEnginePrivate::get(engine);
646 this->unitRoot = root;
651 out->dumpInstructions();
652 if (compilerStatDump())
654 Q_ASSERT(out->rootPropertyCache);
659 compileState = ComponentCompileState();
660 savedCompileStates.clear();
663 this->enginePrivate = 0;
670 void QDeclarativeCompiler::compileTree(QDeclarativeParser::Object *tree)
672 compileState.root = tree;
673 componentStat.lineNumber = tree->location.start.line;
675 // Build global import scripts
676 QStringList importedScriptIndexes;
678 foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
679 importedScriptIndexes.append(script.qualifier);
681 QDeclarativeInstruction import;
682 import.setType(QDeclarativeInstruction::StoreImportedScript);
683 import.storeScript.value = output->scripts.count();
685 QDeclarativeScriptData *scriptData = script.script->scriptData();
686 scriptData->addref();
687 output->scripts << scriptData;
688 output->addInstruction(import);
691 // We generate the importCache before we build the tree so that
692 // it can be used in the binding compiler. Given we "expect" the
693 // QML compilation to succeed, this isn't a waste.
694 output->importCache = new QDeclarativeTypeNameCache(engine);
695 for (int ii = 0; ii < importedScriptIndexes.count(); ++ii)
696 output->importCache->add(importedScriptIndexes.at(ii), ii);
697 unit->imports().populateCache(output->importCache, engine);
699 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
702 QDeclarativeInstruction init;
703 init.setType(QDeclarativeInstruction::Init);
704 init.init.bindingsSize = compileState.bindings.count();
705 init.init.parserStatusSize = compileState.parserStatusCount;
706 init.init.contextCache = genContextCache();
707 if (compileState.compiledBindingData.isEmpty())
708 init.init.compiledBinding = -1;
710 init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData);
711 output->addInstruction(init);
713 if (!compileState.v8BindingProgram.isEmpty()) {
714 QDeclarativeInstruction bindings;
715 bindings.setType(QDeclarativeInstruction::InitV8Bindings);
716 bindings.initV8Bindings.program = output->indexForString(compileState.v8BindingProgram);
717 bindings.initV8Bindings.programIndex = compileState.v8BindingProgramIndex;
718 bindings.initV8Bindings.line = compileState.v8BindingProgramLine;
719 output->addInstruction(bindings);
724 QDeclarativeInstruction def;
725 def.setType(QDeclarativeInstruction::SetDefault);
726 output->addInstruction(def);
728 QDeclarativeInstruction done;
729 done.setType(QDeclarativeInstruction::Done);
730 output->addInstruction(done);
732 Q_ASSERT(tree->metatype);
734 if (tree->metadata.isEmpty()) {
735 output->root = tree->metatype;
737 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
738 output->root = &output->rootData;
740 if (!tree->metadata.isEmpty())
741 enginePrivate->registerCompositeType(output);
744 static bool ValuePtrLessThan(const QDeclarativeParser::Value *t1, const QDeclarativeParser::Value *t2)
746 return t1->location.start.line < t2->location.start.line ||
747 (t1->location.start.line == t2->location.start.line &&
748 t1->location.start.column < t2->location.start.column);
751 bool QDeclarativeCompiler::buildObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
753 componentStat.objects++;
755 Q_ASSERT (obj->type != -1);
756 const QDeclarativeCompiledData::TypeReference &tr =
757 output->types.at(obj->type);
758 obj->metatype = tr.metaObject();
761 obj->typeName = tr.type->qmlTypeName();
762 obj->className = tr.className;
764 // This object is a "Component" element
765 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
766 COMPILE_CHECK(buildComponent(obj, ctxt));
770 // Object instantiations reset the binding context
771 BindingContext objCtxt(obj);
773 // Create the synthesized meta object, ignoring aliases
774 COMPILE_CHECK(checkDynamicMeta(obj));
775 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
776 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
778 // Find the native type and check for the QDeclarativeParserStatus interface
779 QDeclarativeType *type = toQmlType(obj);
781 obj->parserStatusCast = type->parserStatusCast();
782 if (obj->parserStatusCast != -1)
783 compileState.parserStatusCount++;
785 // Check if this is a custom parser type. Custom parser types allow
786 // assignments to non-existent properties. These assignments are then
787 // compiled by the type.
788 bool isCustomParser = output->types.at(obj->type).type &&
789 output->types.at(obj->type).type->customParser() != 0;
790 QList<QDeclarativeCustomParserProperty> customProps;
792 // Fetch the list of deferred properties
793 QStringList deferredList = deferredProperties(obj);
795 // Must do id property first. This is to ensure that the id given to any
796 // id reference created matches the order in which the objects are
798 foreach(Property *prop, obj->properties) {
799 if (prop->name == "id") {
800 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
806 Property *defaultProperty = 0;
807 Property *skipProperty = 0;
808 if (obj->defaultProperty) {
809 const QMetaObject *metaObject = obj->metaObject();
810 Q_ASSERT(metaObject);
811 QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
813 Property *explicitProperty = obj->getProperty(p.name(), false);
814 if (explicitProperty && !explicitProperty->value) {
815 skipProperty = explicitProperty;
817 defaultProperty = new Property;
818 defaultProperty->parent = obj;
819 defaultProperty->isDefault = true;
820 defaultProperty->location = obj->defaultProperty->location;
821 defaultProperty->listValueRange = obj->defaultProperty->listValueRange;
823 defaultProperty->values = obj->defaultProperty->values;
824 defaultProperty->values += explicitProperty->values;
825 foreach(QDeclarativeParser::Value *value, defaultProperty->values)
827 qSort(defaultProperty->values.begin(), defaultProperty->values.end(), ValuePtrLessThan);
830 defaultProperty = obj->defaultProperty;
831 defaultProperty->addref();
834 defaultProperty = obj->defaultProperty;
835 defaultProperty->addref();
839 QDeclarativeCustomParser *cp = 0;
841 cp = output->types.at(obj->type).type->customParser();
843 // Build all explicit properties specified
844 foreach(Property *prop, obj->properties) {
846 if (prop == skipProperty)
848 if (prop->name == "id")
851 bool canDefer = false;
852 if (isCustomParser) {
853 if (doesPropertyExist(prop, obj) &&
854 (!(cp->flags() & QDeclarativeCustomParser::AcceptsAttachedProperties) ||
855 !isAttachedPropertyName(prop->name))) {
856 int ids = compileState.ids.count();
857 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
858 canDefer = ids == compileState.ids.count();
860 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
863 if (isSignalPropertyName(prop->name)) {
864 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
866 int ids = compileState.ids.count();
867 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
868 canDefer = ids == compileState.ids.count();
872 if (canDefer && !deferredList.isEmpty() &&
873 deferredList.contains(QString::fromUtf8(prop->name)))
874 prop->isDeferred = true;
878 // Build the default property
879 if (defaultProperty) {
880 Property *prop = defaultProperty;
882 bool canDefer = false;
883 if (isCustomParser) {
884 if (doesPropertyExist(prop, obj)) {
885 int ids = compileState.ids.count();
886 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
887 canDefer = ids == compileState.ids.count();
889 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
892 int ids = compileState.ids.count();
893 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
894 canDefer = ids == compileState.ids.count();
897 if (canDefer && !deferredList.isEmpty() &&
898 deferredList.contains(QString::fromUtf8(prop->name)))
899 prop->isDeferred = true;
903 defaultProperty->release();
905 // Compile custom parser parts
906 if (isCustomParser && !customProps.isEmpty()) {
910 obj->custom = cp->compile(customProps);
913 foreach (QDeclarativeError err, cp->errors()) {
914 err.setUrl(output->url);
922 void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj)
924 QDeclarativeCompiledData::TypeReference &tr = output->types[obj->type];
925 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
931 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
932 !output->types.at(obj->type).type->isExtendedType() && obj != compileState.root) {
934 QDeclarativeInstruction create;
935 create.setType(QDeclarativeInstruction::CreateSimpleObject);
936 create.createSimple.create = output->types.at(obj->type).type->createFunction();
937 create.createSimple.typeSize = output->types.at(obj->type).type->createSize();
938 create.createSimple.type = obj->type;
939 create.createSimple.line = obj->location.start.line;
940 create.createSimple.column = obj->location.start.column;
941 output->addInstruction(create);
945 QDeclarativeInstruction create;
946 create.setType(QDeclarativeInstruction::CreateObject);
947 create.create.line = obj->location.start.line;
948 create.create.column = obj->location.start.column;
949 create.create.data = -1;
950 if (!obj->custom.isEmpty())
951 create.create.data = output->indexForByteArray(obj->custom);
952 create.create.type = obj->type;
953 if (!output->types.at(create.create.type).type &&
954 !obj->bindingBitmask.isEmpty()) {
955 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
956 create.create.bindingBits =
957 output->indexForByteArray(obj->bindingBitmask);
959 create.create.bindingBits = -1;
961 output->addInstruction(create);
965 // Setup the synthesized meta object if necessary
966 if (!obj->metadata.isEmpty()) {
967 QDeclarativeInstruction meta;
968 meta.setType(QDeclarativeInstruction::StoreMetaObject);
969 meta.storeMeta.data = output->indexForByteArray(obj->metadata);
970 meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata);
971 meta.storeMeta.propertyCache = output->propertyCaches.count();
973 QDeclarativePropertyCache *propertyCache = obj->synthCache;
974 Q_ASSERT(propertyCache);
975 propertyCache->addref();
977 // Add flag for alias properties
978 if (!obj->synthdata.isEmpty()) {
979 const QDeclarativeVMEMetaData *vmeMetaData =
980 reinterpret_cast<const QDeclarativeVMEMetaData *>(obj->synthdata.constData());
981 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
982 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
983 QDeclarativePropertyCache::Data *data = propertyCache->property(index);
984 data->setFlags(data->getFlags() | QDeclarativePropertyCache::Data::IsAlias);
988 if (obj == unitRoot) {
989 propertyCache->addref();
990 output->rootPropertyCache = propertyCache;
993 output->propertyCaches << propertyCache;
994 output->addInstruction(meta);
995 } else if (obj == unitRoot) {
996 output->rootPropertyCache = tr.createPropertyCache(engine);
997 output->rootPropertyCache->addref();
1000 // Set the object id
1001 if (!obj->id.isEmpty()) {
1002 QDeclarativeInstruction id;
1003 id.setType(QDeclarativeInstruction::SetId);
1004 id.setId.value = output->indexForString(obj->id);
1005 id.setId.index = obj->idIndex;
1006 output->addInstruction(id);
1010 if (tr.type && obj->parserStatusCast != -1) {
1011 QDeclarativeInstruction begin;
1012 begin.setType(QDeclarativeInstruction::BeginObject);
1013 begin.begin.castValue = obj->parserStatusCast;
1014 output->addInstruction(begin);
1020 void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj)
1022 typedef QPair<Property *, int> PropPair;
1023 foreach(const PropPair &prop, obj->scriptStringProperties) {
1024 const QString &script = prop.first->values.at(0)->value.asScript();
1025 QDeclarativeInstruction ss;
1026 ss.setType(QDeclarativeInstruction::StoreScriptString);
1027 ss.storeScriptString.propertyIndex = prop.first->index;
1028 ss.storeScriptString.value = output->indexForString(script);
1029 ss.storeScriptString.scope = prop.second;
1030 ss.storeScriptString.bindingId = rewriteBinding(script, prop.first->name);
1031 ss.storeScriptString.line = prop.first->location.start.line;
1032 output->addInstruction(ss);
1035 bool seenDefer = false;
1036 foreach(Property *prop, obj->valueProperties) {
1037 if (prop->isDeferred) {
1042 genValueProperty(prop, obj);
1045 QDeclarativeInstruction defer;
1046 defer.setType(QDeclarativeInstruction::Defer);
1047 defer.defer.deferCount = 0;
1048 int deferIdx = output->addInstruction(defer);
1049 int nextInstructionIndex = output->nextInstructionIndex();
1051 QDeclarativeInstruction init;
1052 init.setType(QDeclarativeInstruction::Init);
1053 init.init.bindingsSize = compileState.bindings.count(); // XXX - bigger than necessary
1054 init.init.parserStatusSize = compileState.parserStatusCount; // XXX - bigger than necessary
1055 init.init.contextCache = -1;
1056 init.init.compiledBinding = -1;
1057 output->addInstruction(init);
1059 foreach(Property *prop, obj->valueProperties) {
1060 if (!prop->isDeferred)
1062 genValueProperty(prop, obj);
1065 QDeclarativeInstruction done;
1066 done.setType(QDeclarativeInstruction::Done);
1067 output->addInstruction(done);
1069 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1072 foreach(Property *prop, obj->signalProperties) {
1074 QDeclarativeParser::Value *v = prop->values.at(0);
1076 if (v->type == Value::SignalObject) {
1078 genObject(v->object);
1080 QDeclarativeInstruction assign;
1081 assign.setType(QDeclarativeInstruction::AssignSignalObject);
1082 assign.assignSignalObject.line = v->location.start.line;
1083 assign.assignSignalObject.signal =
1084 output->indexForByteArray(prop->name);
1085 output->addInstruction(assign);
1087 } else if (v->type == Value::SignalExpression) {
1089 BindingContext ctxt = compileState.signalExpressions.value(v);
1091 QDeclarativeInstruction store;
1092 store.setType(QDeclarativeInstruction::StoreSignal);
1093 store.storeSignal.signalIndex = prop->index;
1094 store.storeSignal.value =
1095 output->indexForString(v->value.asScript().trimmed());
1096 store.storeSignal.context = ctxt.stack;
1097 store.storeSignal.name = output->indexForByteArray(prop->name);
1098 store.storeSignal.line = v->location.start.line;
1099 output->addInstruction(store);
1105 foreach(Property *prop, obj->attachedProperties) {
1106 QDeclarativeInstruction fetch;
1107 fetch.setType(QDeclarativeInstruction::FetchAttached);
1108 fetch.fetchAttached.id = prop->index;
1109 fetch.fetchAttached.line = prop->location.start.line;
1110 output->addInstruction(fetch);
1112 genObjectBody(prop->value);
1114 QDeclarativeInstruction pop;
1115 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1116 output->addInstruction(pop);
1119 foreach(Property *prop, obj->groupedProperties) {
1120 QDeclarativeInstruction fetch;
1121 fetch.setType(QDeclarativeInstruction::FetchObject);
1122 fetch.fetch.property = prop->index;
1123 fetch.fetch.line = prop->location.start.line;
1124 output->addInstruction(fetch);
1126 if (!prop->value->metadata.isEmpty()) {
1127 QDeclarativeInstruction meta;
1128 meta.setType(QDeclarativeInstruction::StoreMetaObject);
1129 meta.storeMeta.data = output->indexForByteArray(prop->value->metadata);
1130 meta.storeMeta.aliasData = output->indexForByteArray(prop->value->synthdata);
1131 meta.storeMeta.propertyCache = -1;
1132 output->addInstruction(meta);
1135 genObjectBody(prop->value);
1137 QDeclarativeInstruction pop;
1138 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1139 output->addInstruction(pop);
1142 foreach(Property *prop, obj->valueTypeProperties) {
1144 genValueTypeProperty(obj, prop);
1147 foreach(Property *prop, obj->valueProperties) {
1148 if (prop->isDeferred)
1151 genValueProperty(prop, obj);
1154 foreach(Property *prop, obj->valueTypeProperties) {
1156 genValueTypeProperty(obj, prop);
1160 void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeParser::Object *obj,QDeclarativeParser::Property *prop)
1162 QDeclarativeInstruction fetch;
1163 fetch.setType(QDeclarativeInstruction::FetchValueType);
1164 fetch.fetchValue.property = prop->index;
1165 fetch.fetchValue.type = prop->type;
1166 fetch.fetchValue.bindingSkipList = 0;
1168 if (obj->type == -1 || output->types.at(obj->type).component) {
1169 // We only have to do this if this is a composite type. If it is a builtin
1170 // type it can't possibly already have bindings that need to be cleared.
1171 foreach(Property *vprop, prop->value->valueProperties) {
1172 if (!vprop->values.isEmpty()) {
1173 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1174 fetch.fetchValue.bindingSkipList |= (1 << vprop->index);
1179 output->addInstruction(fetch);
1181 foreach(Property *vprop, prop->value->valueProperties) {
1182 genPropertyAssignment(vprop, prop->value, prop);
1185 QDeclarativeInstruction pop;
1186 pop.setType(QDeclarativeInstruction::PopValueType);
1187 pop.fetchValue.property = prop->index;
1188 pop.fetchValue.type = prop->type;
1189 pop.fetchValue.bindingSkipList = 0;
1190 output->addInstruction(pop);
1193 void QDeclarativeCompiler::genComponent(QDeclarativeParser::Object *obj)
1195 QDeclarativeParser::Object *root = obj->defaultProperty->values.at(0)->object;
1198 QDeclarativeInstruction create;
1199 create.setType(QDeclarativeInstruction::CreateComponent);
1200 create.createComponent.line = root->location.start.line;
1201 create.createComponent.column = root->location.start.column;
1202 create.createComponent.endLine = root->location.end.line;
1203 int createInstruction = output->addInstruction(create);
1204 int nextInstructionIndex = output->nextInstructionIndex();
1206 ComponentCompileState oldCompileState = compileState;
1207 compileState = componentState(root);
1209 QDeclarativeInstruction init;
1210 init.setType(QDeclarativeInstruction::Init);
1211 init.init.bindingsSize = compileState.bindings.count();
1212 init.init.parserStatusSize = compileState.parserStatusCount;
1213 init.init.contextCache = genContextCache();
1214 if (compileState.compiledBindingData.isEmpty())
1215 init.init.compiledBinding = -1;
1217 init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData);
1218 output->addInstruction(init);
1220 if (!compileState.v8BindingProgram.isEmpty()) {
1221 QDeclarativeInstruction bindings;
1222 bindings.setType(QDeclarativeInstruction::InitV8Bindings);
1223 bindings.initV8Bindings.program = output->indexForString(compileState.v8BindingProgram);
1224 bindings.initV8Bindings.programIndex = compileState.v8BindingProgramIndex;
1225 bindings.initV8Bindings.line = compileState.v8BindingProgramLine;
1226 output->addInstruction(bindings);
1231 QDeclarativeInstruction def;
1232 def.setType(QDeclarativeInstruction::SetDefault);
1233 output->addInstruction(def);
1235 QDeclarativeInstruction done;
1236 done.setType(QDeclarativeInstruction::Done);
1237 output->addInstruction(done);
1239 output->instruction(createInstruction)->createComponent.count =
1240 output->nextInstructionIndex() - nextInstructionIndex;
1242 compileState = oldCompileState;
1244 if (!obj->id.isEmpty()) {
1245 QDeclarativeInstruction id;
1246 id.setType(QDeclarativeInstruction::SetId);
1247 id.setId.value = output->indexForString(obj->id);
1248 id.setId.index = obj->idIndex;
1249 output->addInstruction(id);
1252 if (obj == unitRoot) {
1253 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1254 output->rootPropertyCache->addref();
1258 bool QDeclarativeCompiler::buildComponent(QDeclarativeParser::Object *obj,
1259 const BindingContext &ctxt)
1261 // The special "Component" element can only have the id property and a
1262 // default property, that actually defines the component's tree
1264 // Find, check and set the "id" property (if any)
1265 Property *idProp = 0;
1266 if (obj->properties.count() > 1 ||
1267 (obj->properties.count() == 1 && obj->properties.begin().key() != "id"))
1268 COMPILE_EXCEPTION(*obj->properties.begin(), tr("Component elements may not contain properties other than id"));
1270 if (obj->properties.count())
1271 idProp = *obj->properties.begin();
1274 if (idProp->value || idProp->values.count() > 1 || idProp->values.at(0)->object)
1275 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1276 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1278 QString idVal = idProp->values.first()->primitive();
1280 if (compileState.ids.contains(idVal))
1281 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1287 // Check the Component tree is well formed
1288 if (obj->defaultProperty &&
1289 (obj->defaultProperty->value || obj->defaultProperty->values.count() > 1 ||
1290 (obj->defaultProperty->values.count() == 1 && !obj->defaultProperty->values.first()->object)))
1291 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1293 if (!obj->dynamicProperties.isEmpty())
1294 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1295 if (!obj->dynamicSignals.isEmpty())
1296 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1297 if (!obj->dynamicSlots.isEmpty())
1298 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1300 QDeclarativeParser::Object *root = 0;
1301 if (obj->defaultProperty && obj->defaultProperty->values.count())
1302 root = obj->defaultProperty->values.first()->object;
1305 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1307 // Build the component tree
1308 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1313 bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeParser::Object *obj,
1314 const BindingContext &ctxt)
1316 ComponentCompileState oldComponentCompileState = compileState;
1317 ComponentStat oldComponentStat = componentStat;
1319 compileState = ComponentCompileState();
1320 compileState.root = obj;
1321 compileState.nested = true;
1323 componentStat = ComponentStat();
1324 componentStat.lineNumber = obj->location.start.line;
1327 COMPILE_CHECK(buildObject(obj, ctxt));
1329 COMPILE_CHECK(completeComponentBuild());
1331 compileState = oldComponentCompileState;
1332 componentStat = oldComponentStat;
1338 // Build a sub-object. A sub-object is one that was not created directly by
1339 // QML - such as a grouped property object, or an attached object. Sub-object's
1340 // can't have an id, involve a custom parser, have attached properties etc.
1341 bool QDeclarativeCompiler::buildSubObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
1343 Q_ASSERT(obj->metatype);
1344 Q_ASSERT(!obj->defaultProperty);
1345 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1348 foreach(Property *prop, obj->properties) {
1349 if (isSignalPropertyName(prop->name)) {
1350 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1352 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1359 int QDeclarativeCompiler::componentTypeRef()
1361 QDeclarativeType *t = QDeclarativeMetaType::qmlType("QtQuick/Component",2,0);
1362 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1363 if (output->types.at(ii).type == t)
1366 QDeclarativeCompiledData::TypeReference ref;
1367 ref.className = "Component";
1369 output->types << ref;
1370 return output->types.count() - 1;
1373 bool QDeclarativeCompiler::buildSignal(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj,
1374 const BindingContext &ctxt)
1376 Q_ASSERT(obj->metaObject());
1378 QByteArray name = prop->name;
1379 Q_ASSERT(name.startsWith("on"));
1382 // Note that the property name could start with any alpha or '_' or '$' character,
1383 // so we need to do the lower-casing of the first alpha character.
1384 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1385 if (name[firstAlphaIndex] >= 'A' && name[firstAlphaIndex] <= 'Z') {
1386 name[firstAlphaIndex] = name[firstAlphaIndex] - 'A' + 'a';
1391 bool notInRevision = false;
1392 int sigIdx = indexOfSignal(obj, name, ¬InRevision);
1396 if (notInRevision && -1 == indexOfProperty(obj, prop->name, 0)) {
1397 Q_ASSERT(obj->type != -1);
1398 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1399 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1401 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));
1403 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)));
1407 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1409 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1413 if (prop->value || prop->values.count() != 1)
1414 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1416 prop->index = sigIdx;
1417 obj->addSignalProperty(prop);
1419 if (prop->values.at(0)->object) {
1420 COMPILE_CHECK(buildObject(prop->values.at(0)->object, ctxt));
1421 prop->values.at(0)->type = Value::SignalObject;
1423 prop->values.at(0)->type = Value::SignalExpression;
1425 if (!prop->values.at(0)->value.isScript())
1426 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1428 QString script = prop->values.at(0)->value.asScript().trimmed();
1429 if (script.isEmpty())
1430 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1432 compileState.signalExpressions.insert(prop->values.at(0), ctxt);
1441 Returns true if (value) property \a prop exists on obj, false otherwise.
1443 bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeParser::Property *prop,
1444 QDeclarativeParser::Object *obj)
1446 if(isAttachedPropertyName(prop->name) || prop->name == "id")
1449 const QMetaObject *mo = obj->metaObject();
1451 if (prop->isDefault) {
1452 QMetaProperty p = QDeclarativeMetaType::defaultProperty(mo);
1453 return p.name() != 0;
1455 int idx = indexOfProperty(obj, prop->name);
1456 return idx != -1 && mo->property(idx).isScriptable();
1463 bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop,
1464 QDeclarativeParser::Object *obj,
1465 const BindingContext &ctxt)
1467 if (prop->isEmpty())
1468 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1470 const QMetaObject *metaObject = obj->metaObject();
1471 Q_ASSERT(metaObject);
1473 if (isAttachedPropertyName(prop->name)) {
1474 // Setup attached property data
1476 if (ctxt.isSubContext()) {
1477 // Attached properties cannot be used on sub-objects. Sub-objects
1478 // always exist in a binding sub-context, which is what we test
1480 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1483 QDeclarativeType *type = 0;
1484 QDeclarativeImportedNamespace *typeNamespace = 0;
1485 unit->imports().resolveType(prop->name, &type, 0, 0, 0, &typeNamespace);
1487 if (typeNamespace) {
1488 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1491 } else if (!type || !type->attachedPropertiesType()) {
1492 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1496 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1498 Q_ASSERT(type->attachedPropertiesFunction());
1499 prop->index = type->attachedPropertiesId();
1500 prop->value->metatype = type->attachedPropertiesType();
1502 // Setup regular property data
1505 if (prop->isDefault) {
1506 p = QDeclarativeMetaType::defaultProperty(metaObject);
1509 prop->index = p.propertyIndex();
1510 prop->name = p.name();
1514 bool notInRevision = false;
1515 prop->index = indexOfProperty(obj, prop->name, ¬InRevision);
1516 if (prop->index == -1 && notInRevision) {
1517 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1518 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1520 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));
1522 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)));
1526 if (prop->index != -1) {
1527 p = metaObject->property(prop->index);
1530 if (!p.isScriptable()) {
1532 p = QMetaProperty();
1537 // We can't error here as the "id" property does not require a
1538 // successful index resolution
1540 prop->type = p.userType();
1542 // Check if this is an alias
1543 if (prop->index != -1 &&
1545 prop->parent->type != -1 &&
1546 output->types.at(prop->parent->type).component) {
1548 QDeclarativePropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1549 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1550 prop->isAlias = true;
1553 if (prop->index != -1 && !prop->values.isEmpty())
1554 prop->parent->setBindingBit(prop->index);
1557 if (!prop->isDefault && prop->name == "id" && !ctxt.isSubContext()) {
1559 // The magic "id" behavior doesn't apply when "id" is resolved as a
1560 // default property or to sub-objects (which are always in binding
1562 COMPILE_CHECK(buildIdProperty(prop, obj));
1563 if (prop->type == QVariant::String &&
1564 prop->values.at(0)->value.isString())
1565 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1567 } else if (isAttachedPropertyName(prop->name)) {
1569 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1571 } else if (prop->index == -1) {
1573 if (prop->isDefault) {
1574 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1576 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1579 } else if (prop->value) {
1581 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1583 } else if (enginePrivate->isList(prop->type)) {
1585 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1587 } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) {
1589 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1593 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1600 bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
1601 QDeclarativeParser::Property *nsProp,
1602 QDeclarativeParser::Object *obj,
1603 const BindingContext &ctxt)
1606 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1608 foreach (Property *prop, nsProp->value->properties) {
1610 if (!isAttachedPropertyName(prop->name))
1611 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1613 // Setup attached property data
1615 QDeclarativeType *type = 0;
1616 unit->imports().resolveType(ns, prop->name, &type, 0, 0, 0);
1618 if (!type || !type->attachedPropertiesType())
1619 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1622 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1624 Q_ASSERT(type->attachedPropertiesFunction());
1625 prop->index = type->index();
1626 prop->value->metatype = type->attachedPropertiesType();
1628 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1634 void QDeclarativeCompiler::genValueProperty(QDeclarativeParser::Property *prop,
1635 QDeclarativeParser::Object *obj)
1637 if (enginePrivate->isList(prop->type)) {
1638 genListProperty(prop, obj);
1640 genPropertyAssignment(prop, obj);
1644 void QDeclarativeCompiler::genListProperty(QDeclarativeParser::Property *prop,
1645 QDeclarativeParser::Object *obj)
1647 int listType = enginePrivate->listType(prop->type);
1649 QDeclarativeInstruction fetch;
1650 fetch.setType(QDeclarativeInstruction::FetchQList);
1651 fetch.fetchQmlList.property = prop->index;
1652 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1653 fetch.fetchQmlList.type = listType;
1654 output->addInstruction(fetch);
1656 for (int ii = 0; ii < prop->values.count(); ++ii) {
1657 QDeclarativeParser::Value *v = prop->values.at(ii);
1659 if (v->type == Value::CreatedObject) {
1661 genObject(v->object);
1662 if (listTypeIsInterface) {
1663 QDeclarativeInstruction assign;
1664 assign.setType(QDeclarativeInstruction::AssignObjectList);
1665 assign.assignObjectList.line = prop->location.start.line;
1666 output->addInstruction(assign);
1668 QDeclarativeInstruction store;
1669 store.setType(QDeclarativeInstruction::StoreObjectQList);
1670 output->addInstruction(store);
1673 } else if (v->type == Value::PropertyBinding) {
1675 genBindingAssignment(v, prop, obj);
1681 QDeclarativeInstruction pop;
1682 pop.setType(QDeclarativeInstruction::PopQList);
1683 output->addInstruction(pop);
1686 void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *prop,
1687 QDeclarativeParser::Object *obj,
1688 QDeclarativeParser::Property *valueTypeProperty)
1690 for (int ii = 0; ii < prop->values.count(); ++ii) {
1691 QDeclarativeParser::Value *v = prop->values.at(ii);
1693 Q_ASSERT(v->type == Value::CreatedObject ||
1694 v->type == Value::PropertyBinding ||
1695 v->type == Value::Literal);
1697 if (v->type == Value::CreatedObject) {
1699 genObject(v->object);
1701 if (QDeclarativeMetaType::isInterface(prop->type)) {
1703 QDeclarativeInstruction store;
1704 store.setType(QDeclarativeInstruction::StoreInterface);
1705 store.storeObject.line = v->object->location.start.line;
1706 store.storeObject.propertyIndex = prop->index;
1707 output->addInstruction(store);
1709 } else if (prop->type == -1) {
1711 QDeclarativeInstruction store;
1712 store.setType(QDeclarativeInstruction::StoreVariantObject);
1713 store.storeObject.line = v->object->location.start.line;
1714 store.storeObject.propertyIndex = prop->index;
1715 output->addInstruction(store);
1719 QDeclarativeInstruction store;
1720 store.setType(QDeclarativeInstruction::StoreObject);
1721 store.storeObject.line = v->object->location.start.line;
1722 store.storeObject.propertyIndex = prop->index;
1723 output->addInstruction(store);
1726 } else if (v->type == Value::PropertyBinding) {
1728 genBindingAssignment(v, prop, obj, valueTypeProperty);
1730 } else if (v->type == Value::Literal) {
1732 QMetaProperty mp = obj->metaObject()->property(prop->index);
1733 genLiteralAssignment(mp, v);
1739 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
1741 QDeclarativeParser::Value *v = prop->onValues.at(ii);
1743 Q_ASSERT(v->type == Value::ValueSource ||
1744 v->type == Value::ValueInterceptor);
1746 if (v->type == Value::ValueSource) {
1747 genObject(v->object);
1749 QDeclarativeInstruction store;
1750 store.setType(QDeclarativeInstruction::StoreValueSource);
1751 if (valueTypeProperty) {
1752 store.assignValueSource.property = genValueTypeData(prop, valueTypeProperty);
1753 store.assignValueSource.owner = 1;
1755 store.assignValueSource.property = genPropertyData(prop);
1756 store.assignValueSource.owner = 0;
1758 QDeclarativeType *valueType = toQmlType(v->object);
1759 store.assignValueSource.castValue = valueType->propertyValueSourceCast();
1760 output->addInstruction(store);
1762 } else if (v->type == Value::ValueInterceptor) {
1763 genObject(v->object);
1765 QDeclarativeInstruction store;
1766 store.setType(QDeclarativeInstruction::StoreValueInterceptor);
1767 if (valueTypeProperty) {
1768 store.assignValueInterceptor.property = genValueTypeData(prop, valueTypeProperty);
1769 store.assignValueInterceptor.owner = 1;
1771 store.assignValueInterceptor.property = genPropertyData(prop);
1772 store.assignValueInterceptor.owner = 0;
1774 QDeclarativeType *valueType = toQmlType(v->object);
1775 store.assignValueInterceptor.castValue = valueType->propertyValueInterceptorCast();
1776 output->addInstruction(store);
1782 bool QDeclarativeCompiler::buildIdProperty(QDeclarativeParser::Property *prop,
1783 QDeclarativeParser::Object *obj)
1786 prop->values.count() > 1 ||
1787 prop->values.at(0)->object)
1788 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
1790 QDeclarativeParser::Value *idValue = prop->values.at(0);
1791 QString val = idValue->primitive();
1793 COMPILE_CHECK(checkValidId(idValue, val));
1795 if (compileState.ids.contains(val))
1796 COMPILE_EXCEPTION(prop, tr("id is not unique"));
1798 prop->values.at(0)->type = Value::Id;
1806 void QDeclarativeCompiler::addId(const QString &id, QDeclarativeParser::Object *obj)
1808 Q_ASSERT(!compileState.ids.contains(id));
1809 Q_ASSERT(obj->id == id);
1810 obj->idIndex = compileState.ids.count();
1811 compileState.ids.insert(id, obj);
1812 compileState.idIndexes.insert(obj->idIndex, obj);
1815 void QDeclarativeCompiler::addBindingReference(const BindingReference &ref)
1817 Q_ASSERT(ref.value && !compileState.bindings.contains(ref.value));
1818 compileState.bindings.insert(ref.value, ref);
1821 void QDeclarativeCompiler::saveComponentState()
1823 Q_ASSERT(compileState.root);
1824 Q_ASSERT(!savedCompileStates.contains(compileState.root));
1826 savedCompileStates.insert(compileState.root, compileState);
1827 savedComponentStats.append(componentStat);
1830 QDeclarativeCompiler::ComponentCompileState
1831 QDeclarativeCompiler::componentState(QDeclarativeParser::Object *obj)
1833 Q_ASSERT(savedCompileStates.contains(obj));
1834 return savedCompileStates.value(obj);
1837 // Build attached property object. In this example,
1841 // GridView is an attached property object.
1842 bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeParser::Property *prop,
1843 QDeclarativeParser::Object *obj,
1844 const BindingContext &ctxt)
1846 Q_ASSERT(prop->value);
1847 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
1849 obj->addAttachedProperty(prop);
1851 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1857 // Build "grouped" properties. In this example:
1859 // font.pointSize: 12
1860 // font.family: "Helvetica"
1862 // font is a nested property. pointSize and family are not.
1863 bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeParser::Property *prop,
1864 QDeclarativeParser::Object *obj,
1865 const BindingContext &ctxt)
1867 Q_ASSERT(prop->type != 0);
1868 Q_ASSERT(prop->index != -1);
1870 if (QDeclarativeValueTypeFactory::isValueType(prop->type)) {
1871 if (prop->type >= 0 /* QVariant == -1 */ && enginePrivate->valueTypes[prop->type]) {
1873 if (prop->values.count()) {
1874 if (prop->values.at(0)->location < prop->value->location) {
1875 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
1877 COMPILE_EXCEPTION(prop->values.at(0), tr( "Property has already been assigned a value"));
1881 if (!obj->metaObject()->property(prop->index).isWritable()) {
1882 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
1886 if (prop->isAlias) {
1887 foreach (Property *vtProp, prop->value->properties)
1888 vtProp->isAlias = true;
1891 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
1892 prop->value, obj, ctxt.incr()));
1893 obj->addValueTypeProperty(prop);
1895 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1899 // Load the nested property's meta type
1900 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
1901 if (!prop->value->metatype)
1902 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1904 if (prop->values.count())
1905 COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign a value directly to a grouped property"));
1907 obj->addGroupedProperty(prop);
1909 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1915 bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
1916 QDeclarativeParser::Object *obj,
1917 QDeclarativeParser::Object *baseObj,
1918 const BindingContext &ctxt)
1920 if (obj->defaultProperty)
1921 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
1922 obj->metatype = type->metaObject();
1924 foreach (Property *prop, obj->properties) {
1925 int idx = type->metaObject()->indexOfProperty(prop->name.constData());
1927 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1928 QMetaProperty p = type->metaObject()->property(idx);
1929 if (!p.isScriptable())
1930 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1932 prop->type = p.userType();
1933 prop->isValueTypeSubProperty = true;
1936 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
1938 if (prop->values.count() > 1) {
1939 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
1940 } else if (prop->values.count()) {
1941 QDeclarativeParser::Value *value = prop->values.at(0);
1943 if (value->object) {
1944 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
1945 } else if (value->value.isScript()) {
1946 // ### Check for writability
1948 //optimization for <Type>.<EnumValue> enum assignments
1949 bool isEnumAssignment = false;
1950 COMPILE_CHECK(testQualifiedEnumAssignment(p, obj, value, &isEnumAssignment));
1951 if (isEnumAssignment) {
1952 value->type = Value::Literal;
1954 BindingReference reference;
1955 reference.expression = value->value;
1956 reference.property = prop;
1957 reference.value = value;
1958 reference.bindingContext = ctxt;
1959 reference.bindingContext.owner++;
1960 addBindingReference(reference);
1961 value->type = Value::PropertyBinding;
1964 COMPILE_CHECK(testLiteralAssignment(p, value));
1965 value->type = Value::Literal;
1969 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
1970 QDeclarativeParser::Value *v = prop->onValues.at(ii);
1971 Q_ASSERT(v->object);
1973 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
1976 obj->addValueProperty(prop);
1982 // Build assignments to QML lists. QML lists are properties of type
1983 // QDeclarativeListProperty<T>. List properties can accept a list of
1984 // objects, or a single binding.
1985 bool QDeclarativeCompiler::buildListProperty(QDeclarativeParser::Property *prop,
1986 QDeclarativeParser::Object *obj,
1987 const BindingContext &ctxt)
1989 Q_ASSERT(enginePrivate->isList(prop->type));
1993 obj->addValueProperty(prop);
1995 int listType = enginePrivate->listType(t);
1996 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1998 bool assignedBinding = false;
1999 for (int ii = 0; ii < prop->values.count(); ++ii) {
2000 QDeclarativeParser::Value *v = prop->values.at(ii);
2002 v->type = Value::CreatedObject;
2003 COMPILE_CHECK(buildObject(v->object, ctxt));
2005 // We check object coercian here. We check interface assignment
2007 if (!listTypeIsInterface) {
2008 if (!canCoerce(listType, v->object)) {
2009 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2013 } else if (v->value.isScript()) {
2014 if (assignedBinding)
2015 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2017 assignedBinding = true;
2018 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2019 v->type = Value::PropertyBinding;
2021 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2028 // Compiles an assignment to a QDeclarativeScriptString property
2029 bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeParser::Property *prop,
2030 QDeclarativeParser::Object *obj,
2031 const BindingContext &ctxt)
2033 if (prop->values.count() > 1)
2034 COMPILE_EXCEPTION(prop->values.at(1), tr( "Cannot assign multiple values to a script property"));
2036 if (prop->values.at(0)->object)
2037 COMPILE_EXCEPTION(prop->values.at(0), tr( "Invalid property assignment: script expected"));
2039 obj->addScriptStringProperty(prop, ctxt.stack);
2044 // Compile regular property assignments of the form "property: <value>"
2045 bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeParser::Property *prop,
2046 QDeclarativeParser::Object *obj,
2047 const BindingContext &ctxt)
2049 obj->addValueProperty(prop);
2051 if (prop->values.count() > 1)
2052 COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign multiple values to a singular property") );
2054 for (int ii = 0; ii < prop->values.count(); ++ii) {
2055 QDeclarativeParser::Value *v = prop->values.at(ii);
2058 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2062 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2067 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
2068 QDeclarativeParser::Value *v = prop->onValues.at(ii);
2070 Q_ASSERT(v->object);
2071 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2077 // Compile assigning a single object instance to a regular property
2078 bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeParser::Property *prop,
2079 QDeclarativeParser::Object *obj,
2080 QDeclarativeParser::Value *v,
2081 const BindingContext &ctxt)
2083 Q_ASSERT(prop->index != -1);
2084 Q_ASSERT(v->object->type != -1);
2086 if (!obj->metaObject()->property(prop->index).isWritable())
2087 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2089 if (QDeclarativeMetaType::isInterface(prop->type)) {
2091 // Assigning an object to an interface ptr property
2092 COMPILE_CHECK(buildObject(v->object, ctxt));
2094 v->type = Value::CreatedObject;
2096 } else if (prop->type == -1) {
2098 // Assigning an object to a QVariant
2099 COMPILE_CHECK(buildObject(v->object, ctxt));
2101 v->type = Value::CreatedObject;
2103 // Normally buildObject() will set this up, but we need the static
2104 // meta object earlier to test for assignability. It doesn't matter
2105 // that there may still be outstanding synthesized meta object changes
2106 // on this type, as they are not relevant for assignability testing
2107 v->object->metatype = output->types.at(v->object->type).metaObject();
2108 Q_ASSERT(v->object->metaObject());
2110 // We want to raw metaObject here as the raw metaobject is the
2111 // actual property type before we applied any extensions that might
2112 // effect the properties on the type, but don't effect assignability
2113 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2115 // Will be true if the assgned type inherits propertyMetaObject
2116 bool isAssignable = false;
2117 // Determine isAssignable value
2118 if (propertyMetaObject) {
2119 const QMetaObject *c = v->object->metatype;
2121 isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject));
2122 c = c->superClass();
2127 // Simple assignment
2128 COMPILE_CHECK(buildObject(v->object, ctxt));
2130 v->type = Value::CreatedObject;
2131 } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) {
2132 // Automatic "Component" insertion
2133 QDeclarativeParser::Object *root = v->object;
2134 QDeclarativeParser::Object *component = new QDeclarativeParser::Object;
2135 component->type = componentTypeRef();
2136 component->typeName = "Qt/Component";
2137 component->metatype = &QDeclarativeComponent::staticMetaObject;
2138 component->location = root->location;
2139 QDeclarativeParser::Value *componentValue = new QDeclarativeParser::Value;
2140 componentValue->object = root;
2141 component->getDefaultProperty()->addValue(componentValue);
2142 v->object = component;
2143 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2145 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2152 // Compile assigning a single object instance to a regular property using the "on" syntax.
2156 // NumberAnimation on x { }
2158 bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeParser::Property *prop,
2159 QDeclarativeParser::Object *obj,
2160 QDeclarativeParser::Object *baseObj,
2161 QDeclarativeParser::Value *v,
2162 const BindingContext &ctxt)
2164 Q_ASSERT(prop->index != -1);
2165 Q_ASSERT(v->object->type != -1);
2167 if (!obj->metaObject()->property(prop->index).isWritable())
2168 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2171 // Normally buildObject() will set this up, but we need the static
2172 // meta object earlier to test for assignability. It doesn't matter
2173 // that there may still be outstanding synthesized meta object changes
2174 // on this type, as they are not relevant for assignability testing
2175 v->object->metatype = output->types.at(v->object->type).metaObject();
2176 Q_ASSERT(v->object->metaObject());
2178 // Will be true if the assigned type inherits QDeclarativePropertyValueSource
2179 bool isPropertyValue = false;
2180 // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor
2181 bool isPropertyInterceptor = false;
2182 if (QDeclarativeType *valueType = toQmlType(v->object)) {
2183 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2184 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2187 if (isPropertyValue || isPropertyInterceptor) {
2188 // Assign as a property value source
2189 COMPILE_CHECK(buildObject(v->object, ctxt));
2191 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2192 buildDynamicMeta(baseObj, ForceCreation);
2193 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2195 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(QString::fromUtf8(v->object->typeName)).arg(QString::fromUtf8(prop->name.constData())));
2201 // Compile assigning a literal or binding to a regular property
2202 bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeParser::Property *prop,
2203 QDeclarativeParser::Object *obj,
2204 QDeclarativeParser::Value *v,
2205 const BindingContext &ctxt)
2207 Q_ASSERT(prop->index != -1);
2209 if (v->value.isScript()) {
2211 //optimization for <Type>.<EnumValue> enum assignments
2212 bool isEnumAssignment = false;
2213 COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj, v, &isEnumAssignment));
2214 if (isEnumAssignment) {
2215 v->type = Value::Literal;
2219 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2221 v->type = Value::PropertyBinding;
2225 COMPILE_CHECK(testLiteralAssignment(obj->metaObject()->property(prop->index), v));
2227 v->type = Value::Literal;
2233 bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop,
2234 QDeclarativeParser::Object *obj,
2235 QDeclarativeParser::Value *v,
2238 *isAssignment = false;
2239 if (!prop.isEnumType())
2242 if (!prop.isWritable())
2243 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
2245 QString string = v->value.asString();
2246 if (!string.at(0).isUpper())
2249 QStringList parts = string.split(QLatin1Char('.'));
2250 if (parts.count() != 2)
2253 QString typeName = parts.at(0);
2254 QDeclarativeType *type = 0;
2255 unit->imports().resolveType(typeName.toUtf8(), &type, 0, 0, 0, 0);
2257 //handle enums on value types (where obj->typeName is empty)
2258 QByteArray objTypeName = obj->typeName;
2259 if (objTypeName.isEmpty()) {
2260 QDeclarativeType *objType = toQmlType(obj);
2262 objTypeName = objType->qmlTypeName();
2268 QString enumValue = parts.at(1);
2271 if (objTypeName == type->qmlTypeName()) {
2272 // When these two match, we can short cut the search
2273 if (prop.isFlagType()) {
2274 value = prop.enumerator().keysToValue(enumValue.toUtf8().constData());
2276 value = prop.enumerator().keyToValue(enumValue.toUtf8().constData());
2279 // Otherwise we have to search the whole type
2280 // This matches the logic in QV8TypeWrapper
2281 QByteArray enumName = enumValue.toUtf8();
2282 const QMetaObject *metaObject = type->baseMetaObject();
2283 for (int ii = metaObject->enumeratorCount() - 1; value == -1 && ii >= 0; --ii) {
2284 QMetaEnum e = metaObject->enumerator(ii);
2285 value = e.keyToValue(enumName.constData());
2292 v->type = Value::Literal;
2293 v->value = QDeclarativeParser::Variant((double)value);
2294 *isAssignment = true;
2299 struct StaticQtMetaObject : public QObject
2301 static const QMetaObject *get()
2302 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2305 // Similar logic to above, but not knowing target property.
2306 int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const
2308 int dot = script.indexOf('.');
2310 const QByteArray &scope = script.left(dot);
2311 QDeclarativeType *type = 0;
2312 unit->imports().resolveType(scope, &type, 0, 0, 0, 0);
2313 if (!type && scope != "Qt")
2315 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2316 const char *key = script.constData() + dot+1;
2317 int i = mo->enumeratorCount();
2319 int v = mo->enumerator(i).keyToValue(key);
2327 const QMetaObject *QDeclarativeCompiler::resolveType(const QByteArray& name) const
2329 QDeclarativeType *qmltype = 0;
2330 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2334 return qmltype->metaObject();
2337 // similar to logic of completeComponentBuild, but also sticks data
2338 // into primitives at the end
2339 int QDeclarativeCompiler::rewriteBinding(const QString& expression, const QByteArray& name)
2341 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2342 rewriteBinding.setName('$' + name.mid(name.lastIndexOf('.') + 1));
2344 QString rewrite = rewriteBinding(expression, 0, 0);
2346 return output->indexForString(rewrite);
2349 // Ensures that the dynamic meta specification on obj is valid
2350 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj)
2352 QSet<QByteArray> propNames;
2353 QSet<QByteArray> methodNames;
2354 bool seenDefaultProperty = false;
2357 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2358 const QDeclarativeParser::Object::DynamicProperty &prop =
2359 obj->dynamicProperties.at(ii);
2361 if (prop.isDefaultProperty) {
2362 if (seenDefaultProperty)
2363 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2364 seenDefaultProperty = true;
2367 if (propNames.contains(prop.name))
2368 COMPILE_EXCEPTION(&prop, tr("Duplicate property name"));
2370 QString propName = QString::fromUtf8(prop.name);
2371 if (propName.at(0).isUpper())
2372 COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
2374 if (enginePrivate->v8engine()->illegalNames().contains(propName))
2375 COMPILE_EXCEPTION(&prop, tr("Illegal property name"));
2377 propNames.insert(prop.name);
2380 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2381 QByteArray name = obj->dynamicSignals.at(ii).name;
2382 if (methodNames.contains(name))
2383 COMPILE_EXCEPTION(obj, tr("Duplicate signal name"));
2384 QString nameStr = QString::fromUtf8(name);
2385 if (nameStr.at(0).isUpper())
2386 COMPILE_EXCEPTION(obj, tr("Signal names cannot begin with an upper case letter"));
2387 if (enginePrivate->v8engine()->illegalNames().contains(nameStr))
2388 COMPILE_EXCEPTION(obj, tr("Illegal signal name"));
2389 methodNames.insert(name);
2391 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2392 QByteArray name = obj->dynamicSlots.at(ii).name;
2393 if (methodNames.contains(name))
2394 COMPILE_EXCEPTION(obj, tr("Duplicate method name"));
2395 QString nameStr = QString::fromUtf8(name);
2396 if (nameStr.at(0).isUpper())
2397 COMPILE_EXCEPTION(obj, tr("Method names cannot begin with an upper case letter"));
2398 if (enginePrivate->v8engine()->illegalNames().contains(nameStr))
2399 COMPILE_EXCEPTION(obj, tr("Illegal method name"));
2400 methodNames.insert(name);
2406 bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeParser::Object *obj)
2408 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2409 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2411 if (!p.defaultValue || p.type == Object::DynamicProperty::Alias)
2414 Property *property = 0;
2415 if (p.isDefaultProperty) {
2416 property = obj->getDefaultProperty();
2418 property = obj->getProperty(p.name);
2419 if (!property->values.isEmpty())
2420 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2423 if (property->value)
2424 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2426 for (int ii = 0; ii < p.defaultValue->values.count(); ++ii) {
2427 QDeclarativeParser::Value *v = p.defaultValue->values.at(ii);
2429 property->values.append(v);
2435 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2437 bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, DynamicMetaMode mode)
2440 Q_ASSERT(obj->metatype);
2442 if (mode != ForceCreation &&
2443 obj->dynamicProperties.isEmpty() &&
2444 obj->dynamicSignals.isEmpty() &&
2445 obj->dynamicSlots.isEmpty())
2448 QByteArray dynamicData(sizeof(QDeclarativeVMEMetaData), (char)0);
2450 QByteArray newClassName = obj->metatype->className();
2451 newClassName.append("_QML_");
2452 int idx = classIndexCounter()->fetchAndAddRelaxed(1);
2453 newClassName.append(QByteArray::number(idx));
2454 if (compileState.root == obj && !compileState.nested) {
2455 QString path = output->url.path();
2456 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2457 if (lastSlash > -1) {
2458 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2459 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2460 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(idx);
2464 QMetaObjectBuilder builder;
2465 builder.setClassName(newClassName);
2466 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
2468 bool hasAlias = false;
2469 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2470 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2472 int propIdx = obj->metaObject()->indexOfProperty(p.name.constData());
2473 if (-1 != propIdx) {
2474 QMetaProperty prop = obj->metaObject()->property(propIdx);
2476 COMPILE_EXCEPTION(&p, tr("Cannot override FINAL property"));
2479 if (p.isDefaultProperty &&
2480 (p.type != Object::DynamicProperty::Alias ||
2481 mode == ResolveAliases))
2482 builder.addClassInfo("DefaultProperty", p.name);
2485 int propertyType = 0;
2486 bool readonly = false;
2488 case Object::DynamicProperty::Alias:
2492 case Object::DynamicProperty::CustomList:
2493 case Object::DynamicProperty::Custom:
2495 QByteArray customTypeName;
2496 QDeclarativeType *qmltype = 0;
2498 if (!unit->imports().resolveType(p.customType, &qmltype, &url, 0, 0, 0))
2499 COMPILE_EXCEPTION(&p, tr("Invalid property type"));
2502 QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(url);
2504 Q_ASSERT(tdata->isComplete());
2506 QDeclarativeCompiledData *data = tdata->compiledData();
2507 customTypeName = data->root->className();
2511 customTypeName = qmltype->typeName();
2514 if (p.type == Object::DynamicProperty::Custom) {
2515 type = customTypeName + '*';
2516 propertyType = QMetaType::QObjectStar;
2519 type = "QDeclarativeListProperty<";
2520 type.append(customTypeName);
2522 propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
2526 case Object::DynamicProperty::Variant:
2530 case Object::DynamicProperty::Int:
2531 propertyType = QVariant::Int;
2534 case Object::DynamicProperty::Bool:
2535 propertyType = QVariant::Bool;
2538 case Object::DynamicProperty::Real:
2539 propertyType = QVariant::Double;
2542 case Object::DynamicProperty::String:
2543 propertyType = QVariant::String;
2546 case Object::DynamicProperty::Url:
2547 propertyType = QVariant::Url;
2550 case Object::DynamicProperty::Color:
2551 propertyType = QVariant::Color;
2554 case Object::DynamicProperty::Time:
2555 propertyType = QVariant::Time;
2558 case Object::DynamicProperty::Date:
2559 propertyType = QVariant::Date;
2562 case Object::DynamicProperty::DateTime:
2563 propertyType = QVariant::DateTime;
2568 ((QDeclarativeVMEMetaData *)dynamicData.data())->propertyCount++;
2569 QDeclarativeVMEMetaData::PropertyData propertyData = { propertyType };
2570 dynamicData.append((char *)&propertyData, sizeof(propertyData));
2572 builder.addSignal(p.name + "Changed()");
2573 QMetaPropertyBuilder propBuilder =
2574 builder.addProperty(p.name, type, builder.methodCount() - 1);
2575 propBuilder.setWritable(!readonly);
2578 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2579 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2581 if (p.type == Object::DynamicProperty::Alias) {
2582 if (mode == ResolveAliases) {
2583 ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++;
2584 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, p));
2586 // Need a fake signal so that the metaobject remains consistent across
2587 // the resolve and non-resolve alias runs
2588 builder.addSignal(p.name + "Changed()");
2593 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2594 const Object::DynamicSignal &s = obj->dynamicSignals.at(ii);
2595 QByteArray sig(s.name + '(');
2596 for (int jj = 0; jj < s.parameterTypes.count(); ++jj) {
2597 if (jj) sig.append(',');
2598 sig.append(s.parameterTypes.at(jj));
2601 QMetaMethodBuilder b = builder.addSignal(sig);
2602 b.setParameterNames(s.parameterNames);
2603 ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++;
2606 QStringList funcScripts;
2608 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2609 Object::DynamicSlot &s = obj->dynamicSlots[ii];
2610 QByteArray sig(s.name + '(');
2611 QString funcScript(QLatin1String("(function ") + s.name + QLatin1Char('('));
2613 for (int jj = 0; jj < s.parameterNames.count(); ++jj) {
2616 funcScript.append(QLatin1Char(','));
2618 funcScript.append(QLatin1String(s.parameterNames.at(jj)));
2619 sig.append("QVariant");
2622 funcScript.append(QLatin1Char(')'));
2623 funcScript.append(s.body);
2624 funcScript.append(QLatin1Char(')'));
2625 funcScripts << funcScript;
2627 QMetaMethodBuilder b = builder.addSlot(sig);
2628 b.setReturnType("QVariant");
2629 b.setParameterNames(s.parameterNames);
2631 ((QDeclarativeVMEMetaData *)dynamicData.data())->methodCount++;
2632 QDeclarativeVMEMetaData::MethodData methodData =
2633 { s.parameterNames.count(), 0, funcScript.length(), s.location.start.line };
2635 dynamicData.append((char *)&methodData, sizeof(methodData));
2638 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2639 const QString &funcScript = funcScripts.at(ii);
2640 QDeclarativeVMEMetaData::MethodData *data =
2641 ((QDeclarativeVMEMetaData *)dynamicData.data())->methodData() + ii;
2643 data->bodyOffset = dynamicData.size();
2645 dynamicData.append((const char *)funcScript.constData(),
2646 (funcScript.length() * sizeof(QChar)));
2649 obj->metadata = builder.toRelocatableData();
2650 builder.fromRelocatableData(&obj->extObject, obj->metatype, obj->metadata);
2652 if (mode == IgnoreAliases && hasAlias)
2653 compileState.aliasingObjects << obj;
2655 obj->synthdata = dynamicData;
2657 if (obj->synthCache) {
2658 obj->synthCache->release();
2659 obj->synthCache = 0;
2662 if (obj->type != -1) {
2663 QDeclarativePropertyCache *cache = output->types[obj->type].createPropertyCache(engine)->copy();
2664 cache->append(engine, &obj->extObject, QDeclarativePropertyCache::Data::NoFlags,
2665 QDeclarativePropertyCache::Data::IsVMEFunction,
2666 QDeclarativePropertyCache::Data::IsVMESignal);
2667 obj->synthCache = cache;
2673 bool QDeclarativeCompiler::checkValidId(QDeclarativeParser::Value *v, const QString &val)
2676 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
2678 if (val.at(0).isLetter() && !val.at(0).isLower())
2679 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
2681 QChar u(QLatin1Char('_'));
2682 for (int ii = 0; ii < val.count(); ++ii) {
2684 if (ii == 0 && !val.at(ii).isLetter() && val.at(ii) != u) {
2685 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
2686 } else if (ii != 0 && !val.at(ii).isLetterOrNumber() && val.at(ii) != u) {
2687 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
2692 if (enginePrivate->v8engine()->illegalNames().contains(val))
2693 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
2698 #include <qdeclarativejsparser_p.h>
2700 static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node)
2702 if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) {
2704 static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name->asString();
2705 return QStringList() << name;
2706 } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) {
2707 QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node);
2709 QStringList rv = astNodeToStringList(expr->base);
2712 rv.append(expr->name->asString());
2715 return QStringList();
2718 bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder,
2720 QDeclarativeParser::Object *obj,
2721 const Object::DynamicProperty &prop)
2723 if (!prop.defaultValue)
2724 COMPILE_EXCEPTION(obj, tr("No property alias location"));
2726 if (prop.defaultValue->values.count() != 1 ||
2727 prop.defaultValue->values.at(0)->object ||
2728 !prop.defaultValue->values.at(0)->value.isScript())
2729 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2731 QDeclarativeJS::AST::Node *node = prop.defaultValue->values.at(0)->value.asAST();
2733 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
2735 QStringList alias = astNodeToStringList(node);
2737 if (alias.count() < 1 || alias.count() > 3)
2738 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
2740 if (!compileState.ids.contains(alias.at(0)))
2741 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
2743 QDeclarativeParser::Object *idObject = compileState.ids[alias.at(0)];
2745 QByteArray typeName;
2749 bool writable = false;
2750 if (alias.count() == 2 || alias.count() == 3) {
2751 propIdx = indexOfProperty(idObject, alias.at(1).toUtf8());
2753 if (-1 == propIdx) {
2754 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2755 } else if (propIdx > 0xFFFF) {
2756 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
2759 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
2760 if (!aliasProperty.isScriptable())
2761 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2763 writable = aliasProperty.isWritable();
2765 if (alias.count() == 3) {
2766 QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
2768 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2770 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
2772 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
2773 if (valueTypeIndex == -1)
2774 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2775 Q_ASSERT(valueTypeIndex <= 0xFF);
2777 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
2778 propIdx |= (valueTypeIndex << 16);
2781 if (aliasProperty.isEnumType())
2782 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
2784 typeName = aliasProperty.typeName();
2786 Q_ASSERT(idObject->type != -1); // How else did it get an id?
2788 const QDeclarativeCompiledData::TypeReference &ref = output->types.at(idObject->type);
2790 typeName = ref.type->typeName();
2792 typeName = ref.component->root->className();
2797 if (typeName.endsWith('*'))
2798 flags |= QML_ALIAS_FLAG_PTR;
2800 data.append((const char *)&idObject->idIndex, sizeof(idObject->idIndex));
2801 data.append((const char *)&propIdx, sizeof(propIdx));
2802 data.append((const char *)&flags, sizeof(flags));
2804 builder.addSignal(prop.name + "Changed()");
2805 QMetaPropertyBuilder propBuilder =
2806 builder.addProperty(prop.name, typeName.constData(), builder.methodCount() - 1);
2807 propBuilder.setWritable(writable);
2811 bool QDeclarativeCompiler::buildBinding(QDeclarativeParser::Value *value,
2812 QDeclarativeParser::Property *prop,
2813 const BindingContext &ctxt)
2815 Q_ASSERT(prop->index != -1);
2816 Q_ASSERT(prop->parent);
2817 Q_ASSERT(prop->parent->metaObject());
2819 QMetaProperty mp = prop->parent->metaObject()->property(prop->index);
2820 if (!mp.isWritable() && !QDeclarativeMetaType::isList(prop->type))
2821 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2823 BindingReference reference;
2824 reference.expression = value->value;
2825 reference.property = prop;
2826 reference.value = value;
2827 reference.bindingContext = ctxt;
2828 addBindingReference(reference);
2833 void QDeclarativeCompiler::genBindingAssignment(QDeclarativeParser::Value *binding,
2834 QDeclarativeParser::Property *prop,
2835 QDeclarativeParser::Object *obj,
2836 QDeclarativeParser::Property *valueTypeProperty)
2839 Q_ASSERT(compileState.bindings.contains(binding));
2841 const BindingReference &ref = compileState.bindings.value(binding);
2842 if (ref.dataType == BindingReference::V4) {
2843 QDeclarativeInstruction store;
2844 store.setType(QDeclarativeInstruction::StoreV4Binding);
2845 store.assignBinding.value = ref.compiledIndex;
2846 store.assignBinding.context = ref.bindingContext.stack;
2847 store.assignBinding.owner = ref.bindingContext.owner;
2848 if (valueTypeProperty)
2849 store.assignBinding.property = (valueTypeProperty->index & 0xFFFF) |
2850 ((valueTypeProperty->type & 0xFF)) << 16 |
2851 ((prop->index & 0xFF) << 24);
2853 store.assignBinding.property = prop->index;
2854 store.assignBinding.line = binding->location.start.line;
2855 output->addInstruction(store);
2856 } else if (ref.dataType == BindingReference::V8) {
2857 QDeclarativeInstruction store;
2858 store.setType(QDeclarativeInstruction::StoreV8Binding);
2859 store.assignBinding.value = ref.compiledIndex;
2860 store.assignBinding.context = ref.bindingContext.stack;
2861 store.assignBinding.owner = ref.bindingContext.owner;
2862 store.assignBinding.line = binding->location.start.line;
2864 Q_ASSERT(ref.bindingContext.owner == 0 ||
2865 (ref.bindingContext.owner != 0 && valueTypeProperty));
2866 if (ref.bindingContext.owner) {
2867 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
2869 store.assignBinding.property = genPropertyData(prop);
2872 output->addInstruction(store);
2874 QDeclarativeInstruction store;
2876 store.setType(QDeclarativeInstruction::StoreBinding);
2878 store.setType(QDeclarativeInstruction::StoreBindingOnAlias);
2879 store.assignBinding.value = output->indexForString(ref.rewrittenExpression);
2880 store.assignBinding.context = ref.bindingContext.stack;
2881 store.assignBinding.owner = ref.bindingContext.owner;
2882 store.assignBinding.line = binding->location.start.line;
2884 Q_ASSERT(ref.bindingContext.owner == 0 ||
2885 (ref.bindingContext.owner != 0 && valueTypeProperty));
2886 if (ref.bindingContext.owner) {
2887 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
2889 store.assignBinding.property = genPropertyData(prop);
2891 output->addInstruction(store);
2895 int QDeclarativeCompiler::genContextCache()
2897 if (compileState.ids.count() == 0)
2900 QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache();
2902 for (QHash<QString, QDeclarativeParser::Object *>::ConstIterator iter = compileState.ids.begin();
2903 iter != compileState.ids.end();
2905 cache->add(iter.key(), (*iter)->idIndex);
2907 output->contextCaches.append(cache);
2908 return output->contextCaches.count() - 1;
2911 int QDeclarativeCompiler::genValueTypeData(QDeclarativeParser::Property *valueTypeProp,
2912 QDeclarativeParser::Property *prop)
2914 typedef QDeclarativePropertyPrivate QDPP;
2915 QByteArray data = QDPP::saveValueType(prop->parent->metaObject(), prop->index,
2916 enginePrivate->valueTypes[prop->type]->metaObject(),
2917 valueTypeProp->index, engine);
2919 return output->indexForByteArray(data);
2922 int QDeclarativeCompiler::genPropertyData(QDeclarativeParser::Property *prop)
2924 typedef QDeclarativePropertyPrivate QDPP;
2925 QByteArray data = QDPP::saveProperty(prop->parent->metaObject(), prop->index, engine);
2927 return output->indexForByteArray(data);
2930 bool QDeclarativeCompiler::completeComponentBuild()
2932 componentStat.ids = compileState.ids.count();
2934 for (int ii = 0; ii < compileState.aliasingObjects.count(); ++ii) {
2935 QDeclarativeParser::Object *aliasObject = compileState.aliasingObjects.at(ii);
2936 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
2939 QDeclarativeV4Compiler::Expression expr;
2940 expr.component = compileState.root;
2941 expr.ids = compileState.ids;
2942 expr.importCache = output->importCache;
2943 expr.imports = unit->imports();
2945 QDeclarativeV4Compiler bindingCompiler;
2947 QList<BindingReference*> sharedBindings;
2949 for (QHash<QDeclarativeParser::Value*,BindingReference>::Iterator iter = compileState.bindings.begin();
2950 iter != compileState.bindings.end(); ++iter) {
2952 BindingReference &binding = *iter;
2954 // ### We don't currently optimize for bindings on alias's - because
2955 // of the solution to QTBUG-13719
2956 if (!binding.property->isAlias) {
2957 expr.context = binding.bindingContext.object;
2958 expr.property = binding.property;
2959 expr.expression = binding.expression;
2961 int index = bindingCompiler.compile(expr, enginePrivate);
2963 binding.dataType = BindingReference::V4;
2964 binding.compiledIndex = index;
2965 componentStat.optimizedBindings.append(iter.key()->location);
2970 // Pre-rewrite the expression
2971 QString expression = binding.expression.asScript();
2973 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2974 rewriteBinding.setName('$'+binding.property->name);
2975 bool isSharable = false;
2976 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
2978 if (isSharable && !binding.property->isAlias /* See above re alias */ &&
2979 binding.property->type != qMetaTypeId<QDeclarativeBinding*>()) {
2980 binding.dataType = BindingReference::V8;
2981 sharedBindings.append(&iter.value());
2983 binding.dataType = BindingReference::QtScript;
2986 componentStat.scriptBindings.append(iter.key()->location);
2989 if (!sharedBindings.isEmpty()) {
2991 static bool lt(const BindingReference *lhs, const BindingReference *rhs)
2993 return lhs->value->location.start.line < rhs->value->location.start.line;
2997 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
2999 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3000 int lineNumber = startLineNumber;
3002 QString functionArray(QLatin1String("["));
3003 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3004 BindingReference *reference = sharedBindings.at(ii);
3005 QDeclarativeParser::Value *value = reference->value;
3006 const QString &expression = reference->rewrittenExpression;
3008 if (ii != 0) functionArray += QLatin1String(",");
3010 while (lineNumber < value->location.start.line) {
3012 functionArray += QLatin1String("\n");
3015 functionArray += expression;
3016 reference->compiledIndex = ii;
3018 functionArray += QLatin1String("]");
3020 compileState.v8BindingProgram = functionArray;
3021 compileState.v8BindingProgramLine = startLineNumber;
3022 compileState.v8BindingProgramIndex = output->v8bindings.count();
3023 output->v8bindings.append(v8::Persistent<v8::Array>());
3026 if (bindingCompiler.isValid())
3027 compileState.compiledBindingData = bindingCompiler.program();
3029 saveComponentState();
3034 void QDeclarativeCompiler::dumpStats()
3036 qWarning().nospace() << "QML Document: " << output->url.toString();
3037 for (int ii = 0; ii < savedComponentStats.count(); ++ii) {
3038 const ComponentStat &stat = savedComponentStats.at(ii);
3039 qWarning().nospace() << " Component Line " << stat.lineNumber;
3040 qWarning().nospace() << " Total Objects: " << stat.objects;
3041 qWarning().nospace() << " IDs Used: " << stat.ids;
3042 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3046 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3047 if (0 == (ii % 10)) {
3048 if (ii) output.append("\n");
3053 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3055 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3056 output.append(") ");
3058 if (!output.isEmpty())
3059 qWarning().nospace() << output.constData();
3062 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3065 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3066 if (0 == (ii % 10)) {
3067 if (ii) output.append("\n");
3072 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3074 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3075 output.append(") ");
3077 if (!output.isEmpty())
3078 qWarning().nospace() << output.constData();
3084 Returns true if from can be assigned to a (QObject) property of type
3087 bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeParser::Object *from)
3089 const QMetaObject *toMo =
3090 enginePrivate->rawMetaObjectForType(to);
3091 const QMetaObject *fromMo = from->metaObject();
3094 if (QDeclarativePropertyPrivate::equal(fromMo, toMo))
3096 fromMo = fromMo->superClass();
3101 QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeParser::Object *from)
3104 const QMetaObject *mo = from->metatype;
3105 QDeclarativeType *type = 0;
3106 while (!type && mo) {
3107 type = QDeclarativeMetaType::qmlType(mo);
3108 mo = mo->superClass();
3113 QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeParser::Object *obj)
3115 const QMetaObject *mo = obj->metatype;
3117 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3119 return QStringList();
3121 QMetaClassInfo classInfo = mo->classInfo(idx);
3122 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3126 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3127 int QDeclarativeCompiler::indexOfSignal(QDeclarativeParser::Object *object, const QByteArray &name,
3128 bool *notInRevision)
3130 if (notInRevision) *notInRevision = false;
3132 if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) {
3134 QString strName(QString::fromUtf8(name));
3135 QDeclarativePropertyCache *cache =
3136 object->synthCache?object->synthCache:output->types.at(object->type).propertyCache();
3138 QDeclarativePropertyCache::Data *d = cache->property(strName);
3139 if (notInRevision) *notInRevision = false;
3141 while (d && !(d->isFunction()))
3142 d = cache->overrideData(d);
3144 if (d && !cache->isAllowedInRevision(d)) {
3145 if (notInRevision) *notInRevision = true;
3148 return d->coreIndex;
3151 if (name.endsWith("Changed")) {
3152 QByteArray propName = name.mid(0, name.length() - 7);
3154 int propIndex = indexOfProperty(object, propName, notInRevision);
3155 if (propIndex != -1) {
3156 d = cache->property(propIndex);
3157 return d->notifyIndex;
3163 return QDeclarativePropertyPrivate::findSignalByName(object->metaObject(), name).methodIndex();
3168 int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QByteArray &name,
3169 bool *notInRevision)
3171 if (notInRevision) *notInRevision = false;
3173 if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) {
3175 QString strName(QString::fromUtf8(name));
3176 QDeclarativePropertyCache *cache =
3177 object->synthCache?object->synthCache:output->types.at(object->type).propertyCache();
3179 QDeclarativePropertyCache::Data *d = cache->property(strName);
3180 // Find the first property
3181 while (d && d->isFunction())
3182 d = cache->overrideData(d);
3184 if (d && !cache->isAllowedInRevision(d)) {
3185 if (notInRevision) *notInRevision = true;
3188 return d?d->coreIndex:-1;
3191 const QMetaObject *mo = object->metaObject();
3192 return mo->indexOfProperty(name.constData());