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"
67 #include "private/qdeclarativeglobalscriptclass_p.h"
75 #include <QtCore/qdebug.h>
76 #include <QtCore/qdatetime.h>
80 DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP);
81 DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS);
83 using namespace QDeclarativeParser;
86 Instantiate a new QDeclarativeCompiler.
88 QDeclarativeCompiler::QDeclarativeCompiler()
89 : output(0), engine(0), unitRoot(0), unit(0)
94 Returns true if the last call to compile() caused errors.
98 bool QDeclarativeCompiler::isError() const
100 return !exceptions.isEmpty();
104 Return the list of errors from the last call to compile(), or an empty list
105 if there were no errors.
107 QList<QDeclarativeError> QDeclarativeCompiler::errors() const
113 Returns true if \a name refers to an attached property, false otherwise.
115 Attached property names are those that start with a capital letter.
117 bool QDeclarativeCompiler::isAttachedPropertyName(const QByteArray &name)
119 return !name.isEmpty() && name.at(0) >= 'A' && name.at(0) <= 'Z';
123 Returns true if \a name refers to a signal property, false otherwise.
125 Signal property names are those that start with "on", followed by a first
126 character which is either a capital letter or one or more underscores followed
127 by a capital letter, which is then followed by other allowed characters.
129 Note that although ECMA-262r3 supports dollarsigns and escaped unicode
130 character codes in property names, for simplicity and performance reasons
131 QML only supports letters, numbers and underscores.
133 bool QDeclarativeCompiler::isSignalPropertyName(const QByteArray &name)
135 if (name.length() < 3) return false;
136 if (!name.startsWith("on")) return false;
137 int ns = name.size();
138 for (int i = 2; i < ns; ++i) {
139 char curr = name.at(i);
140 if (curr == '_') continue;
141 if (curr >= 'A' && curr <= 'Z') return true;
144 return false; // consists solely of underscores - invalid.
148 \macro COMPILE_EXCEPTION
150 Inserts an error into the QDeclarativeCompiler error list, and returns false
153 \a token is used to source the error line and column, and \a desc is the
154 error itself. \a desc can be an expression that can be piped into QDebug.
159 COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(QString::fromUtf8(property->name)));
162 #define COMPILE_EXCEPTION(token, desc) \
164 QString exceptionDescription; \
165 QDeclarativeError error; \
166 error.setUrl(output->url); \
167 error.setLine((token)->location.start.line); \
168 error.setColumn((token)->location.start.column); \
169 error.setDescription(desc.trimmed()); \
170 exceptions << error; \
177 Returns false if \a is false, otherwise does nothing.
179 #define COMPILE_CHECK(a) \
181 if (!a) return false; \
185 Returns true if literal \a v can be assigned to property \a prop, otherwise
188 This test corresponds to action taken by genLiteralAssignment(). Any change
189 made here, must have a corresponding action in genLiteralAssigment().
191 bool QDeclarativeCompiler::testLiteralAssignment(const QMetaProperty &prop,
192 QDeclarativeParser::Value *v)
194 QString string = v->value.asString();
196 if (!prop.isWritable())
197 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
199 if (prop.isEnumType()) {
201 if (prop.isFlagType()) {
202 value = prop.enumerator().keysToValue(string.toUtf8().constData());
204 value = prop.enumerator().keyToValue(string.toUtf8().constData());
206 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration"));
209 int type = prop.userType();
213 case QVariant::String:
214 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
216 case QVariant::ByteArray:
217 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected"));
220 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected"));
224 bool ok = v->value.isNumber();
226 double n = v->value.asNumber();
227 if (double(uint(n)) != n)
230 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected"));
235 bool ok = v->value.isNumber();
237 double n = v->value.asNumber();
238 if (double(int(n)) != n)
241 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected"));
244 case QMetaType::Float:
245 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
247 case QVariant::Double:
248 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
250 case QVariant::Color:
253 QDeclarativeStringConverters::colorFromString(string, &ok);
254 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected"));
257 #ifndef QT_NO_DATESTRING
261 QDeclarativeStringConverters::dateFromString(string, &ok);
262 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected"));
268 QDeclarativeStringConverters::timeFromString(string, &ok);
269 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected"));
272 case QVariant::DateTime:
275 QDeclarativeStringConverters::dateTimeFromString(string, &ok);
276 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected"));
279 #endif // QT_NO_DATESTRING
280 case QVariant::Point:
281 case QVariant::PointF:
284 QPointF point = QDeclarativeStringConverters::pointFFromString(string, &ok);
285 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected"));
289 case QVariant::SizeF:
292 QSizeF size = QDeclarativeStringConverters::sizeFFromString(string, &ok);
293 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected"));
297 case QVariant::RectF:
300 QRectF rect = QDeclarativeStringConverters::rectFFromString(string, &ok);
301 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected"));
306 if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected"));
309 case QVariant::Vector3D:
312 QDeclarativeStringConverters::vector3DFromString(string, &ok);
313 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected"));
318 int t = prop.userType();
319 QDeclarativeMetaType::StringConverter converter =
320 QDeclarativeMetaType::customStringConverter(t);
322 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName(prop.type()))));
330 Generate a store instruction for assigning literal \a v to property \a prop.
332 Any literal assignment that is approved in testLiteralAssignment() must have
333 a corresponding action in this method.
335 void QDeclarativeCompiler::genLiteralAssignment(const QMetaProperty &prop,
336 QDeclarativeParser::Value *v)
338 QDeclarativeInstruction instr;
339 if (prop.isEnumType()) {
341 if (v->value.isNumber()) {
343 value = (int)v->value.asNumber();
346 if (prop.isFlagType()) {
347 value = prop.enumerator().keysToValue(v->value.asString().toUtf8().constData());
349 value = prop.enumerator().keyToValue(v->value.asString().toUtf8().constData());
352 instr.setType(QDeclarativeInstruction::StoreInteger);
353 instr.storeInteger.propertyIndex = prop.propertyIndex();
354 instr.storeInteger.value = value;
355 output->addInstruction(instr);
359 QString string = v->value.asString();
361 int type = prop.userType();
365 if (v->value.isNumber()) {
366 double n = v->value.asNumber();
367 if (double(int(n)) == n) {
368 instr.setType(QDeclarativeInstruction::StoreVariantInteger);
369 instr.storeInteger.propertyIndex = prop.propertyIndex();
370 instr.storeInteger.value = int(n);
372 instr.setType(QDeclarativeInstruction::StoreVariantDouble);
373 instr.storeDouble.propertyIndex = prop.propertyIndex();
374 instr.storeDouble.value = n;
376 } else if(v->value.isBoolean()) {
377 instr.setType(QDeclarativeInstruction::StoreVariantBool);
378 instr.storeBool.propertyIndex = prop.propertyIndex();
379 instr.storeBool.value = v->value.asBoolean();
381 instr.setType(QDeclarativeInstruction::StoreVariant);
382 instr.storeString.propertyIndex = prop.propertyIndex();
383 instr.storeString.value = output->indexForString(string);
387 case QVariant::String:
389 instr.setType(QDeclarativeInstruction::StoreString);
390 instr.storeString.propertyIndex = prop.propertyIndex();
391 instr.storeString.value = output->indexForString(string);
394 case QVariant::ByteArray:
396 instr.setType(QDeclarativeInstruction::StoreByteArray);
397 instr.storeByteArray.propertyIndex = prop.propertyIndex();
398 instr.storeByteArray.value = output->indexForByteArray(string.toLatin1());
403 instr.setType(QDeclarativeInstruction::StoreUrl);
404 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
405 instr.storeUrl.propertyIndex = prop.propertyIndex();
406 instr.storeUrl.value = output->indexForUrl(u);
411 instr.setType(QDeclarativeInstruction::StoreInteger);
412 instr.storeInteger.propertyIndex = prop.propertyIndex();
413 instr.storeInteger.value = uint(v->value.asNumber());
418 instr.setType(QDeclarativeInstruction::StoreInteger);
419 instr.storeInteger.propertyIndex = prop.propertyIndex();
420 instr.storeInteger.value = int(v->value.asNumber());
423 case QMetaType::Float:
425 instr.setType(QDeclarativeInstruction::StoreFloat);
426 instr.storeFloat.propertyIndex = prop.propertyIndex();
427 instr.storeFloat.value = float(v->value.asNumber());
430 case QVariant::Double:
432 instr.setType(QDeclarativeInstruction::StoreDouble);
433 instr.storeDouble.propertyIndex = prop.propertyIndex();
434 instr.storeDouble.value = v->value.asNumber();
437 case QVariant::Color:
439 QColor c = QDeclarativeStringConverters::colorFromString(string);
440 instr.setType(QDeclarativeInstruction::StoreColor);
441 instr.storeColor.propertyIndex = prop.propertyIndex();
442 instr.storeColor.value = c.rgba();
445 #ifndef QT_NO_DATESTRING
448 QDate d = QDeclarativeStringConverters::dateFromString(string);
449 instr.setType(QDeclarativeInstruction::StoreDate);
450 instr.storeDate.propertyIndex = prop.propertyIndex();
451 instr.storeDate.value = d.toJulianDay();
456 QTime time = QDeclarativeStringConverters::timeFromString(string);
457 instr.setType(QDeclarativeInstruction::StoreTime);
458 instr.storeTime.propertyIndex = prop.propertyIndex();
459 instr.storeTime.time = *(QDeclarativeInstruction::instr_storeTime::QTime *)&time;
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 instr.storeDateTime.time = *(QDeclarativeInstruction::instr_storeTime::QTime *)&time;
472 #endif // QT_NO_DATESTRING
473 case QVariant::Point:
476 QPoint point = QDeclarativeStringConverters::pointFFromString(string, &ok).toPoint();
477 instr.setType(QDeclarativeInstruction::StorePoint);
478 instr.storePoint.propertyIndex = prop.propertyIndex();
479 instr.storePoint.point.xp = point.x();
480 instr.storePoint.point.yp = point.y();
483 case QVariant::PointF:
486 QPointF point = QDeclarativeStringConverters::pointFFromString(string, &ok);
487 instr.setType(QDeclarativeInstruction::StorePointF);
488 instr.storePointF.propertyIndex = prop.propertyIndex();
489 instr.storePointF.point.xp = point.x();
490 instr.storePointF.point.yp = point.y();
496 QSize size = QDeclarativeStringConverters::sizeFFromString(string, &ok).toSize();
497 instr.setType(QDeclarativeInstruction::StoreSize);
498 instr.storeSize.propertyIndex = prop.propertyIndex();
499 instr.storeSize.size.wd = size.width();
500 instr.storeSize.size.ht = size.height();
503 case QVariant::SizeF:
506 QSizeF size = QDeclarativeStringConverters::sizeFFromString(string, &ok);
507 instr.setType(QDeclarativeInstruction::StoreSizeF);
508 instr.storeSizeF.propertyIndex = prop.propertyIndex();
509 instr.storeSizeF.size.wd = size.width();
510 instr.storeSizeF.size.ht = size.height();
516 QRect rect = QDeclarativeStringConverters::rectFFromString(string, &ok).toRect();
517 instr.setType(QDeclarativeInstruction::StoreRect);
518 instr.storeRect.propertyIndex = prop.propertyIndex();
519 instr.storeRect.rect.x1 = rect.left();
520 instr.storeRect.rect.y1 = rect.top();
521 instr.storeRect.rect.x2 = rect.right();
522 instr.storeRect.rect.y2 = rect.bottom();
525 case QVariant::RectF:
528 QRectF rect = QDeclarativeStringConverters::rectFFromString(string, &ok);
529 instr.setType(QDeclarativeInstruction::StoreRectF);
530 instr.storeRectF.propertyIndex = prop.propertyIndex();
531 instr.storeRectF.rect.xp = rect.left();
532 instr.storeRectF.rect.yp = rect.top();
533 instr.storeRectF.rect.w = rect.width();
534 instr.storeRectF.rect.h = rect.height();
539 bool b = v->value.asBoolean();
540 instr.setType(QDeclarativeInstruction::StoreBool);
541 instr.storeBool.propertyIndex = prop.propertyIndex();
542 instr.storeBool.value = b;
545 case QVariant::Vector3D:
548 QVector3D vector = QDeclarativeStringConverters::vector3DFromString(string, &ok);
549 instr.setType(QDeclarativeInstruction::StoreVector3D);
550 instr.storeVector3D.propertyIndex = prop.propertyIndex();
551 instr.storeVector3D.vector.xp = vector.x();
552 instr.storeVector3D.vector.yp = vector.y();
553 instr.storeVector3D.vector.zp = vector.z();
558 int t = prop.userType();
559 instr.setType(QDeclarativeInstruction::AssignCustomType);
560 instr.assignCustomType.propertyIndex = prop.propertyIndex();
561 instr.assignCustomType.primitive = output->indexForString(string);
562 instr.assignCustomType.type = t;
566 output->addInstruction(instr);
570 Resets data by clearing the lists that the QDeclarativeCompiler modifies.
572 void QDeclarativeCompiler::reset(QDeclarativeCompiledData *data)
575 data->primitives.clear();
577 data->bytecode.clear();
581 Compile \a unit, and store the output in \a out. \a engine is the QDeclarativeEngine
582 with which the QDeclarativeCompiledData will be associated.
584 Returns true on success, false on failure. On failure, the compile errors
585 are available from errors().
587 If the environment variant QML_COMPILER_DUMP is set
588 (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
589 on a successful compiler.
591 bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine,
592 QDeclarativeTypeData *unit,
593 QDeclarativeCompiledData *out)
603 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
604 QList<QDeclarativeScriptParser::TypeReference *> referencedTypes = unit->parser().referencedTypes();
606 for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
607 QDeclarativeCompiledData::TypeReference ref;
609 const QDeclarativeTypeData::TypeReference &tref = resolvedTypes.at(ii);
610 QDeclarativeScriptParser::TypeReference *parserRef = referencedTypes.at(ii);
613 ref.type = tref.type;
614 if (!ref.type->isCreatable()) {
615 QString err = ref.type->noCreationReason();
617 err = tr( "Element is not creatable.");
618 COMPILE_EXCEPTION(parserRef->refObjects.first(), err);
621 if (ref.type->containsRevisionedAttributes()) {
622 QDeclarativeError cacheError;
623 ref.typePropertyCache =
624 QDeclarativeEnginePrivate::get(engine)->cache(ref.type, resolvedTypes.at(ii).minorVersion, cacheError);
626 if (!ref.typePropertyCache) {
627 COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description());
629 ref.typePropertyCache->addref();
632 } else if (tref.typeData) {
633 ref.component = tref.typeData->compiledData();
635 ref.className = parserRef->name.toUtf8();
639 QDeclarativeParser::Object *root = unit->parser().tree();
642 this->engine = engine;
643 this->enginePrivate = QDeclarativeEnginePrivate::get(engine);
645 this->unitRoot = root;
650 out->dumpInstructions();
651 if (compilerStatDump())
657 compileState = ComponentCompileState();
658 savedCompileStates.clear();
661 this->enginePrivate = 0;
668 void QDeclarativeCompiler::compileTree(QDeclarativeParser::Object *tree)
670 compileState.root = tree;
671 componentStat.lineNumber = tree->location.start.line;
673 // Build global import scripts
674 QStringList importedScriptIndexes;
676 foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
677 importedScriptIndexes.append(script.qualifier);
679 QDeclarativeInstruction import;
680 import.setType(QDeclarativeInstruction::StoreImportedScript);
681 import.storeScript.value = output->scripts.count();
683 QDeclarativeScriptData *scriptData = script.script->scriptData();
684 scriptData->addref();
685 output->scripts << scriptData;
686 output->addInstruction(import);
689 // We generate the importCache before we build the tree so that
690 // it can be used in the binding compiler. Given we "expect" the
691 // QML compilation to succeed, this isn't a waste.
692 output->importCache = new QDeclarativeTypeNameCache(engine);
693 for (int ii = 0; ii < importedScriptIndexes.count(); ++ii)
694 output->importCache->add(importedScriptIndexes.at(ii), ii);
695 unit->imports().populateCache(output->importCache, engine);
697 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
700 QDeclarativeInstruction init;
701 init.setType(QDeclarativeInstruction::Init);
702 init.init.bindingsSize = compileState.bindings.count();
703 init.init.parserStatusSize = compileState.parserStatusCount;
704 init.init.contextCache = genContextCache();
705 if (compileState.compiledBindingData.isEmpty())
706 init.init.compiledBinding = -1;
708 init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData);
709 output->addInstruction(init);
713 QDeclarativeInstruction def;
714 def.setType(QDeclarativeInstruction::SetDefault);
715 output->addInstruction(def);
717 QDeclarativeInstruction done;
718 done.setType(QDeclarativeInstruction::Done);
719 output->addInstruction(done);
721 Q_ASSERT(tree->metatype);
723 if (tree->metadata.isEmpty()) {
724 output->root = tree->metatype;
726 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
727 output->root = &output->rootData;
729 if (!tree->metadata.isEmpty())
730 enginePrivate->registerCompositeType(output);
733 static bool ValuePtrLessThan(const QDeclarativeParser::Value *t1, const QDeclarativeParser::Value *t2)
735 return t1->location.start.line < t2->location.start.line ||
736 (t1->location.start.line == t2->location.start.line &&
737 t1->location.start.column < t2->location.start.column);
740 bool QDeclarativeCompiler::buildObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
742 componentStat.objects++;
744 Q_ASSERT (obj->type != -1);
745 const QDeclarativeCompiledData::TypeReference &tr =
746 output->types.at(obj->type);
747 obj->metatype = tr.metaObject();
750 obj->url = tr.component->url;
752 obj->typeName = tr.type->qmlTypeName();
753 obj->className = tr.className;
755 // This object is a "Component" element
756 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
757 COMPILE_CHECK(buildComponent(obj, ctxt));
761 // Object instantiations reset the binding context
762 BindingContext objCtxt(obj);
764 // Create the synthesized meta object, ignoring aliases
765 COMPILE_CHECK(checkDynamicMeta(obj));
766 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
767 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
769 // Find the native type and check for the QDeclarativeParserStatus interface
770 QDeclarativeType *type = toQmlType(obj);
772 obj->parserStatusCast = type->parserStatusCast();
773 if (obj->parserStatusCast != -1)
774 compileState.parserStatusCount++;
776 // Check if this is a custom parser type. Custom parser types allow
777 // assignments to non-existent properties. These assignments are then
778 // compiled by the type.
779 bool isCustomParser = output->types.at(obj->type).type &&
780 output->types.at(obj->type).type->customParser() != 0;
781 QList<QDeclarativeCustomParserProperty> customProps;
783 // Fetch the list of deferred properties
784 QStringList deferredList = deferredProperties(obj);
786 // Must do id property first. This is to ensure that the id given to any
787 // id reference created matches the order in which the objects are
789 foreach(Property *prop, obj->properties) {
790 if (prop->name == "id") {
791 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
797 Property *defaultProperty = 0;
798 Property *skipProperty = 0;
799 if (obj->defaultProperty) {
800 const QMetaObject *metaObject = obj->metaObject();
801 Q_ASSERT(metaObject);
802 QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
804 Property *explicitProperty = obj->getProperty(p.name(), false);
805 if (explicitProperty && !explicitProperty->value) {
806 skipProperty = explicitProperty;
808 defaultProperty = new Property;
809 defaultProperty->parent = obj;
810 defaultProperty->isDefault = true;
811 defaultProperty->location = obj->defaultProperty->location;
812 defaultProperty->listValueRange = obj->defaultProperty->listValueRange;
813 defaultProperty->listCommaPositions = obj->defaultProperty->listCommaPositions;
815 defaultProperty->values = obj->defaultProperty->values;
816 defaultProperty->values += explicitProperty->values;
817 foreach(QDeclarativeParser::Value *value, defaultProperty->values)
819 qSort(defaultProperty->values.begin(), defaultProperty->values.end(), ValuePtrLessThan);
822 defaultProperty = obj->defaultProperty;
823 defaultProperty->addref();
826 defaultProperty = obj->defaultProperty;
827 defaultProperty->addref();
831 QDeclarativeCustomParser *cp = 0;
833 cp = output->types.at(obj->type).type->customParser();
835 // Build all explicit properties specified
836 foreach(Property *prop, obj->properties) {
838 if (prop == skipProperty)
840 if (prop->name == "id")
843 bool canDefer = false;
844 if (isCustomParser) {
845 if (doesPropertyExist(prop, obj) &&
846 (!(cp->flags() & QDeclarativeCustomParser::AcceptsAttachedProperties) ||
847 !isAttachedPropertyName(prop->name))) {
848 int ids = compileState.ids.count();
849 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
850 canDefer = ids == compileState.ids.count();
852 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
855 if (isSignalPropertyName(prop->name)) {
856 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
858 int ids = compileState.ids.count();
859 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
860 canDefer = ids == compileState.ids.count();
864 if (canDefer && !deferredList.isEmpty() &&
865 deferredList.contains(QString::fromUtf8(prop->name)))
866 prop->isDeferred = true;
870 // Build the default property
871 if (defaultProperty) {
872 Property *prop = defaultProperty;
874 bool canDefer = false;
875 if (isCustomParser) {
876 if (doesPropertyExist(prop, obj)) {
877 int ids = compileState.ids.count();
878 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
879 canDefer = ids == compileState.ids.count();
881 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
884 int ids = compileState.ids.count();
885 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
886 canDefer = ids == compileState.ids.count();
889 if (canDefer && !deferredList.isEmpty() &&
890 deferredList.contains(QString::fromUtf8(prop->name)))
891 prop->isDeferred = true;
895 defaultProperty->release();
897 // Compile custom parser parts
898 if (isCustomParser && !customProps.isEmpty()) {
902 obj->custom = cp->compile(customProps);
905 foreach (QDeclarativeError err, cp->errors()) {
906 err.setUrl(output->url);
914 void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj)
916 QDeclarativeCompiledData::TypeReference &tr = output->types[obj->type];
917 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
923 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
924 !output->types.at(obj->type).type->isExtendedType() && obj != compileState.root) {
926 QDeclarativeInstruction create;
927 create.setType(QDeclarativeInstruction::CreateSimpleObject);
928 create.createSimple.create = output->types.at(obj->type).type->createFunction();
929 create.createSimple.typeSize = output->types.at(obj->type).type->createSize();
930 create.createSimple.type = obj->type;
931 create.createSimple.line = obj->location.start.line;
932 create.createSimple.column = obj->location.start.column;
933 output->addInstruction(create);
937 QDeclarativeInstruction create;
938 create.setType(QDeclarativeInstruction::CreateObject);
939 create.create.line = obj->location.start.line;
940 create.create.column = obj->location.start.column;
941 create.create.data = -1;
942 if (!obj->custom.isEmpty())
943 create.create.data = output->indexForByteArray(obj->custom);
944 create.create.type = obj->type;
945 if (!output->types.at(create.create.type).type &&
946 !obj->bindingBitmask.isEmpty()) {
947 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
948 create.create.bindingBits =
949 output->indexForByteArray(obj->bindingBitmask);
951 create.create.bindingBits = -1;
953 output->addInstruction(create);
957 // Setup the synthesized meta object if necessary
958 if (!obj->metadata.isEmpty()) {
959 QDeclarativeInstruction meta;
960 meta.setType(QDeclarativeInstruction::StoreMetaObject);
961 meta.storeMeta.data = output->indexForByteArray(obj->metadata);
962 meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata);
963 meta.storeMeta.propertyCache = output->propertyCaches.count();
965 QDeclarativePropertyCache *propertyCache = obj->synthCache;
966 Q_ASSERT(propertyCache);
967 propertyCache->addref();
969 // Add flag for alias properties
970 if (!obj->synthdata.isEmpty()) {
971 const QDeclarativeVMEMetaData *vmeMetaData =
972 reinterpret_cast<const QDeclarativeVMEMetaData *>(obj->synthdata.constData());
973 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
974 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
975 propertyCache->property(index)->flags |= QDeclarativePropertyCache::Data::IsAlias;
979 if (obj == unitRoot) {
980 propertyCache->addref();
981 output->rootPropertyCache = propertyCache;
984 output->propertyCaches << propertyCache;
985 output->addInstruction(meta);
986 } else if (obj == unitRoot) {
987 output->rootPropertyCache = tr.createPropertyCache(engine);
988 output->rootPropertyCache->addref();
992 if (!obj->id.isEmpty()) {
993 QDeclarativeInstruction id;
994 id.setType(QDeclarativeInstruction::SetId);
995 id.setId.value = output->indexForString(obj->id);
996 id.setId.index = obj->idIndex;
997 output->addInstruction(id);
1001 if (tr.type && obj->parserStatusCast != -1) {
1002 QDeclarativeInstruction begin;
1003 begin.setType(QDeclarativeInstruction::BeginObject);
1004 begin.begin.castValue = obj->parserStatusCast;
1005 output->addInstruction(begin);
1011 void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj)
1013 typedef QPair<Property *, int> PropPair;
1014 foreach(const PropPair &prop, obj->scriptStringProperties) {
1015 QDeclarativeInstruction ss;
1016 ss.setType(QDeclarativeInstruction::StoreScriptString);
1017 ss.storeScriptString.propertyIndex = prop.first->index;
1018 ss.storeScriptString.value =
1019 output->indexForString(prop.first->values.at(0)->value.asScript());
1020 ss.storeScriptString.scope = prop.second;
1021 output->addInstruction(ss);
1024 bool seenDefer = false;
1025 foreach(Property *prop, obj->valueProperties) {
1026 if (prop->isDeferred) {
1031 genValueProperty(prop, obj);
1034 QDeclarativeInstruction defer;
1035 defer.setType(QDeclarativeInstruction::Defer);
1036 defer.defer.deferCount = 0;
1037 int deferIdx = output->addInstruction(defer);
1038 int nextInstructionIndex = output->nextInstructionIndex();
1040 QDeclarativeInstruction init;
1041 init.setType(QDeclarativeInstruction::Init);
1042 init.init.bindingsSize = compileState.bindings.count(); // XXX - bigger than necessary
1043 init.init.parserStatusSize = compileState.parserStatusCount; // XXX - bigger than necessary
1044 init.init.contextCache = -1;
1045 init.init.compiledBinding = -1;
1046 output->addInstruction(init);
1048 foreach(Property *prop, obj->valueProperties) {
1049 if (!prop->isDeferred)
1051 genValueProperty(prop, obj);
1054 QDeclarativeInstruction done;
1055 done.setType(QDeclarativeInstruction::Done);
1056 output->addInstruction(done);
1058 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1061 foreach(Property *prop, obj->signalProperties) {
1063 QDeclarativeParser::Value *v = prop->values.at(0);
1065 if (v->type == Value::SignalObject) {
1067 genObject(v->object);
1069 QDeclarativeInstruction assign;
1070 assign.setType(QDeclarativeInstruction::AssignSignalObject);
1071 assign.assignSignalObject.line = v->location.start.line;
1072 assign.assignSignalObject.signal =
1073 output->indexForByteArray(prop->name);
1074 output->addInstruction(assign);
1076 } else if (v->type == Value::SignalExpression) {
1078 BindingContext ctxt = compileState.signalExpressions.value(v);
1080 QDeclarativeInstruction store;
1081 store.setType(QDeclarativeInstruction::StoreSignal);
1082 store.storeSignal.signalIndex = prop->index;
1083 store.storeSignal.value =
1084 output->indexForString(v->value.asScript().trimmed());
1085 store.storeSignal.context = ctxt.stack;
1086 store.storeSignal.name = output->indexForByteArray(prop->name);
1087 store.storeSignal.line = v->location.start.line;
1088 output->addInstruction(store);
1094 foreach(Property *prop, obj->attachedProperties) {
1095 QDeclarativeInstruction fetch;
1096 fetch.setType(QDeclarativeInstruction::FetchAttached);
1097 fetch.fetchAttached.id = prop->index;
1098 fetch.fetchAttached.line = prop->location.start.line;
1099 output->addInstruction(fetch);
1101 genObjectBody(prop->value);
1103 QDeclarativeInstruction pop;
1104 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1105 output->addInstruction(pop);
1108 foreach(Property *prop, obj->groupedProperties) {
1109 QDeclarativeInstruction fetch;
1110 fetch.setType(QDeclarativeInstruction::FetchObject);
1111 fetch.fetch.property = prop->index;
1112 fetch.fetch.line = prop->location.start.line;
1113 output->addInstruction(fetch);
1115 if (!prop->value->metadata.isEmpty()) {
1116 QDeclarativeInstruction meta;
1117 meta.setType(QDeclarativeInstruction::StoreMetaObject);
1118 meta.storeMeta.data = output->indexForByteArray(prop->value->metadata);
1119 meta.storeMeta.aliasData = output->indexForByteArray(prop->value->synthdata);
1120 meta.storeMeta.propertyCache = -1;
1121 output->addInstruction(meta);
1124 genObjectBody(prop->value);
1126 QDeclarativeInstruction pop;
1127 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1128 output->addInstruction(pop);
1131 foreach(Property *prop, obj->valueTypeProperties) {
1133 genValueTypeProperty(obj, prop);
1136 foreach(Property *prop, obj->valueProperties) {
1137 if (prop->isDeferred)
1140 genValueProperty(prop, obj);
1143 foreach(Property *prop, obj->valueTypeProperties) {
1145 genValueTypeProperty(obj, prop);
1149 void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeParser::Object *obj,QDeclarativeParser::Property *prop)
1151 QDeclarativeInstruction fetch;
1152 fetch.setType(QDeclarativeInstruction::FetchValueType);
1153 fetch.fetchValue.property = prop->index;
1154 fetch.fetchValue.type = prop->type;
1155 fetch.fetchValue.bindingSkipList = 0;
1157 if (obj->type == -1 || output->types.at(obj->type).component) {
1158 // We only have to do this if this is a composite type. If it is a builtin
1159 // type it can't possibly already have bindings that need to be cleared.
1160 foreach(Property *vprop, prop->value->valueProperties) {
1161 if (!vprop->values.isEmpty()) {
1162 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1163 fetch.fetchValue.bindingSkipList |= (1 << vprop->index);
1168 output->addInstruction(fetch);
1170 foreach(Property *vprop, prop->value->valueProperties) {
1171 genPropertyAssignment(vprop, prop->value, prop);
1174 QDeclarativeInstruction pop;
1175 pop.setType(QDeclarativeInstruction::PopValueType);
1176 pop.fetchValue.property = prop->index;
1177 pop.fetchValue.type = prop->type;
1178 pop.fetchValue.bindingSkipList = 0;
1179 output->addInstruction(pop);
1182 void QDeclarativeCompiler::genComponent(QDeclarativeParser::Object *obj)
1184 QDeclarativeParser::Object *root = obj->defaultProperty->values.at(0)->object;
1187 QDeclarativeInstruction create;
1188 create.setType(QDeclarativeInstruction::CreateComponent);
1189 create.createComponent.line = root->location.start.line;
1190 create.createComponent.column = root->location.start.column;
1191 create.createComponent.endLine = root->location.end.line;
1192 int createInstruction = output->addInstruction(create);
1193 int nextInstructionIndex = output->nextInstructionIndex();
1195 ComponentCompileState oldCompileState = compileState;
1196 compileState = componentState(root);
1198 QDeclarativeInstruction init;
1199 init.setType(QDeclarativeInstruction::Init);
1200 init.init.bindingsSize = compileState.bindings.count();
1201 init.init.parserStatusSize = compileState.parserStatusCount;
1202 init.init.contextCache = genContextCache();
1203 if (compileState.compiledBindingData.isEmpty())
1204 init.init.compiledBinding = -1;
1206 init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData);
1207 output->addInstruction(init);
1211 QDeclarativeInstruction def;
1212 def.setType(QDeclarativeInstruction::SetDefault);
1213 output->addInstruction(def);
1215 QDeclarativeInstruction done;
1216 done.setType(QDeclarativeInstruction::Done);
1217 output->addInstruction(done);
1219 output->instruction(createInstruction)->createComponent.count =
1220 output->nextInstructionIndex() - nextInstructionIndex;
1222 compileState = oldCompileState;
1224 if (!obj->id.isEmpty()) {
1225 QDeclarativeInstruction id;
1226 id.setType(QDeclarativeInstruction::SetId);
1227 id.setId.value = output->indexForString(obj->id);
1228 id.setId.index = obj->idIndex;
1229 output->addInstruction(id);
1233 bool QDeclarativeCompiler::buildComponent(QDeclarativeParser::Object *obj,
1234 const BindingContext &ctxt)
1236 // The special "Component" element can only have the id property and a
1237 // default property, that actually defines the component's tree
1239 // Find, check and set the "id" property (if any)
1240 Property *idProp = 0;
1241 if (obj->properties.count() > 1 ||
1242 (obj->properties.count() == 1 && obj->properties.begin().key() != "id"))
1243 COMPILE_EXCEPTION(*obj->properties.begin(), tr("Component elements may not contain properties other than id"));
1245 if (obj->properties.count())
1246 idProp = *obj->properties.begin();
1249 if (idProp->value || idProp->values.count() > 1 || idProp->values.at(0)->object)
1250 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1251 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1253 QString idVal = idProp->values.first()->primitive();
1255 if (compileState.ids.contains(idVal))
1256 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1262 // Check the Component tree is well formed
1263 if (obj->defaultProperty &&
1264 (obj->defaultProperty->value || obj->defaultProperty->values.count() > 1 ||
1265 (obj->defaultProperty->values.count() == 1 && !obj->defaultProperty->values.first()->object)))
1266 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1268 if (!obj->dynamicProperties.isEmpty())
1269 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1270 if (!obj->dynamicSignals.isEmpty())
1271 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1272 if (!obj->dynamicSlots.isEmpty())
1273 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1275 QDeclarativeParser::Object *root = 0;
1276 if (obj->defaultProperty && obj->defaultProperty->values.count())
1277 root = obj->defaultProperty->values.first()->object;
1280 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1282 // Build the component tree
1283 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1288 bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeParser::Object *obj,
1289 const BindingContext &ctxt)
1291 ComponentCompileState oldComponentCompileState = compileState;
1292 ComponentStat oldComponentStat = componentStat;
1294 compileState = ComponentCompileState();
1295 compileState.root = obj;
1296 compileState.nested = true;
1298 componentStat = ComponentStat();
1299 componentStat.lineNumber = obj->location.start.line;
1302 COMPILE_CHECK(buildObject(obj, ctxt));
1304 COMPILE_CHECK(completeComponentBuild());
1306 compileState = oldComponentCompileState;
1307 componentStat = oldComponentStat;
1313 // Build a sub-object. A sub-object is one that was not created directly by
1314 // QML - such as a grouped property object, or an attached object. Sub-object's
1315 // can't have an id, involve a custom parser, have attached properties etc.
1316 bool QDeclarativeCompiler::buildSubObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
1318 Q_ASSERT(obj->metatype);
1319 Q_ASSERT(!obj->defaultProperty);
1320 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1323 foreach(Property *prop, obj->properties) {
1324 if (isSignalPropertyName(prop->name)) {
1325 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1327 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1334 int QDeclarativeCompiler::componentTypeRef()
1336 QDeclarativeType *t = QDeclarativeMetaType::qmlType("QtQuick/Component",1,0);
1337 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1338 if (output->types.at(ii).type == t)
1341 QDeclarativeCompiledData::TypeReference ref;
1342 ref.className = "Component";
1344 output->types << ref;
1345 return output->types.count() - 1;
1348 bool QDeclarativeCompiler::buildSignal(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj,
1349 const BindingContext &ctxt)
1351 Q_ASSERT(obj->metaObject());
1353 QByteArray name = prop->name;
1354 Q_ASSERT(name.startsWith("on"));
1357 // Note that the property name could start with any alpha or '_' or '$' character,
1358 // so we need to do the lower-casing of the first alpha character.
1359 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1360 if (name[firstAlphaIndex] >= 'A' && name[firstAlphaIndex] <= 'Z') {
1361 name[firstAlphaIndex] = name[firstAlphaIndex] - 'A' + 'a';
1366 bool notInRevision = false;
1367 int sigIdx = indexOfSignal(obj, name, ¬InRevision);
1371 if (notInRevision && -1 == indexOfProperty(obj, prop->name, 0)) {
1372 Q_ASSERT(obj->type != -1);
1373 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1374 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1376 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));
1378 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)));
1382 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1384 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1388 if (prop->value || prop->values.count() != 1)
1389 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1391 prop->index = sigIdx;
1392 obj->addSignalProperty(prop);
1394 if (prop->values.at(0)->object) {
1395 COMPILE_CHECK(buildObject(prop->values.at(0)->object, ctxt));
1396 prop->values.at(0)->type = Value::SignalObject;
1398 prop->values.at(0)->type = Value::SignalExpression;
1400 if (!prop->values.at(0)->value.isScript())
1401 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1403 QString script = prop->values.at(0)->value.asScript().trimmed();
1404 if (script.isEmpty())
1405 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1407 compileState.signalExpressions.insert(prop->values.at(0), ctxt);
1416 Returns true if (value) property \a prop exists on obj, false otherwise.
1418 bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeParser::Property *prop,
1419 QDeclarativeParser::Object *obj)
1421 if(isAttachedPropertyName(prop->name) || prop->name == "id")
1424 const QMetaObject *mo = obj->metaObject();
1426 if (prop->isDefault) {
1427 QMetaProperty p = QDeclarativeMetaType::defaultProperty(mo);
1428 return p.name() != 0;
1430 int idx = indexOfProperty(obj, prop->name);
1431 return idx != -1 && mo->property(idx).isScriptable();
1438 bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop,
1439 QDeclarativeParser::Object *obj,
1440 const BindingContext &ctxt)
1442 if (prop->isEmpty())
1443 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1445 const QMetaObject *metaObject = obj->metaObject();
1446 Q_ASSERT(metaObject);
1448 if (isAttachedPropertyName(prop->name)) {
1449 // Setup attached property data
1451 if (ctxt.isSubContext()) {
1452 // Attached properties cannot be used on sub-objects. Sub-objects
1453 // always exist in a binding sub-context, which is what we test
1455 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1458 QDeclarativeType *type = 0;
1459 QDeclarativeImportedNamespace *typeNamespace = 0;
1460 unit->imports().resolveType(prop->name, &type, 0, 0, 0, &typeNamespace);
1462 if (typeNamespace) {
1463 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1466 } else if (!type || !type->attachedPropertiesType()) {
1467 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1471 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1473 Q_ASSERT(type->attachedPropertiesFunction());
1474 prop->index = type->attachedPropertiesId();
1475 prop->value->metatype = type->attachedPropertiesType();
1477 // Setup regular property data
1480 if (prop->isDefault) {
1481 p = QDeclarativeMetaType::defaultProperty(metaObject);
1484 prop->index = p.propertyIndex();
1485 prop->name = p.name();
1489 bool notInRevision = false;
1490 prop->index = indexOfProperty(obj, prop->name, ¬InRevision);
1491 if (prop->index == -1 && notInRevision) {
1492 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1493 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1495 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));
1497 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)));
1501 if (prop->index != -1) {
1502 p = metaObject->property(prop->index);
1505 if (!p.isScriptable()) {
1507 p = QMetaProperty();
1512 // We can't error here as the "id" property does not require a
1513 // successful index resolution
1515 prop->type = p.userType();
1517 // Check if this is an alias
1518 if (prop->index != -1 &&
1520 prop->parent->type != -1 &&
1521 output->types.at(prop->parent->type).component) {
1523 QDeclarativePropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1524 if (cache && cache->property(prop->index) &&
1525 cache->property(prop->index)->flags & QDeclarativePropertyCache::Data::IsAlias)
1526 prop->isAlias = true;
1529 if (prop->index != -1 && !prop->values.isEmpty())
1530 prop->parent->setBindingBit(prop->index);
1533 if (!prop->isDefault && prop->name == "id" && !ctxt.isSubContext()) {
1535 // The magic "id" behavior doesn't apply when "id" is resolved as a
1536 // default property or to sub-objects (which are always in binding
1538 COMPILE_CHECK(buildIdProperty(prop, obj));
1539 if (prop->type == QVariant::String &&
1540 prop->values.at(0)->value.isString())
1541 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1543 } else if (isAttachedPropertyName(prop->name)) {
1545 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1547 } else if (prop->index == -1) {
1549 if (prop->isDefault) {
1550 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1552 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1555 } else if (prop->value) {
1557 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1559 } else if (enginePrivate->isList(prop->type)) {
1561 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1563 } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) {
1565 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1569 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1576 bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
1577 QDeclarativeParser::Property *nsProp,
1578 QDeclarativeParser::Object *obj,
1579 const BindingContext &ctxt)
1582 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1584 foreach (Property *prop, nsProp->value->properties) {
1586 if (!isAttachedPropertyName(prop->name))
1587 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1589 // Setup attached property data
1591 QDeclarativeType *type = 0;
1592 unit->imports().resolveType(ns, prop->name, &type, 0, 0, 0);
1594 if (!type || !type->attachedPropertiesType())
1595 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1598 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1600 Q_ASSERT(type->attachedPropertiesFunction());
1601 prop->index = type->index();
1602 prop->value->metatype = type->attachedPropertiesType();
1604 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1610 void QDeclarativeCompiler::genValueProperty(QDeclarativeParser::Property *prop,
1611 QDeclarativeParser::Object *obj)
1613 if (enginePrivate->isList(prop->type)) {
1614 genListProperty(prop, obj);
1616 genPropertyAssignment(prop, obj);
1620 void QDeclarativeCompiler::genListProperty(QDeclarativeParser::Property *prop,
1621 QDeclarativeParser::Object *obj)
1623 int listType = enginePrivate->listType(prop->type);
1625 QDeclarativeInstruction fetch;
1626 fetch.setType(QDeclarativeInstruction::FetchQList);
1627 fetch.fetchQmlList.property = prop->index;
1628 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1629 fetch.fetchQmlList.type = listType;
1630 output->addInstruction(fetch);
1632 for (int ii = 0; ii < prop->values.count(); ++ii) {
1633 QDeclarativeParser::Value *v = prop->values.at(ii);
1635 if (v->type == Value::CreatedObject) {
1637 genObject(v->object);
1638 if (listTypeIsInterface) {
1639 QDeclarativeInstruction assign;
1640 assign.setType(QDeclarativeInstruction::AssignObjectList);
1641 assign.assignObjectList.line = prop->location.start.line;
1642 output->addInstruction(assign);
1644 QDeclarativeInstruction store;
1645 store.setType(QDeclarativeInstruction::StoreObjectQList);
1646 output->addInstruction(store);
1649 } else if (v->type == Value::PropertyBinding) {
1651 genBindingAssignment(v, prop, obj);
1657 QDeclarativeInstruction pop;
1658 pop.setType(QDeclarativeInstruction::PopQList);
1659 output->addInstruction(pop);
1662 void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *prop,
1663 QDeclarativeParser::Object *obj,
1664 QDeclarativeParser::Property *valueTypeProperty)
1666 for (int ii = 0; ii < prop->values.count(); ++ii) {
1667 QDeclarativeParser::Value *v = prop->values.at(ii);
1669 Q_ASSERT(v->type == Value::CreatedObject ||
1670 v->type == Value::PropertyBinding ||
1671 v->type == Value::Literal);
1673 if (v->type == Value::CreatedObject) {
1675 genObject(v->object);
1677 if (QDeclarativeMetaType::isInterface(prop->type)) {
1679 QDeclarativeInstruction store;
1680 store.setType(QDeclarativeInstruction::StoreInterface);
1681 store.storeObject.line = v->object->location.start.line;
1682 store.storeObject.propertyIndex = prop->index;
1683 output->addInstruction(store);
1685 } else if (prop->type == -1) {
1687 QDeclarativeInstruction store;
1688 store.setType(QDeclarativeInstruction::StoreVariantObject);
1689 store.storeObject.line = v->object->location.start.line;
1690 store.storeObject.propertyIndex = prop->index;
1691 output->addInstruction(store);
1695 QDeclarativeInstruction store;
1696 store.setType(QDeclarativeInstruction::StoreObject);
1697 store.storeObject.line = v->object->location.start.line;
1698 store.storeObject.propertyIndex = prop->index;
1699 output->addInstruction(store);
1702 } else if (v->type == Value::PropertyBinding) {
1704 genBindingAssignment(v, prop, obj, valueTypeProperty);
1706 } else if (v->type == Value::Literal) {
1708 QMetaProperty mp = obj->metaObject()->property(prop->index);
1709 genLiteralAssignment(mp, v);
1715 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
1717 QDeclarativeParser::Value *v = prop->onValues.at(ii);
1719 Q_ASSERT(v->type == Value::ValueSource ||
1720 v->type == Value::ValueInterceptor);
1722 if (v->type == Value::ValueSource) {
1723 genObject(v->object);
1725 QDeclarativeInstruction store;
1726 store.setType(QDeclarativeInstruction::StoreValueSource);
1727 if (valueTypeProperty) {
1728 store.assignValueSource.property = genValueTypeData(prop, valueTypeProperty);
1729 store.assignValueSource.owner = 1;
1731 store.assignValueSource.property = genPropertyData(prop);
1732 store.assignValueSource.owner = 0;
1734 QDeclarativeType *valueType = toQmlType(v->object);
1735 store.assignValueSource.castValue = valueType->propertyValueSourceCast();
1736 output->addInstruction(store);
1738 } else if (v->type == Value::ValueInterceptor) {
1739 genObject(v->object);
1741 QDeclarativeInstruction store;
1742 store.setType(QDeclarativeInstruction::StoreValueInterceptor);
1743 if (valueTypeProperty) {
1744 store.assignValueInterceptor.property = genValueTypeData(prop, valueTypeProperty);
1745 store.assignValueInterceptor.owner = 1;
1747 store.assignValueInterceptor.property = genPropertyData(prop);
1748 store.assignValueInterceptor.owner = 0;
1750 QDeclarativeType *valueType = toQmlType(v->object);
1751 store.assignValueInterceptor.castValue = valueType->propertyValueInterceptorCast();
1752 output->addInstruction(store);
1758 bool QDeclarativeCompiler::buildIdProperty(QDeclarativeParser::Property *prop,
1759 QDeclarativeParser::Object *obj)
1762 prop->values.count() > 1 ||
1763 prop->values.at(0)->object)
1764 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
1766 QDeclarativeParser::Value *idValue = prop->values.at(0);
1767 QString val = idValue->primitive();
1769 COMPILE_CHECK(checkValidId(idValue, val));
1771 if (compileState.ids.contains(val))
1772 COMPILE_EXCEPTION(prop, tr("id is not unique"));
1774 prop->values.at(0)->type = Value::Id;
1782 void QDeclarativeCompiler::addId(const QString &id, QDeclarativeParser::Object *obj)
1784 Q_ASSERT(!compileState.ids.contains(id));
1785 Q_ASSERT(obj->id == id);
1786 obj->idIndex = compileState.ids.count();
1787 compileState.ids.insert(id, obj);
1788 compileState.idIndexes.insert(obj->idIndex, obj);
1791 void QDeclarativeCompiler::addBindingReference(const BindingReference &ref)
1793 Q_ASSERT(ref.value && !compileState.bindings.contains(ref.value));
1794 compileState.bindings.insert(ref.value, ref);
1797 void QDeclarativeCompiler::saveComponentState()
1799 Q_ASSERT(compileState.root);
1800 Q_ASSERT(!savedCompileStates.contains(compileState.root));
1802 savedCompileStates.insert(compileState.root, compileState);
1803 savedComponentStats.append(componentStat);
1806 QDeclarativeCompiler::ComponentCompileState
1807 QDeclarativeCompiler::componentState(QDeclarativeParser::Object *obj)
1809 Q_ASSERT(savedCompileStates.contains(obj));
1810 return savedCompileStates.value(obj);
1813 // Build attached property object. In this example,
1817 // GridView is an attached property object.
1818 bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeParser::Property *prop,
1819 QDeclarativeParser::Object *obj,
1820 const BindingContext &ctxt)
1822 Q_ASSERT(prop->value);
1823 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
1825 obj->addAttachedProperty(prop);
1827 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1833 // Build "grouped" properties. In this example:
1835 // font.pointSize: 12
1836 // font.family: "Helvetica"
1838 // font is a nested property. pointSize and family are not.
1839 bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeParser::Property *prop,
1840 QDeclarativeParser::Object *obj,
1841 const BindingContext &ctxt)
1843 Q_ASSERT(prop->type != 0);
1844 Q_ASSERT(prop->index != -1);
1846 if (QDeclarativeValueTypeFactory::isValueType(prop->type)) {
1847 if (prop->type >= 0 /* QVariant == -1 */ && enginePrivate->valueTypes[prop->type]) {
1849 if (prop->values.count()) {
1850 if (prop->values.at(0)->location < prop->value->location) {
1851 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
1853 COMPILE_EXCEPTION(prop->values.at(0), tr( "Property has already been assigned a value"));
1857 if (!obj->metaObject()->property(prop->index).isWritable()) {
1858 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
1862 if (prop->isAlias) {
1863 foreach (Property *vtProp, prop->value->properties)
1864 vtProp->isAlias = true;
1867 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
1868 prop->value, obj, ctxt.incr()));
1869 obj->addValueTypeProperty(prop);
1871 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1875 // Load the nested property's meta type
1876 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
1877 if (!prop->value->metatype)
1878 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1880 if (prop->values.count())
1881 COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign a value directly to a grouped property"));
1883 obj->addGroupedProperty(prop);
1885 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1891 bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
1892 QDeclarativeParser::Object *obj,
1893 QDeclarativeParser::Object *baseObj,
1894 const BindingContext &ctxt)
1896 if (obj->defaultProperty)
1897 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
1898 obj->metatype = type->metaObject();
1900 foreach (Property *prop, obj->properties) {
1901 int idx = type->metaObject()->indexOfProperty(prop->name.constData());
1903 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1904 QMetaProperty p = type->metaObject()->property(idx);
1905 if (!p.isScriptable())
1906 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1908 prop->type = p.userType();
1909 prop->isValueTypeSubProperty = true;
1912 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
1914 if (prop->values.count() > 1) {
1915 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
1916 } else if (prop->values.count()) {
1917 QDeclarativeParser::Value *value = prop->values.at(0);
1919 if (value->object) {
1920 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
1921 } else if (value->value.isScript()) {
1922 // ### Check for writability
1924 //optimization for <Type>.<EnumValue> enum assignments
1925 bool isEnumAssignment = false;
1926 COMPILE_CHECK(testQualifiedEnumAssignment(p, obj, value, &isEnumAssignment));
1927 if (isEnumAssignment) {
1928 value->type = Value::Literal;
1930 BindingReference reference;
1931 reference.expression = value->value;
1932 reference.property = prop;
1933 reference.value = value;
1934 reference.bindingContext = ctxt;
1935 reference.bindingContext.owner++;
1936 addBindingReference(reference);
1937 value->type = Value::PropertyBinding;
1940 COMPILE_CHECK(testLiteralAssignment(p, value));
1941 value->type = Value::Literal;
1945 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
1946 QDeclarativeParser::Value *v = prop->onValues.at(ii);
1947 Q_ASSERT(v->object);
1949 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
1952 obj->addValueProperty(prop);
1958 // Build assignments to QML lists. QML lists are properties of type
1959 // QDeclarativeListProperty<T>. List properties can accept a list of
1960 // objects, or a single binding.
1961 bool QDeclarativeCompiler::buildListProperty(QDeclarativeParser::Property *prop,
1962 QDeclarativeParser::Object *obj,
1963 const BindingContext &ctxt)
1965 Q_ASSERT(enginePrivate->isList(prop->type));
1969 obj->addValueProperty(prop);
1971 int listType = enginePrivate->listType(t);
1972 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1974 bool assignedBinding = false;
1975 for (int ii = 0; ii < prop->values.count(); ++ii) {
1976 QDeclarativeParser::Value *v = prop->values.at(ii);
1978 v->type = Value::CreatedObject;
1979 COMPILE_CHECK(buildObject(v->object, ctxt));
1981 // We check object coercian here. We check interface assignment
1983 if (!listTypeIsInterface) {
1984 if (!canCoerce(listType, v->object)) {
1985 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
1989 } else if (v->value.isScript()) {
1990 if (assignedBinding)
1991 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
1993 assignedBinding = true;
1994 COMPILE_CHECK(buildBinding(v, prop, ctxt));
1995 v->type = Value::PropertyBinding;
1997 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2004 // Compiles an assignment to a QDeclarativeScriptString property
2005 bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeParser::Property *prop,
2006 QDeclarativeParser::Object *obj,
2007 const BindingContext &ctxt)
2009 if (prop->values.count() > 1)
2010 COMPILE_EXCEPTION(prop->values.at(1), tr( "Cannot assign multiple values to a script property"));
2012 if (prop->values.at(0)->object)
2013 COMPILE_EXCEPTION(prop->values.at(0), tr( "Invalid property assignment: script expected"));
2015 obj->addScriptStringProperty(prop, ctxt.stack);
2020 // Compile regular property assignments of the form "property: <value>"
2021 bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeParser::Property *prop,
2022 QDeclarativeParser::Object *obj,
2023 const BindingContext &ctxt)
2025 obj->addValueProperty(prop);
2027 if (prop->values.count() > 1)
2028 COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign multiple values to a singular property") );
2030 for (int ii = 0; ii < prop->values.count(); ++ii) {
2031 QDeclarativeParser::Value *v = prop->values.at(ii);
2034 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2038 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2043 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
2044 QDeclarativeParser::Value *v = prop->onValues.at(ii);
2046 Q_ASSERT(v->object);
2047 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2053 // Compile assigning a single object instance to a regular property
2054 bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeParser::Property *prop,
2055 QDeclarativeParser::Object *obj,
2056 QDeclarativeParser::Value *v,
2057 const BindingContext &ctxt)
2059 Q_ASSERT(prop->index != -1);
2060 Q_ASSERT(v->object->type != -1);
2062 if (!obj->metaObject()->property(prop->index).isWritable())
2063 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2065 if (QDeclarativeMetaType::isInterface(prop->type)) {
2067 // Assigning an object to an interface ptr property
2068 COMPILE_CHECK(buildObject(v->object, ctxt));
2070 v->type = Value::CreatedObject;
2072 } else if (prop->type == -1) {
2074 // Assigning an object to a QVariant
2075 COMPILE_CHECK(buildObject(v->object, ctxt));
2077 v->type = Value::CreatedObject;
2079 // Normally buildObject() will set this up, but we need the static
2080 // meta object earlier to test for assignability. It doesn't matter
2081 // that there may still be outstanding synthesized meta object changes
2082 // on this type, as they are not relevant for assignability testing
2083 v->object->metatype = output->types.at(v->object->type).metaObject();
2084 Q_ASSERT(v->object->metaObject());
2086 // We want to raw metaObject here as the raw metaobject is the
2087 // actual property type before we applied any extensions that might
2088 // effect the properties on the type, but don't effect assignability
2089 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2091 // Will be true if the assgned type inherits propertyMetaObject
2092 bool isAssignable = false;
2093 // Determine isAssignable value
2094 if (propertyMetaObject) {
2095 const QMetaObject *c = v->object->metatype;
2097 isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject));
2098 c = c->superClass();
2103 // Simple assignment
2104 COMPILE_CHECK(buildObject(v->object, ctxt));
2106 v->type = Value::CreatedObject;
2107 } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) {
2108 // Automatic "Component" insertion
2109 QDeclarativeParser::Object *root = v->object;
2110 QDeclarativeParser::Object *component = new QDeclarativeParser::Object;
2111 component->type = componentTypeRef();
2112 component->typeName = "Qt/Component";
2113 component->metatype = &QDeclarativeComponent::staticMetaObject;
2114 component->location = root->location;
2115 QDeclarativeParser::Value *componentValue = new QDeclarativeParser::Value;
2116 componentValue->object = root;
2117 component->getDefaultProperty()->addValue(componentValue);
2118 v->object = component;
2119 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2121 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2128 // Compile assigning a single object instance to a regular property using the "on" syntax.
2132 // NumberAnimation on x { }
2134 bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeParser::Property *prop,
2135 QDeclarativeParser::Object *obj,
2136 QDeclarativeParser::Object *baseObj,
2137 QDeclarativeParser::Value *v,
2138 const BindingContext &ctxt)
2140 Q_ASSERT(prop->index != -1);
2141 Q_ASSERT(v->object->type != -1);
2143 if (!obj->metaObject()->property(prop->index).isWritable())
2144 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2147 // Normally buildObject() will set this up, but we need the static
2148 // meta object earlier to test for assignability. It doesn't matter
2149 // that there may still be outstanding synthesized meta object changes
2150 // on this type, as they are not relevant for assignability testing
2151 v->object->metatype = output->types.at(v->object->type).metaObject();
2152 Q_ASSERT(v->object->metaObject());
2154 // Will be true if the assigned type inherits QDeclarativePropertyValueSource
2155 bool isPropertyValue = false;
2156 // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor
2157 bool isPropertyInterceptor = false;
2158 if (QDeclarativeType *valueType = toQmlType(v->object)) {
2159 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2160 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2163 if (isPropertyValue || isPropertyInterceptor) {
2164 // Assign as a property value source
2165 COMPILE_CHECK(buildObject(v->object, ctxt));
2167 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2168 buildDynamicMeta(baseObj, ForceCreation);
2169 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2171 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(QString::fromUtf8(v->object->typeName)).arg(QString::fromUtf8(prop->name.constData())));
2177 // Compile assigning a literal or binding to a regular property
2178 bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeParser::Property *prop,
2179 QDeclarativeParser::Object *obj,
2180 QDeclarativeParser::Value *v,
2181 const BindingContext &ctxt)
2183 Q_ASSERT(prop->index != -1);
2185 if (v->value.isScript()) {
2187 //optimization for <Type>.<EnumValue> enum assignments
2188 bool isEnumAssignment = false;
2189 COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj, v, &isEnumAssignment));
2190 if (isEnumAssignment) {
2191 v->type = Value::Literal;
2195 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2197 v->type = Value::PropertyBinding;
2201 COMPILE_CHECK(testLiteralAssignment(obj->metaObject()->property(prop->index), v));
2203 v->type = Value::Literal;
2209 bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop,
2210 QDeclarativeParser::Object *obj,
2211 QDeclarativeParser::Value *v,
2214 *isAssignment = false;
2215 if (!prop.isEnumType())
2218 if (!prop.isWritable())
2219 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
2221 QString string = v->value.asString();
2222 if (!string.at(0).isUpper())
2225 QStringList parts = string.split(QLatin1Char('.'));
2226 if (parts.count() != 2)
2229 QString typeName = parts.at(0);
2230 QDeclarativeType *type = 0;
2231 unit->imports().resolveType(typeName.toUtf8(), &type, 0, 0, 0, 0);
2233 //handle enums on value types (where obj->typeName is empty)
2234 QByteArray objTypeName = obj->typeName;
2235 if (objTypeName.isEmpty()) {
2236 QDeclarativeType *objType = toQmlType(obj);
2238 objTypeName = objType->qmlTypeName();
2244 QString enumValue = parts.at(1);
2247 if (objTypeName == type->qmlTypeName()) {
2248 // When these two match, we can short cut the search
2249 if (prop.isFlagType()) {
2250 value = prop.enumerator().keysToValue(enumValue.toUtf8().constData());
2252 value = prop.enumerator().keyToValue(enumValue.toUtf8().constData());
2255 // Otherwise we have to search the whole type
2256 // This matches the logic in QDeclarativeTypeNameScriptClass
2257 QByteArray enumName = enumValue.toUtf8();
2258 const QMetaObject *metaObject = type->baseMetaObject();
2259 for (int ii = metaObject->enumeratorCount() - 1; value == -1 && ii >= 0; --ii) {
2260 QMetaEnum e = metaObject->enumerator(ii);
2261 value = e.keyToValue(enumName.constData());
2268 v->type = Value::Literal;
2269 v->value = QDeclarativeParser::Variant((double)value);
2270 *isAssignment = true;
2275 // Similar logic to above, but not knowing target property.
2276 int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const
2278 int dot = script.indexOf('.');
2280 QDeclarativeType *type = 0;
2281 unit->imports().resolveType(script.left(dot), &type, 0, 0, 0, 0);
2284 const QMetaObject *mo = type->metaObject();
2285 const char *key = script.constData() + dot+1;
2286 int i = mo->enumeratorCount();
2288 int v = mo->enumerator(i).keyToValue(key);
2296 const QMetaObject *QDeclarativeCompiler::resolveType(const QByteArray& name) const
2298 QDeclarativeType *qmltype = 0;
2299 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2303 return qmltype->metaObject();
2306 // similar to logic of completeComponentBuild, but also sticks data
2307 // into datas at the end
2308 int QDeclarativeCompiler::rewriteBinding(const QString& expression, const QByteArray& name)
2310 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2311 rewriteBinding.setName('$' + name.mid(name.lastIndexOf('.') + 1));
2312 bool isSharable = false;
2313 QString rewrite = rewriteBinding(expression, 0, &isSharable);
2315 quint32 length = rewrite.length();
2319 pc = output->cachedClosures.count();
2321 output->cachedClosures.append(0);
2323 pc = output->cachedPrograms.length();
2324 output->cachedPrograms.append(0);
2327 QByteArray compiledData =
2328 QByteArray((const char *)&pc, sizeof(quint32)) +
2329 QByteArray((const char *)&length, sizeof(quint32)) +
2330 QByteArray((const char *)rewrite.constData(),
2331 rewrite.length() * sizeof(QChar));
2333 return output->indexForByteArray(compiledData);
2336 // Ensures that the dynamic meta specification on obj is valid
2337 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj)
2339 QSet<QByteArray> propNames;
2340 QSet<QByteArray> methodNames;
2341 bool seenDefaultProperty = false;
2344 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2345 const QDeclarativeParser::Object::DynamicProperty &prop =
2346 obj->dynamicProperties.at(ii);
2348 if (prop.isDefaultProperty) {
2349 if (seenDefaultProperty)
2350 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2351 seenDefaultProperty = true;
2354 if (propNames.contains(prop.name))
2355 COMPILE_EXCEPTION(&prop, tr("Duplicate property name"));
2357 QString propName = QString::fromUtf8(prop.name);
2358 if (propName.at(0).isUpper())
2359 COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
2361 if (enginePrivate->globalClass->illegalNames().contains(propName))
2362 COMPILE_EXCEPTION(&prop, tr("Illegal property name"));
2364 propNames.insert(prop.name);
2367 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2368 QByteArray name = obj->dynamicSignals.at(ii).name;
2369 if (methodNames.contains(name))
2370 COMPILE_EXCEPTION(obj, tr("Duplicate signal name"));
2371 QString nameStr = QString::fromUtf8(name);
2372 if (nameStr.at(0).isUpper())
2373 COMPILE_EXCEPTION(obj, tr("Signal names cannot begin with an upper case letter"));
2374 if (enginePrivate->globalClass->illegalNames().contains(nameStr))
2375 COMPILE_EXCEPTION(obj, tr("Illegal signal name"));
2376 methodNames.insert(name);
2378 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2379 QByteArray name = obj->dynamicSlots.at(ii).name;
2380 if (methodNames.contains(name))
2381 COMPILE_EXCEPTION(obj, tr("Duplicate method name"));
2382 QString nameStr = QString::fromUtf8(name);
2383 if (nameStr.at(0).isUpper())
2384 COMPILE_EXCEPTION(obj, tr("Method names cannot begin with an upper case letter"));
2385 if (enginePrivate->globalClass->illegalNames().contains(nameStr))
2386 COMPILE_EXCEPTION(obj, tr("Illegal method name"));
2387 methodNames.insert(name);
2393 bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeParser::Object *obj)
2395 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2396 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2398 if (!p.defaultValue || p.type == Object::DynamicProperty::Alias)
2401 Property *property = 0;
2402 if (p.isDefaultProperty) {
2403 property = obj->getDefaultProperty();
2405 property = obj->getProperty(p.name);
2406 if (!property->values.isEmpty())
2407 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2410 if (property->value)
2411 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2413 for (int ii = 0; ii < p.defaultValue->values.count(); ++ii) {
2414 QDeclarativeParser::Value *v = p.defaultValue->values.at(ii);
2416 property->values.append(v);
2422 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2424 bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, DynamicMetaMode mode)
2427 Q_ASSERT(obj->metatype);
2429 if (mode != ForceCreation &&
2430 obj->dynamicProperties.isEmpty() &&
2431 obj->dynamicSignals.isEmpty() &&
2432 obj->dynamicSlots.isEmpty())
2435 QByteArray dynamicData(sizeof(QDeclarativeVMEMetaData), (char)0);
2437 QByteArray newClassName = obj->metatype->className();
2438 newClassName.append("_QML_");
2439 int idx = classIndexCounter()->fetchAndAddRelaxed(1);
2440 newClassName.append(QByteArray::number(idx));
2441 if (compileState.root == obj && !compileState.nested) {
2442 QString path = output->url.path();
2443 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2444 if (lastSlash > -1) {
2445 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2446 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2447 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(idx);
2451 QMetaObjectBuilder builder;
2452 builder.setClassName(newClassName);
2453 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
2455 bool hasAlias = false;
2456 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2457 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2459 int propIdx = obj->metaObject()->indexOfProperty(p.name.constData());
2460 if (-1 != propIdx) {
2461 QMetaProperty prop = obj->metaObject()->property(propIdx);
2463 COMPILE_EXCEPTION(&p, tr("Cannot override FINAL property"));
2466 if (p.isDefaultProperty &&
2467 (p.type != Object::DynamicProperty::Alias ||
2468 mode == ResolveAliases))
2469 builder.addClassInfo("DefaultProperty", p.name);
2472 int propertyType = 0;
2473 bool readonly = false;
2475 case Object::DynamicProperty::Alias:
2479 case Object::DynamicProperty::CustomList:
2480 case Object::DynamicProperty::Custom:
2482 QByteArray customTypeName;
2483 QDeclarativeType *qmltype = 0;
2485 if (!unit->imports().resolveType(p.customType, &qmltype, &url, 0, 0, 0))
2486 COMPILE_EXCEPTION(&p, tr("Invalid property type"));
2489 QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(url);
2491 Q_ASSERT(tdata->isComplete());
2493 QDeclarativeCompiledData *data = tdata->compiledData();
2494 customTypeName = data->root->className();
2498 customTypeName = qmltype->typeName();
2501 if (p.type == Object::DynamicProperty::Custom) {
2502 type = customTypeName + '*';
2503 propertyType = QMetaType::QObjectStar;
2506 type = "QDeclarativeListProperty<";
2507 type.append(customTypeName);
2509 propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
2513 case Object::DynamicProperty::Variant:
2517 case Object::DynamicProperty::Int:
2518 propertyType = QVariant::Int;
2521 case Object::DynamicProperty::Bool:
2522 propertyType = QVariant::Bool;
2525 case Object::DynamicProperty::Real:
2526 propertyType = QVariant::Double;
2529 case Object::DynamicProperty::String:
2530 propertyType = QVariant::String;
2533 case Object::DynamicProperty::Url:
2534 propertyType = QVariant::Url;
2537 case Object::DynamicProperty::Color:
2538 propertyType = QVariant::Color;
2541 case Object::DynamicProperty::Time:
2542 propertyType = QVariant::Time;
2545 case Object::DynamicProperty::Date:
2546 propertyType = QVariant::Date;
2549 case Object::DynamicProperty::DateTime:
2550 propertyType = QVariant::DateTime;
2555 ((QDeclarativeVMEMetaData *)dynamicData.data())->propertyCount++;
2556 QDeclarativeVMEMetaData::PropertyData propertyData = { propertyType };
2557 dynamicData.append((char *)&propertyData, sizeof(propertyData));
2559 builder.addSignal(p.name + "Changed()");
2560 QMetaPropertyBuilder propBuilder =
2561 builder.addProperty(p.name, type, builder.methodCount() - 1);
2562 propBuilder.setWritable(!readonly);
2565 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2566 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2568 if (p.type == Object::DynamicProperty::Alias) {
2569 if (mode == ResolveAliases) {
2570 ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++;
2571 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, p));
2573 // Need a fake signal so that the metaobject remains consistent across
2574 // the resolve and non-resolve alias runs
2575 builder.addSignal(p.name + "Changed()");
2580 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2581 const Object::DynamicSignal &s = obj->dynamicSignals.at(ii);
2582 QByteArray sig(s.name + '(');
2583 for (int jj = 0; jj < s.parameterTypes.count(); ++jj) {
2584 if (jj) sig.append(',');
2585 sig.append(s.parameterTypes.at(jj));
2588 QMetaMethodBuilder b = builder.addSignal(sig);
2589 b.setParameterNames(s.parameterNames);
2590 ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++;
2593 QStringList funcScripts;
2595 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2596 Object::DynamicSlot &s = obj->dynamicSlots[ii];
2597 QByteArray sig(s.name + '(');
2598 QString funcScript(QLatin1String("(function ") + s.name + QLatin1Char('('));
2600 for (int jj = 0; jj < s.parameterNames.count(); ++jj) {
2603 funcScript.append(QLatin1Char(','));
2605 funcScript.append(QLatin1String(s.parameterNames.at(jj)));
2606 sig.append("QVariant");
2609 funcScript.append(QLatin1Char(')'));
2610 funcScript.append(s.body);
2611 funcScript.append(QLatin1Char(')'));
2612 funcScripts << funcScript;
2614 QMetaMethodBuilder b = builder.addSlot(sig);
2615 b.setReturnType("QVariant");
2616 b.setParameterNames(s.parameterNames);
2618 ((QDeclarativeVMEMetaData *)dynamicData.data())->methodCount++;
2619 QDeclarativeVMEMetaData::MethodData methodData =
2620 { s.parameterNames.count(), 0, funcScript.length(), s.location.start.line };
2622 dynamicData.append((char *)&methodData, sizeof(methodData));
2625 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2626 const QString &funcScript = funcScripts.at(ii);
2627 QDeclarativeVMEMetaData::MethodData *data =
2628 ((QDeclarativeVMEMetaData *)dynamicData.data())->methodData() + ii;
2630 data->bodyOffset = dynamicData.size();
2632 dynamicData.append((const char *)funcScript.constData(),
2633 (funcScript.length() * sizeof(QChar)));
2636 obj->metadata = builder.toRelocatableData();
2637 builder.fromRelocatableData(&obj->extObject, obj->metatype, obj->metadata);
2639 if (mode == IgnoreAliases && hasAlias)
2640 compileState.aliasingObjects << obj;
2642 obj->synthdata = dynamicData;
2644 if (obj->synthCache) {
2645 obj->synthCache->release();
2646 obj->synthCache = 0;
2649 if (obj->type != -1) {
2650 QDeclarativePropertyCache *cache = output->types[obj->type].createPropertyCache(engine)->copy();
2651 cache->append(engine, &obj->extObject, QDeclarativePropertyCache::Data::NoFlags,
2652 QDeclarativePropertyCache::Data::IsVMEFunction,
2653 QDeclarativePropertyCache::Data::IsVMESignal);
2654 obj->synthCache = cache;
2660 bool QDeclarativeCompiler::checkValidId(QDeclarativeParser::Value *v, const QString &val)
2663 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
2665 if (val.at(0).isLetter() && !val.at(0).isLower())
2666 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
2668 QChar u(QLatin1Char('_'));
2669 for (int ii = 0; ii < val.count(); ++ii) {
2671 if (ii == 0 && !val.at(ii).isLetter() && val.at(ii) != u) {
2672 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
2673 } else if (ii != 0 && !val.at(ii).isLetterOrNumber() && val.at(ii) != u) {
2674 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
2679 if (enginePrivate->globalClass->illegalNames().contains(val))
2680 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
2685 #include <qdeclarativejsparser_p.h>
2687 static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node)
2689 if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) {
2691 static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name->asString();
2692 return QStringList() << name;
2693 } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) {
2694 QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node);
2696 QStringList rv = astNodeToStringList(expr->base);
2699 rv.append(expr->name->asString());
2702 return QStringList();
2705 bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder,
2707 QDeclarativeParser::Object *obj,
2708 const Object::DynamicProperty &prop)
2710 if (!prop.defaultValue)
2711 COMPILE_EXCEPTION(obj, tr("No property alias location"));
2713 if (prop.defaultValue->values.count() != 1 ||
2714 prop.defaultValue->values.at(0)->object ||
2715 !prop.defaultValue->values.at(0)->value.isScript())
2716 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2718 QDeclarativeJS::AST::Node *node = prop.defaultValue->values.at(0)->value.asAST();
2720 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
2722 QStringList alias = astNodeToStringList(node);
2724 if (alias.count() < 1 || alias.count() > 3)
2725 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
2727 if (!compileState.ids.contains(alias.at(0)))
2728 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
2730 QDeclarativeParser::Object *idObject = compileState.ids[alias.at(0)];
2732 QByteArray typeName;
2736 bool writable = false;
2737 if (alias.count() == 2 || alias.count() == 3) {
2738 propIdx = indexOfProperty(idObject, alias.at(1).toUtf8());
2740 if (-1 == propIdx) {
2741 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2742 } else if (propIdx > 0xFFFF) {
2743 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
2746 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
2747 if (!aliasProperty.isScriptable())
2748 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2750 writable = aliasProperty.isWritable();
2752 if (alias.count() == 3) {
2753 QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
2755 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2757 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
2759 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
2760 if (valueTypeIndex == -1)
2761 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2762 Q_ASSERT(valueTypeIndex <= 0xFF);
2764 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
2765 propIdx |= (valueTypeIndex << 16);
2768 if (aliasProperty.isEnumType())
2769 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
2771 typeName = aliasProperty.typeName();
2773 typeName = idObject->metaObject()->className();
2775 //use the base type since it has been registered with metatype system
2776 int index = typeName.indexOf("_QML_");
2778 typeName = typeName.left(index);
2780 index = typeName.indexOf("_QMLTYPE_");
2781 const QMetaObject *mo = idObject->metaObject();
2782 while (index != -1 && mo) {
2783 typeName = mo->superClass()->className();
2784 index = typeName.indexOf("_QMLTYPE_");
2785 mo = mo->superClass();
2792 if (typeName.endsWith('*'))
2793 flags |= QML_ALIAS_FLAG_PTR;
2795 data.append((const char *)&idObject->idIndex, sizeof(idObject->idIndex));
2796 data.append((const char *)&propIdx, sizeof(propIdx));
2797 data.append((const char *)&flags, sizeof(flags));
2799 builder.addSignal(prop.name + "Changed()");
2800 QMetaPropertyBuilder propBuilder =
2801 builder.addProperty(prop.name, typeName.constData(), builder.methodCount() - 1);
2802 propBuilder.setWritable(writable);
2806 bool QDeclarativeCompiler::buildBinding(QDeclarativeParser::Value *value,
2807 QDeclarativeParser::Property *prop,
2808 const BindingContext &ctxt)
2810 Q_ASSERT(prop->index != -1);
2811 Q_ASSERT(prop->parent);
2812 Q_ASSERT(prop->parent->metaObject());
2814 QMetaProperty mp = prop->parent->metaObject()->property(prop->index);
2815 if (!mp.isWritable() && !QDeclarativeMetaType::isList(prop->type))
2816 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2818 BindingReference reference;
2819 reference.expression = value->value;
2820 reference.property = prop;
2821 reference.value = value;
2822 reference.bindingContext = ctxt;
2823 addBindingReference(reference);
2828 void QDeclarativeCompiler::genBindingAssignment(QDeclarativeParser::Value *binding,
2829 QDeclarativeParser::Property *prop,
2830 QDeclarativeParser::Object *obj,
2831 QDeclarativeParser::Property *valueTypeProperty)
2834 Q_ASSERT(compileState.bindings.contains(binding));
2836 const BindingReference &ref = compileState.bindings.value(binding);
2837 if (ref.dataType == BindingReference::Experimental) {
2838 QDeclarativeInstruction store;
2839 store.setType(QDeclarativeInstruction::StoreCompiledBinding);
2840 store.assignBinding.value = ref.compiledIndex;
2841 store.assignBinding.context = ref.bindingContext.stack;
2842 store.assignBinding.owner = ref.bindingContext.owner;
2843 if (valueTypeProperty)
2844 store.assignBinding.property = (valueTypeProperty->index & 0xFFFF) |
2845 ((valueTypeProperty->type & 0xFF)) << 16 |
2846 ((prop->index & 0xFF) << 24);
2848 store.assignBinding.property = prop->index;
2849 store.assignBinding.line = binding->location.start.line;
2850 output->addInstruction(store);
2854 QDeclarativeInstruction store;
2856 store.setType(QDeclarativeInstruction::StoreBinding);
2858 store.setType(QDeclarativeInstruction::StoreBindingOnAlias);
2859 store.assignBinding.value = output->indexForByteArray(ref.compiledData);
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);
2875 int QDeclarativeCompiler::genContextCache()
2877 if (compileState.ids.count() == 0)
2880 QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache(engine);
2882 for (QHash<QString, QDeclarativeParser::Object *>::ConstIterator iter = compileState.ids.begin();
2883 iter != compileState.ids.end();
2885 cache->add(iter.key(), (*iter)->idIndex);
2887 output->contextCaches.append(cache);
2888 return output->contextCaches.count() - 1;
2891 int QDeclarativeCompiler::genValueTypeData(QDeclarativeParser::Property *valueTypeProp,
2892 QDeclarativeParser::Property *prop)
2895 QDeclarativePropertyPrivate::saveValueType(prop->parent->metaObject(), prop->index,
2896 enginePrivate->valueTypes[prop->type]->metaObject(),
2897 valueTypeProp->index);
2898 // valueTypeProp->index, valueTypeProp->type);
2900 return output->indexForByteArray(data);
2903 int QDeclarativeCompiler::genPropertyData(QDeclarativeParser::Property *prop)
2905 return output->indexForByteArray(QDeclarativePropertyPrivate::saveProperty(prop->parent->metaObject(), prop->index));
2908 bool QDeclarativeCompiler::completeComponentBuild()
2910 componentStat.ids = compileState.ids.count();
2912 for (int ii = 0; ii < compileState.aliasingObjects.count(); ++ii) {
2913 QDeclarativeParser::Object *aliasObject = compileState.aliasingObjects.at(ii);
2914 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
2917 QDeclarativeV4Compiler::Expression expr;
2918 expr.component = compileState.root;
2919 expr.ids = compileState.ids;
2920 expr.importCache = output->importCache;
2921 expr.imports = unit->imports();
2923 QDeclarativeV4Compiler bindingCompiler;
2925 for (QHash<QDeclarativeParser::Value*,BindingReference>::Iterator iter = compileState.bindings.begin();
2926 iter != compileState.bindings.end(); ++iter) {
2928 BindingReference &binding = *iter;
2930 // ### We don't currently optimize for bindings on alias's - because
2931 // of the solution to QTBUG-13719
2932 if (!binding.property->isAlias) {
2933 expr.context = binding.bindingContext.object;
2934 expr.property = binding.property;
2935 expr.expression = binding.expression;
2937 int index = bindingCompiler.compile(expr, enginePrivate);
2939 binding.dataType = BindingReference::Experimental;
2940 binding.compiledIndex = index;
2941 componentStat.optimizedBindings.append(iter.key()->location);
2946 binding.dataType = BindingReference::QtScript;
2948 // Pre-rewrite the expression
2949 QString expression = binding.expression.asScript();
2951 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2952 rewriteBinding.setName('$'+binding.property->name);
2953 bool isSharable = false;
2954 expression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
2956 quint32 length = expression.length();
2960 pc = output->cachedClosures.count();
2962 output->cachedClosures.append(0);
2964 pc = output->cachedPrograms.length();
2965 output->cachedPrograms.append(0);
2968 binding.compiledData =
2969 QByteArray((const char *)&pc, sizeof(quint32)) +
2970 QByteArray((const char *)&length, sizeof(quint32)) +
2971 QByteArray((const char *)expression.constData(),
2972 expression.length() * sizeof(QChar));
2974 componentStat.scriptBindings.append(iter.key()->location);
2977 if (bindingCompiler.isValid())
2978 compileState.compiledBindingData = bindingCompiler.program();
2980 saveComponentState();
2985 void QDeclarativeCompiler::dumpStats()
2987 qWarning().nospace() << "QML Document: " << output->url.toString();
2988 for (int ii = 0; ii < savedComponentStats.count(); ++ii) {
2989 const ComponentStat &stat = savedComponentStats.at(ii);
2990 qWarning().nospace() << " Component Line " << stat.lineNumber;
2991 qWarning().nospace() << " Total Objects: " << stat.objects;
2992 qWarning().nospace() << " IDs Used: " << stat.ids;
2993 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
2997 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
2998 if (0 == (ii % 10)) {
2999 if (ii) output.append("\n");
3004 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3006 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3007 output.append(") ");
3009 if (!output.isEmpty())
3010 qWarning().nospace() << output.constData();
3013 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3016 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3017 if (0 == (ii % 10)) {
3018 if (ii) output.append("\n");
3023 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3025 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3026 output.append(") ");
3028 if (!output.isEmpty())
3029 qWarning().nospace() << output.constData();
3035 Returns true if from can be assigned to a (QObject) property of type
3038 bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeParser::Object *from)
3040 const QMetaObject *toMo =
3041 enginePrivate->rawMetaObjectForType(to);
3042 const QMetaObject *fromMo = from->metaObject();
3045 if (QDeclarativePropertyPrivate::equal(fromMo, toMo))
3047 fromMo = fromMo->superClass();
3052 QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeParser::Object *from)
3055 const QMetaObject *mo = from->metatype;
3056 QDeclarativeType *type = 0;
3057 while (!type && mo) {
3058 type = QDeclarativeMetaType::qmlType(mo);
3059 mo = mo->superClass();
3064 QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeParser::Object *obj)
3066 const QMetaObject *mo = obj->metatype;
3068 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3070 return QStringList();
3072 QMetaClassInfo classInfo = mo->classInfo(idx);
3073 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3077 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3078 int QDeclarativeCompiler::indexOfSignal(QDeclarativeParser::Object *object, const QByteArray &name,
3079 bool *notInRevision)
3081 if (notInRevision) *notInRevision = false;
3083 if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) {
3085 QString strName(QString::fromUtf8(name));
3086 QDeclarativePropertyCache *cache =
3087 object->synthCache?object->synthCache:output->types.at(object->type).propertyCache();
3089 QDeclarativePropertyCache::Data *d = cache->property(strName);
3090 if (notInRevision) *notInRevision = false;
3092 while (d && !(d->flags & QDeclarativePropertyCache::Data::IsFunction))
3093 d = cache->overrideData(d);
3095 if (d && !cache->isAllowedInRevision(d)) {
3096 if (notInRevision) *notInRevision = true;
3099 return d->coreIndex;
3102 if (name.endsWith("Changed")) {
3103 QByteArray propName = name.mid(0, name.length() - 7);
3105 int propIndex = indexOfProperty(object, propName, notInRevision);
3106 if (propIndex != -1) {
3107 d = cache->property(propIndex);
3108 return d->notifyIndex;
3114 return QDeclarativePropertyPrivate::findSignalByName(object->metaObject(), name).methodIndex();
3119 int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QByteArray &name,
3120 bool *notInRevision)
3122 if (notInRevision) *notInRevision = false;
3124 if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) {
3126 QString strName(QString::fromUtf8(name));
3127 QDeclarativePropertyCache *cache =
3128 object->synthCache?object->synthCache:output->types.at(object->type).propertyCache();
3130 QDeclarativePropertyCache::Data *d = cache->property(strName);
3131 // Find the first property
3132 while (d && d->flags & QDeclarativePropertyCache::Data::IsFunction)
3133 d = cache->overrideData(d);
3135 if (d && !cache->isAllowedInRevision(d)) {
3136 if (notInRevision) *notInRevision = true;
3139 return d?d->coreIndex:-1;
3142 const QMetaObject *mo = object->metaObject();
3143 return mo->indexOfProperty(name.constData());