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())
653 Q_ASSERT(out->rootPropertyCache);
658 compileState = ComponentCompileState();
659 savedCompileStates.clear();
662 this->enginePrivate = 0;
669 void QDeclarativeCompiler::compileTree(QDeclarativeParser::Object *tree)
671 compileState.root = tree;
672 componentStat.lineNumber = tree->location.start.line;
674 // Build global import scripts
675 QStringList importedScriptIndexes;
677 foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
678 importedScriptIndexes.append(script.qualifier);
680 QDeclarativeInstruction import;
681 import.setType(QDeclarativeInstruction::StoreImportedScript);
682 import.storeScript.value = output->scripts.count();
684 QDeclarativeScriptData *scriptData = script.script->scriptData();
685 scriptData->addref();
686 output->scripts << scriptData;
687 output->addInstruction(import);
690 // We generate the importCache before we build the tree so that
691 // it can be used in the binding compiler. Given we "expect" the
692 // QML compilation to succeed, this isn't a waste.
693 output->importCache = new QDeclarativeTypeNameCache(engine);
694 for (int ii = 0; ii < importedScriptIndexes.count(); ++ii)
695 output->importCache->add(importedScriptIndexes.at(ii), ii);
696 unit->imports().populateCache(output->importCache, engine);
698 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
701 QDeclarativeInstruction init;
702 init.setType(QDeclarativeInstruction::Init);
703 init.init.bindingsSize = compileState.bindings.count();
704 init.init.parserStatusSize = compileState.parserStatusCount;
705 init.init.contextCache = genContextCache();
706 if (compileState.compiledBindingData.isEmpty())
707 init.init.compiledBinding = -1;
709 init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData);
710 output->addInstruction(init);
714 QDeclarativeInstruction def;
715 def.setType(QDeclarativeInstruction::SetDefault);
716 output->addInstruction(def);
718 QDeclarativeInstruction done;
719 done.setType(QDeclarativeInstruction::Done);
720 output->addInstruction(done);
722 Q_ASSERT(tree->metatype);
724 if (tree->metadata.isEmpty()) {
725 output->root = tree->metatype;
727 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
728 output->root = &output->rootData;
730 if (!tree->metadata.isEmpty())
731 enginePrivate->registerCompositeType(output);
734 static bool ValuePtrLessThan(const QDeclarativeParser::Value *t1, const QDeclarativeParser::Value *t2)
736 return t1->location.start.line < t2->location.start.line ||
737 (t1->location.start.line == t2->location.start.line &&
738 t1->location.start.column < t2->location.start.column);
741 bool QDeclarativeCompiler::buildObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
743 componentStat.objects++;
745 Q_ASSERT (obj->type != -1);
746 const QDeclarativeCompiledData::TypeReference &tr =
747 output->types.at(obj->type);
748 obj->metatype = tr.metaObject();
751 obj->url = tr.component->url;
753 obj->typeName = tr.type->qmlTypeName();
754 obj->className = tr.className;
756 // This object is a "Component" element
757 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
758 COMPILE_CHECK(buildComponent(obj, ctxt));
762 // Object instantiations reset the binding context
763 BindingContext objCtxt(obj);
765 // Create the synthesized meta object, ignoring aliases
766 COMPILE_CHECK(checkDynamicMeta(obj));
767 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
768 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
770 // Find the native type and check for the QDeclarativeParserStatus interface
771 QDeclarativeType *type = toQmlType(obj);
773 obj->parserStatusCast = type->parserStatusCast();
774 if (obj->parserStatusCast != -1)
775 compileState.parserStatusCount++;
777 // Check if this is a custom parser type. Custom parser types allow
778 // assignments to non-existent properties. These assignments are then
779 // compiled by the type.
780 bool isCustomParser = output->types.at(obj->type).type &&
781 output->types.at(obj->type).type->customParser() != 0;
782 QList<QDeclarativeCustomParserProperty> customProps;
784 // Fetch the list of deferred properties
785 QStringList deferredList = deferredProperties(obj);
787 // Must do id property first. This is to ensure that the id given to any
788 // id reference created matches the order in which the objects are
790 foreach(Property *prop, obj->properties) {
791 if (prop->name == "id") {
792 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
798 Property *defaultProperty = 0;
799 Property *skipProperty = 0;
800 if (obj->defaultProperty) {
801 const QMetaObject *metaObject = obj->metaObject();
802 Q_ASSERT(metaObject);
803 QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
805 Property *explicitProperty = obj->getProperty(p.name(), false);
806 if (explicitProperty && !explicitProperty->value) {
807 skipProperty = explicitProperty;
809 defaultProperty = new Property;
810 defaultProperty->parent = obj;
811 defaultProperty->isDefault = true;
812 defaultProperty->location = obj->defaultProperty->location;
813 defaultProperty->listValueRange = obj->defaultProperty->listValueRange;
814 defaultProperty->listCommaPositions = obj->defaultProperty->listCommaPositions;
816 defaultProperty->values = obj->defaultProperty->values;
817 defaultProperty->values += explicitProperty->values;
818 foreach(QDeclarativeParser::Value *value, defaultProperty->values)
820 qSort(defaultProperty->values.begin(), defaultProperty->values.end(), ValuePtrLessThan);
823 defaultProperty = obj->defaultProperty;
824 defaultProperty->addref();
827 defaultProperty = obj->defaultProperty;
828 defaultProperty->addref();
832 QDeclarativeCustomParser *cp = 0;
834 cp = output->types.at(obj->type).type->customParser();
836 // Build all explicit properties specified
837 foreach(Property *prop, obj->properties) {
839 if (prop == skipProperty)
841 if (prop->name == "id")
844 bool canDefer = false;
845 if (isCustomParser) {
846 if (doesPropertyExist(prop, obj) &&
847 (!(cp->flags() & QDeclarativeCustomParser::AcceptsAttachedProperties) ||
848 !isAttachedPropertyName(prop->name))) {
849 int ids = compileState.ids.count();
850 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
851 canDefer = ids == compileState.ids.count();
853 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
856 if (isSignalPropertyName(prop->name)) {
857 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
859 int ids = compileState.ids.count();
860 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
861 canDefer = ids == compileState.ids.count();
865 if (canDefer && !deferredList.isEmpty() &&
866 deferredList.contains(QString::fromUtf8(prop->name)))
867 prop->isDeferred = true;
871 // Build the default property
872 if (defaultProperty) {
873 Property *prop = defaultProperty;
875 bool canDefer = false;
876 if (isCustomParser) {
877 if (doesPropertyExist(prop, obj)) {
878 int ids = compileState.ids.count();
879 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
880 canDefer = ids == compileState.ids.count();
882 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
885 int ids = compileState.ids.count();
886 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
887 canDefer = ids == compileState.ids.count();
890 if (canDefer && !deferredList.isEmpty() &&
891 deferredList.contains(QString::fromUtf8(prop->name)))
892 prop->isDeferred = true;
896 defaultProperty->release();
898 // Compile custom parser parts
899 if (isCustomParser && !customProps.isEmpty()) {
903 obj->custom = cp->compile(customProps);
906 foreach (QDeclarativeError err, cp->errors()) {
907 err.setUrl(output->url);
915 void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj)
917 QDeclarativeCompiledData::TypeReference &tr = output->types[obj->type];
918 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
924 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
925 !output->types.at(obj->type).type->isExtendedType() && obj != compileState.root) {
927 QDeclarativeInstruction create;
928 create.setType(QDeclarativeInstruction::CreateSimpleObject);
929 create.createSimple.create = output->types.at(obj->type).type->createFunction();
930 create.createSimple.typeSize = output->types.at(obj->type).type->createSize();
931 create.createSimple.type = obj->type;
932 create.createSimple.line = obj->location.start.line;
933 create.createSimple.column = obj->location.start.column;
934 output->addInstruction(create);
938 QDeclarativeInstruction create;
939 create.setType(QDeclarativeInstruction::CreateObject);
940 create.create.line = obj->location.start.line;
941 create.create.column = obj->location.start.column;
942 create.create.data = -1;
943 if (!obj->custom.isEmpty())
944 create.create.data = output->indexForByteArray(obj->custom);
945 create.create.type = obj->type;
946 if (!output->types.at(create.create.type).type &&
947 !obj->bindingBitmask.isEmpty()) {
948 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
949 create.create.bindingBits =
950 output->indexForByteArray(obj->bindingBitmask);
952 create.create.bindingBits = -1;
954 output->addInstruction(create);
958 // Setup the synthesized meta object if necessary
959 if (!obj->metadata.isEmpty()) {
960 QDeclarativeInstruction meta;
961 meta.setType(QDeclarativeInstruction::StoreMetaObject);
962 meta.storeMeta.data = output->indexForByteArray(obj->metadata);
963 meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata);
964 meta.storeMeta.propertyCache = output->propertyCaches.count();
966 QDeclarativePropertyCache *propertyCache = obj->synthCache;
967 Q_ASSERT(propertyCache);
968 propertyCache->addref();
970 // Add flag for alias properties
971 if (!obj->synthdata.isEmpty()) {
972 const QDeclarativeVMEMetaData *vmeMetaData =
973 reinterpret_cast<const QDeclarativeVMEMetaData *>(obj->synthdata.constData());
974 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
975 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
976 propertyCache->property(index)->flags |= QDeclarativePropertyCache::Data::IsAlias;
980 if (obj == unitRoot) {
981 propertyCache->addref();
982 output->rootPropertyCache = propertyCache;
985 output->propertyCaches << propertyCache;
986 output->addInstruction(meta);
987 } else if (obj == unitRoot) {
988 output->rootPropertyCache = tr.createPropertyCache(engine);
989 output->rootPropertyCache->addref();
993 if (!obj->id.isEmpty()) {
994 QDeclarativeInstruction id;
995 id.setType(QDeclarativeInstruction::SetId);
996 id.setId.value = output->indexForString(obj->id);
997 id.setId.index = obj->idIndex;
998 output->addInstruction(id);
1002 if (tr.type && obj->parserStatusCast != -1) {
1003 QDeclarativeInstruction begin;
1004 begin.setType(QDeclarativeInstruction::BeginObject);
1005 begin.begin.castValue = obj->parserStatusCast;
1006 output->addInstruction(begin);
1012 void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj)
1014 typedef QPair<Property *, int> PropPair;
1015 foreach(const PropPair &prop, obj->scriptStringProperties) {
1016 const QString &script = prop.first->values.at(0)->value.asScript();
1017 QDeclarativeInstruction ss;
1018 ss.setType(QDeclarativeInstruction::StoreScriptString);
1019 ss.storeScriptString.propertyIndex = prop.first->index;
1020 ss.storeScriptString.value = output->indexForString(script);
1021 ss.storeScriptString.scope = prop.second;
1022 ss.storeScriptString.bindingId = rewriteBinding(script, prop.first->name);
1023 ss.storeScriptString.line = prop.first->location.start.line;
1024 output->addInstruction(ss);
1027 bool seenDefer = false;
1028 foreach(Property *prop, obj->valueProperties) {
1029 if (prop->isDeferred) {
1034 genValueProperty(prop, obj);
1037 QDeclarativeInstruction defer;
1038 defer.setType(QDeclarativeInstruction::Defer);
1039 defer.defer.deferCount = 0;
1040 int deferIdx = output->addInstruction(defer);
1041 int nextInstructionIndex = output->nextInstructionIndex();
1043 QDeclarativeInstruction init;
1044 init.setType(QDeclarativeInstruction::Init);
1045 init.init.bindingsSize = compileState.bindings.count(); // XXX - bigger than necessary
1046 init.init.parserStatusSize = compileState.parserStatusCount; // XXX - bigger than necessary
1047 init.init.contextCache = -1;
1048 init.init.compiledBinding = -1;
1049 output->addInstruction(init);
1051 foreach(Property *prop, obj->valueProperties) {
1052 if (!prop->isDeferred)
1054 genValueProperty(prop, obj);
1057 QDeclarativeInstruction done;
1058 done.setType(QDeclarativeInstruction::Done);
1059 output->addInstruction(done);
1061 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1064 foreach(Property *prop, obj->signalProperties) {
1066 QDeclarativeParser::Value *v = prop->values.at(0);
1068 if (v->type == Value::SignalObject) {
1070 genObject(v->object);
1072 QDeclarativeInstruction assign;
1073 assign.setType(QDeclarativeInstruction::AssignSignalObject);
1074 assign.assignSignalObject.line = v->location.start.line;
1075 assign.assignSignalObject.signal =
1076 output->indexForByteArray(prop->name);
1077 output->addInstruction(assign);
1079 } else if (v->type == Value::SignalExpression) {
1081 BindingContext ctxt = compileState.signalExpressions.value(v);
1083 QDeclarativeInstruction store;
1084 store.setType(QDeclarativeInstruction::StoreSignal);
1085 store.storeSignal.signalIndex = prop->index;
1086 store.storeSignal.value =
1087 output->indexForString(v->value.asScript().trimmed());
1088 store.storeSignal.context = ctxt.stack;
1089 store.storeSignal.name = output->indexForByteArray(prop->name);
1090 store.storeSignal.line = v->location.start.line;
1091 output->addInstruction(store);
1097 foreach(Property *prop, obj->attachedProperties) {
1098 QDeclarativeInstruction fetch;
1099 fetch.setType(QDeclarativeInstruction::FetchAttached);
1100 fetch.fetchAttached.id = prop->index;
1101 fetch.fetchAttached.line = prop->location.start.line;
1102 output->addInstruction(fetch);
1104 genObjectBody(prop->value);
1106 QDeclarativeInstruction pop;
1107 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1108 output->addInstruction(pop);
1111 foreach(Property *prop, obj->groupedProperties) {
1112 QDeclarativeInstruction fetch;
1113 fetch.setType(QDeclarativeInstruction::FetchObject);
1114 fetch.fetch.property = prop->index;
1115 fetch.fetch.line = prop->location.start.line;
1116 output->addInstruction(fetch);
1118 if (!prop->value->metadata.isEmpty()) {
1119 QDeclarativeInstruction meta;
1120 meta.setType(QDeclarativeInstruction::StoreMetaObject);
1121 meta.storeMeta.data = output->indexForByteArray(prop->value->metadata);
1122 meta.storeMeta.aliasData = output->indexForByteArray(prop->value->synthdata);
1123 meta.storeMeta.propertyCache = -1;
1124 output->addInstruction(meta);
1127 genObjectBody(prop->value);
1129 QDeclarativeInstruction pop;
1130 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1131 output->addInstruction(pop);
1134 foreach(Property *prop, obj->valueTypeProperties) {
1136 genValueTypeProperty(obj, prop);
1139 foreach(Property *prop, obj->valueProperties) {
1140 if (prop->isDeferred)
1143 genValueProperty(prop, obj);
1146 foreach(Property *prop, obj->valueTypeProperties) {
1148 genValueTypeProperty(obj, prop);
1152 void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeParser::Object *obj,QDeclarativeParser::Property *prop)
1154 QDeclarativeInstruction fetch;
1155 fetch.setType(QDeclarativeInstruction::FetchValueType);
1156 fetch.fetchValue.property = prop->index;
1157 fetch.fetchValue.type = prop->type;
1158 fetch.fetchValue.bindingSkipList = 0;
1160 if (obj->type == -1 || output->types.at(obj->type).component) {
1161 // We only have to do this if this is a composite type. If it is a builtin
1162 // type it can't possibly already have bindings that need to be cleared.
1163 foreach(Property *vprop, prop->value->valueProperties) {
1164 if (!vprop->values.isEmpty()) {
1165 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1166 fetch.fetchValue.bindingSkipList |= (1 << vprop->index);
1171 output->addInstruction(fetch);
1173 foreach(Property *vprop, prop->value->valueProperties) {
1174 genPropertyAssignment(vprop, prop->value, prop);
1177 QDeclarativeInstruction pop;
1178 pop.setType(QDeclarativeInstruction::PopValueType);
1179 pop.fetchValue.property = prop->index;
1180 pop.fetchValue.type = prop->type;
1181 pop.fetchValue.bindingSkipList = 0;
1182 output->addInstruction(pop);
1185 void QDeclarativeCompiler::genComponent(QDeclarativeParser::Object *obj)
1187 QDeclarativeParser::Object *root = obj->defaultProperty->values.at(0)->object;
1190 QDeclarativeInstruction create;
1191 create.setType(QDeclarativeInstruction::CreateComponent);
1192 create.createComponent.line = root->location.start.line;
1193 create.createComponent.column = root->location.start.column;
1194 create.createComponent.endLine = root->location.end.line;
1195 int createInstruction = output->addInstruction(create);
1196 int nextInstructionIndex = output->nextInstructionIndex();
1198 ComponentCompileState oldCompileState = compileState;
1199 compileState = componentState(root);
1201 QDeclarativeInstruction init;
1202 init.setType(QDeclarativeInstruction::Init);
1203 init.init.bindingsSize = compileState.bindings.count();
1204 init.init.parserStatusSize = compileState.parserStatusCount;
1205 init.init.contextCache = genContextCache();
1206 if (compileState.compiledBindingData.isEmpty())
1207 init.init.compiledBinding = -1;
1209 init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData);
1210 output->addInstruction(init);
1214 QDeclarativeInstruction def;
1215 def.setType(QDeclarativeInstruction::SetDefault);
1216 output->addInstruction(def);
1218 QDeclarativeInstruction done;
1219 done.setType(QDeclarativeInstruction::Done);
1220 output->addInstruction(done);
1222 output->instruction(createInstruction)->createComponent.count =
1223 output->nextInstructionIndex() - nextInstructionIndex;
1225 compileState = oldCompileState;
1227 if (!obj->id.isEmpty()) {
1228 QDeclarativeInstruction id;
1229 id.setType(QDeclarativeInstruction::SetId);
1230 id.setId.value = output->indexForString(obj->id);
1231 id.setId.index = obj->idIndex;
1232 output->addInstruction(id);
1235 if (obj == unitRoot) {
1236 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1237 output->rootPropertyCache->addref();
1241 bool QDeclarativeCompiler::buildComponent(QDeclarativeParser::Object *obj,
1242 const BindingContext &ctxt)
1244 // The special "Component" element can only have the id property and a
1245 // default property, that actually defines the component's tree
1247 // Find, check and set the "id" property (if any)
1248 Property *idProp = 0;
1249 if (obj->properties.count() > 1 ||
1250 (obj->properties.count() == 1 && obj->properties.begin().key() != "id"))
1251 COMPILE_EXCEPTION(*obj->properties.begin(), tr("Component elements may not contain properties other than id"));
1253 if (obj->properties.count())
1254 idProp = *obj->properties.begin();
1257 if (idProp->value || idProp->values.count() > 1 || idProp->values.at(0)->object)
1258 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1259 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1261 QString idVal = idProp->values.first()->primitive();
1263 if (compileState.ids.contains(idVal))
1264 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1270 // Check the Component tree is well formed
1271 if (obj->defaultProperty &&
1272 (obj->defaultProperty->value || obj->defaultProperty->values.count() > 1 ||
1273 (obj->defaultProperty->values.count() == 1 && !obj->defaultProperty->values.first()->object)))
1274 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1276 if (!obj->dynamicProperties.isEmpty())
1277 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1278 if (!obj->dynamicSignals.isEmpty())
1279 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1280 if (!obj->dynamicSlots.isEmpty())
1281 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1283 QDeclarativeParser::Object *root = 0;
1284 if (obj->defaultProperty && obj->defaultProperty->values.count())
1285 root = obj->defaultProperty->values.first()->object;
1288 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1290 // Build the component tree
1291 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1296 bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeParser::Object *obj,
1297 const BindingContext &ctxt)
1299 ComponentCompileState oldComponentCompileState = compileState;
1300 ComponentStat oldComponentStat = componentStat;
1302 compileState = ComponentCompileState();
1303 compileState.root = obj;
1304 compileState.nested = true;
1306 componentStat = ComponentStat();
1307 componentStat.lineNumber = obj->location.start.line;
1310 COMPILE_CHECK(buildObject(obj, ctxt));
1312 COMPILE_CHECK(completeComponentBuild());
1314 compileState = oldComponentCompileState;
1315 componentStat = oldComponentStat;
1321 // Build a sub-object. A sub-object is one that was not created directly by
1322 // QML - such as a grouped property object, or an attached object. Sub-object's
1323 // can't have an id, involve a custom parser, have attached properties etc.
1324 bool QDeclarativeCompiler::buildSubObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
1326 Q_ASSERT(obj->metatype);
1327 Q_ASSERT(!obj->defaultProperty);
1328 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1331 foreach(Property *prop, obj->properties) {
1332 if (isSignalPropertyName(prop->name)) {
1333 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1335 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1342 int QDeclarativeCompiler::componentTypeRef()
1344 QDeclarativeType *t = QDeclarativeMetaType::qmlType("QtQuick/Component",1,0);
1345 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1346 if (output->types.at(ii).type == t)
1349 QDeclarativeCompiledData::TypeReference ref;
1350 ref.className = "Component";
1352 output->types << ref;
1353 return output->types.count() - 1;
1356 bool QDeclarativeCompiler::buildSignal(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj,
1357 const BindingContext &ctxt)
1359 Q_ASSERT(obj->metaObject());
1361 QByteArray name = prop->name;
1362 Q_ASSERT(name.startsWith("on"));
1365 // Note that the property name could start with any alpha or '_' or '$' character,
1366 // so we need to do the lower-casing of the first alpha character.
1367 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1368 if (name[firstAlphaIndex] >= 'A' && name[firstAlphaIndex] <= 'Z') {
1369 name[firstAlphaIndex] = name[firstAlphaIndex] - 'A' + 'a';
1374 bool notInRevision = false;
1375 int sigIdx = indexOfSignal(obj, name, ¬InRevision);
1379 if (notInRevision && -1 == indexOfProperty(obj, prop->name, 0)) {
1380 Q_ASSERT(obj->type != -1);
1381 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1382 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1384 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));
1386 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)));
1390 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1392 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1396 if (prop->value || prop->values.count() != 1)
1397 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1399 prop->index = sigIdx;
1400 obj->addSignalProperty(prop);
1402 if (prop->values.at(0)->object) {
1403 COMPILE_CHECK(buildObject(prop->values.at(0)->object, ctxt));
1404 prop->values.at(0)->type = Value::SignalObject;
1406 prop->values.at(0)->type = Value::SignalExpression;
1408 if (!prop->values.at(0)->value.isScript())
1409 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1411 QString script = prop->values.at(0)->value.asScript().trimmed();
1412 if (script.isEmpty())
1413 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1415 compileState.signalExpressions.insert(prop->values.at(0), ctxt);
1424 Returns true if (value) property \a prop exists on obj, false otherwise.
1426 bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeParser::Property *prop,
1427 QDeclarativeParser::Object *obj)
1429 if(isAttachedPropertyName(prop->name) || prop->name == "id")
1432 const QMetaObject *mo = obj->metaObject();
1434 if (prop->isDefault) {
1435 QMetaProperty p = QDeclarativeMetaType::defaultProperty(mo);
1436 return p.name() != 0;
1438 int idx = indexOfProperty(obj, prop->name);
1439 return idx != -1 && mo->property(idx).isScriptable();
1446 bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop,
1447 QDeclarativeParser::Object *obj,
1448 const BindingContext &ctxt)
1450 if (prop->isEmpty())
1451 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1453 const QMetaObject *metaObject = obj->metaObject();
1454 Q_ASSERT(metaObject);
1456 if (isAttachedPropertyName(prop->name)) {
1457 // Setup attached property data
1459 if (ctxt.isSubContext()) {
1460 // Attached properties cannot be used on sub-objects. Sub-objects
1461 // always exist in a binding sub-context, which is what we test
1463 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1466 QDeclarativeType *type = 0;
1467 QDeclarativeImportedNamespace *typeNamespace = 0;
1468 unit->imports().resolveType(prop->name, &type, 0, 0, 0, &typeNamespace);
1470 if (typeNamespace) {
1471 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1474 } else if (!type || !type->attachedPropertiesType()) {
1475 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1479 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1481 Q_ASSERT(type->attachedPropertiesFunction());
1482 prop->index = type->attachedPropertiesId();
1483 prop->value->metatype = type->attachedPropertiesType();
1485 // Setup regular property data
1488 if (prop->isDefault) {
1489 p = QDeclarativeMetaType::defaultProperty(metaObject);
1492 prop->index = p.propertyIndex();
1493 prop->name = p.name();
1497 bool notInRevision = false;
1498 prop->index = indexOfProperty(obj, prop->name, ¬InRevision);
1499 if (prop->index == -1 && notInRevision) {
1500 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1501 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1503 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));
1505 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)));
1509 if (prop->index != -1) {
1510 p = metaObject->property(prop->index);
1513 if (!p.isScriptable()) {
1515 p = QMetaProperty();
1520 // We can't error here as the "id" property does not require a
1521 // successful index resolution
1523 prop->type = p.userType();
1525 // Check if this is an alias
1526 if (prop->index != -1 &&
1528 prop->parent->type != -1 &&
1529 output->types.at(prop->parent->type).component) {
1531 QDeclarativePropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1532 if (cache && cache->property(prop->index) &&
1533 cache->property(prop->index)->flags & QDeclarativePropertyCache::Data::IsAlias)
1534 prop->isAlias = true;
1537 if (prop->index != -1 && !prop->values.isEmpty())
1538 prop->parent->setBindingBit(prop->index);
1541 if (!prop->isDefault && prop->name == "id" && !ctxt.isSubContext()) {
1543 // The magic "id" behavior doesn't apply when "id" is resolved as a
1544 // default property or to sub-objects (which are always in binding
1546 COMPILE_CHECK(buildIdProperty(prop, obj));
1547 if (prop->type == QVariant::String &&
1548 prop->values.at(0)->value.isString())
1549 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1551 } else if (isAttachedPropertyName(prop->name)) {
1553 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1555 } else if (prop->index == -1) {
1557 if (prop->isDefault) {
1558 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1560 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1563 } else if (prop->value) {
1565 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1567 } else if (enginePrivate->isList(prop->type)) {
1569 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1571 } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) {
1573 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1577 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1584 bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
1585 QDeclarativeParser::Property *nsProp,
1586 QDeclarativeParser::Object *obj,
1587 const BindingContext &ctxt)
1590 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1592 foreach (Property *prop, nsProp->value->properties) {
1594 if (!isAttachedPropertyName(prop->name))
1595 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1597 // Setup attached property data
1599 QDeclarativeType *type = 0;
1600 unit->imports().resolveType(ns, prop->name, &type, 0, 0, 0);
1602 if (!type || !type->attachedPropertiesType())
1603 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1606 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1608 Q_ASSERT(type->attachedPropertiesFunction());
1609 prop->index = type->index();
1610 prop->value->metatype = type->attachedPropertiesType();
1612 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1618 void QDeclarativeCompiler::genValueProperty(QDeclarativeParser::Property *prop,
1619 QDeclarativeParser::Object *obj)
1621 if (enginePrivate->isList(prop->type)) {
1622 genListProperty(prop, obj);
1624 genPropertyAssignment(prop, obj);
1628 void QDeclarativeCompiler::genListProperty(QDeclarativeParser::Property *prop,
1629 QDeclarativeParser::Object *obj)
1631 int listType = enginePrivate->listType(prop->type);
1633 QDeclarativeInstruction fetch;
1634 fetch.setType(QDeclarativeInstruction::FetchQList);
1635 fetch.fetchQmlList.property = prop->index;
1636 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1637 fetch.fetchQmlList.type = listType;
1638 output->addInstruction(fetch);
1640 for (int ii = 0; ii < prop->values.count(); ++ii) {
1641 QDeclarativeParser::Value *v = prop->values.at(ii);
1643 if (v->type == Value::CreatedObject) {
1645 genObject(v->object);
1646 if (listTypeIsInterface) {
1647 QDeclarativeInstruction assign;
1648 assign.setType(QDeclarativeInstruction::AssignObjectList);
1649 assign.assignObjectList.line = prop->location.start.line;
1650 output->addInstruction(assign);
1652 QDeclarativeInstruction store;
1653 store.setType(QDeclarativeInstruction::StoreObjectQList);
1654 output->addInstruction(store);
1657 } else if (v->type == Value::PropertyBinding) {
1659 genBindingAssignment(v, prop, obj);
1665 QDeclarativeInstruction pop;
1666 pop.setType(QDeclarativeInstruction::PopQList);
1667 output->addInstruction(pop);
1670 void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *prop,
1671 QDeclarativeParser::Object *obj,
1672 QDeclarativeParser::Property *valueTypeProperty)
1674 for (int ii = 0; ii < prop->values.count(); ++ii) {
1675 QDeclarativeParser::Value *v = prop->values.at(ii);
1677 Q_ASSERT(v->type == Value::CreatedObject ||
1678 v->type == Value::PropertyBinding ||
1679 v->type == Value::Literal);
1681 if (v->type == Value::CreatedObject) {
1683 genObject(v->object);
1685 if (QDeclarativeMetaType::isInterface(prop->type)) {
1687 QDeclarativeInstruction store;
1688 store.setType(QDeclarativeInstruction::StoreInterface);
1689 store.storeObject.line = v->object->location.start.line;
1690 store.storeObject.propertyIndex = prop->index;
1691 output->addInstruction(store);
1693 } else if (prop->type == -1) {
1695 QDeclarativeInstruction store;
1696 store.setType(QDeclarativeInstruction::StoreVariantObject);
1697 store.storeObject.line = v->object->location.start.line;
1698 store.storeObject.propertyIndex = prop->index;
1699 output->addInstruction(store);
1703 QDeclarativeInstruction store;
1704 store.setType(QDeclarativeInstruction::StoreObject);
1705 store.storeObject.line = v->object->location.start.line;
1706 store.storeObject.propertyIndex = prop->index;
1707 output->addInstruction(store);
1710 } else if (v->type == Value::PropertyBinding) {
1712 genBindingAssignment(v, prop, obj, valueTypeProperty);
1714 } else if (v->type == Value::Literal) {
1716 QMetaProperty mp = obj->metaObject()->property(prop->index);
1717 genLiteralAssignment(mp, v);
1723 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
1725 QDeclarativeParser::Value *v = prop->onValues.at(ii);
1727 Q_ASSERT(v->type == Value::ValueSource ||
1728 v->type == Value::ValueInterceptor);
1730 if (v->type == Value::ValueSource) {
1731 genObject(v->object);
1733 QDeclarativeInstruction store;
1734 store.setType(QDeclarativeInstruction::StoreValueSource);
1735 if (valueTypeProperty) {
1736 store.assignValueSource.property = genValueTypeData(prop, valueTypeProperty);
1737 store.assignValueSource.owner = 1;
1739 store.assignValueSource.property = genPropertyData(prop);
1740 store.assignValueSource.owner = 0;
1742 QDeclarativeType *valueType = toQmlType(v->object);
1743 store.assignValueSource.castValue = valueType->propertyValueSourceCast();
1744 output->addInstruction(store);
1746 } else if (v->type == Value::ValueInterceptor) {
1747 genObject(v->object);
1749 QDeclarativeInstruction store;
1750 store.setType(QDeclarativeInstruction::StoreValueInterceptor);
1751 if (valueTypeProperty) {
1752 store.assignValueInterceptor.property = genValueTypeData(prop, valueTypeProperty);
1753 store.assignValueInterceptor.owner = 1;
1755 store.assignValueInterceptor.property = genPropertyData(prop);
1756 store.assignValueInterceptor.owner = 0;
1758 QDeclarativeType *valueType = toQmlType(v->object);
1759 store.assignValueInterceptor.castValue = valueType->propertyValueInterceptorCast();
1760 output->addInstruction(store);
1766 bool QDeclarativeCompiler::buildIdProperty(QDeclarativeParser::Property *prop,
1767 QDeclarativeParser::Object *obj)
1770 prop->values.count() > 1 ||
1771 prop->values.at(0)->object)
1772 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
1774 QDeclarativeParser::Value *idValue = prop->values.at(0);
1775 QString val = idValue->primitive();
1777 COMPILE_CHECK(checkValidId(idValue, val));
1779 if (compileState.ids.contains(val))
1780 COMPILE_EXCEPTION(prop, tr("id is not unique"));
1782 prop->values.at(0)->type = Value::Id;
1790 void QDeclarativeCompiler::addId(const QString &id, QDeclarativeParser::Object *obj)
1792 Q_ASSERT(!compileState.ids.contains(id));
1793 Q_ASSERT(obj->id == id);
1794 obj->idIndex = compileState.ids.count();
1795 compileState.ids.insert(id, obj);
1796 compileState.idIndexes.insert(obj->idIndex, obj);
1799 void QDeclarativeCompiler::addBindingReference(const BindingReference &ref)
1801 Q_ASSERT(ref.value && !compileState.bindings.contains(ref.value));
1802 compileState.bindings.insert(ref.value, ref);
1805 void QDeclarativeCompiler::saveComponentState()
1807 Q_ASSERT(compileState.root);
1808 Q_ASSERT(!savedCompileStates.contains(compileState.root));
1810 savedCompileStates.insert(compileState.root, compileState);
1811 savedComponentStats.append(componentStat);
1814 QDeclarativeCompiler::ComponentCompileState
1815 QDeclarativeCompiler::componentState(QDeclarativeParser::Object *obj)
1817 Q_ASSERT(savedCompileStates.contains(obj));
1818 return savedCompileStates.value(obj);
1821 // Build attached property object. In this example,
1825 // GridView is an attached property object.
1826 bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeParser::Property *prop,
1827 QDeclarativeParser::Object *obj,
1828 const BindingContext &ctxt)
1830 Q_ASSERT(prop->value);
1831 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
1833 obj->addAttachedProperty(prop);
1835 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1841 // Build "grouped" properties. In this example:
1843 // font.pointSize: 12
1844 // font.family: "Helvetica"
1846 // font is a nested property. pointSize and family are not.
1847 bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeParser::Property *prop,
1848 QDeclarativeParser::Object *obj,
1849 const BindingContext &ctxt)
1851 Q_ASSERT(prop->type != 0);
1852 Q_ASSERT(prop->index != -1);
1854 if (QDeclarativeValueTypeFactory::isValueType(prop->type)) {
1855 if (prop->type >= 0 /* QVariant == -1 */ && enginePrivate->valueTypes[prop->type]) {
1857 if (prop->values.count()) {
1858 if (prop->values.at(0)->location < prop->value->location) {
1859 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
1861 COMPILE_EXCEPTION(prop->values.at(0), tr( "Property has already been assigned a value"));
1865 if (!obj->metaObject()->property(prop->index).isWritable()) {
1866 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
1870 if (prop->isAlias) {
1871 foreach (Property *vtProp, prop->value->properties)
1872 vtProp->isAlias = true;
1875 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
1876 prop->value, obj, ctxt.incr()));
1877 obj->addValueTypeProperty(prop);
1879 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1883 // Load the nested property's meta type
1884 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
1885 if (!prop->value->metatype)
1886 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1888 if (prop->values.count())
1889 COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign a value directly to a grouped property"));
1891 obj->addGroupedProperty(prop);
1893 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1899 bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
1900 QDeclarativeParser::Object *obj,
1901 QDeclarativeParser::Object *baseObj,
1902 const BindingContext &ctxt)
1904 if (obj->defaultProperty)
1905 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
1906 obj->metatype = type->metaObject();
1908 foreach (Property *prop, obj->properties) {
1909 int idx = type->metaObject()->indexOfProperty(prop->name.constData());
1911 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1912 QMetaProperty p = type->metaObject()->property(idx);
1913 if (!p.isScriptable())
1914 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1916 prop->type = p.userType();
1917 prop->isValueTypeSubProperty = true;
1920 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
1922 if (prop->values.count() > 1) {
1923 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
1924 } else if (prop->values.count()) {
1925 QDeclarativeParser::Value *value = prop->values.at(0);
1927 if (value->object) {
1928 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
1929 } else if (value->value.isScript()) {
1930 // ### Check for writability
1932 //optimization for <Type>.<EnumValue> enum assignments
1933 bool isEnumAssignment = false;
1934 COMPILE_CHECK(testQualifiedEnumAssignment(p, obj, value, &isEnumAssignment));
1935 if (isEnumAssignment) {
1936 value->type = Value::Literal;
1938 BindingReference reference;
1939 reference.expression = value->value;
1940 reference.property = prop;
1941 reference.value = value;
1942 reference.bindingContext = ctxt;
1943 reference.bindingContext.owner++;
1944 addBindingReference(reference);
1945 value->type = Value::PropertyBinding;
1948 COMPILE_CHECK(testLiteralAssignment(p, value));
1949 value->type = Value::Literal;
1953 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
1954 QDeclarativeParser::Value *v = prop->onValues.at(ii);
1955 Q_ASSERT(v->object);
1957 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
1960 obj->addValueProperty(prop);
1966 // Build assignments to QML lists. QML lists are properties of type
1967 // QDeclarativeListProperty<T>. List properties can accept a list of
1968 // objects, or a single binding.
1969 bool QDeclarativeCompiler::buildListProperty(QDeclarativeParser::Property *prop,
1970 QDeclarativeParser::Object *obj,
1971 const BindingContext &ctxt)
1973 Q_ASSERT(enginePrivate->isList(prop->type));
1977 obj->addValueProperty(prop);
1979 int listType = enginePrivate->listType(t);
1980 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1982 bool assignedBinding = false;
1983 for (int ii = 0; ii < prop->values.count(); ++ii) {
1984 QDeclarativeParser::Value *v = prop->values.at(ii);
1986 v->type = Value::CreatedObject;
1987 COMPILE_CHECK(buildObject(v->object, ctxt));
1989 // We check object coercian here. We check interface assignment
1991 if (!listTypeIsInterface) {
1992 if (!canCoerce(listType, v->object)) {
1993 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
1997 } else if (v->value.isScript()) {
1998 if (assignedBinding)
1999 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2001 assignedBinding = true;
2002 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2003 v->type = Value::PropertyBinding;
2005 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2012 // Compiles an assignment to a QDeclarativeScriptString property
2013 bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeParser::Property *prop,
2014 QDeclarativeParser::Object *obj,
2015 const BindingContext &ctxt)
2017 if (prop->values.count() > 1)
2018 COMPILE_EXCEPTION(prop->values.at(1), tr( "Cannot assign multiple values to a script property"));
2020 if (prop->values.at(0)->object)
2021 COMPILE_EXCEPTION(prop->values.at(0), tr( "Invalid property assignment: script expected"));
2023 obj->addScriptStringProperty(prop, ctxt.stack);
2028 // Compile regular property assignments of the form "property: <value>"
2029 bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeParser::Property *prop,
2030 QDeclarativeParser::Object *obj,
2031 const BindingContext &ctxt)
2033 obj->addValueProperty(prop);
2035 if (prop->values.count() > 1)
2036 COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign multiple values to a singular property") );
2038 for (int ii = 0; ii < prop->values.count(); ++ii) {
2039 QDeclarativeParser::Value *v = prop->values.at(ii);
2042 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2046 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2051 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
2052 QDeclarativeParser::Value *v = prop->onValues.at(ii);
2054 Q_ASSERT(v->object);
2055 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2061 // Compile assigning a single object instance to a regular property
2062 bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeParser::Property *prop,
2063 QDeclarativeParser::Object *obj,
2064 QDeclarativeParser::Value *v,
2065 const BindingContext &ctxt)
2067 Q_ASSERT(prop->index != -1);
2068 Q_ASSERT(v->object->type != -1);
2070 if (!obj->metaObject()->property(prop->index).isWritable())
2071 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2073 if (QDeclarativeMetaType::isInterface(prop->type)) {
2075 // Assigning an object to an interface ptr property
2076 COMPILE_CHECK(buildObject(v->object, ctxt));
2078 v->type = Value::CreatedObject;
2080 } else if (prop->type == -1) {
2082 // Assigning an object to a QVariant
2083 COMPILE_CHECK(buildObject(v->object, ctxt));
2085 v->type = Value::CreatedObject;
2087 // Normally buildObject() will set this up, but we need the static
2088 // meta object earlier to test for assignability. It doesn't matter
2089 // that there may still be outstanding synthesized meta object changes
2090 // on this type, as they are not relevant for assignability testing
2091 v->object->metatype = output->types.at(v->object->type).metaObject();
2092 Q_ASSERT(v->object->metaObject());
2094 // We want to raw metaObject here as the raw metaobject is the
2095 // actual property type before we applied any extensions that might
2096 // effect the properties on the type, but don't effect assignability
2097 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2099 // Will be true if the assgned type inherits propertyMetaObject
2100 bool isAssignable = false;
2101 // Determine isAssignable value
2102 if (propertyMetaObject) {
2103 const QMetaObject *c = v->object->metatype;
2105 isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject));
2106 c = c->superClass();
2111 // Simple assignment
2112 COMPILE_CHECK(buildObject(v->object, ctxt));
2114 v->type = Value::CreatedObject;
2115 } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) {
2116 // Automatic "Component" insertion
2117 QDeclarativeParser::Object *root = v->object;
2118 QDeclarativeParser::Object *component = new QDeclarativeParser::Object;
2119 component->type = componentTypeRef();
2120 component->typeName = "Qt/Component";
2121 component->metatype = &QDeclarativeComponent::staticMetaObject;
2122 component->location = root->location;
2123 QDeclarativeParser::Value *componentValue = new QDeclarativeParser::Value;
2124 componentValue->object = root;
2125 component->getDefaultProperty()->addValue(componentValue);
2126 v->object = component;
2127 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2129 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2136 // Compile assigning a single object instance to a regular property using the "on" syntax.
2140 // NumberAnimation on x { }
2142 bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeParser::Property *prop,
2143 QDeclarativeParser::Object *obj,
2144 QDeclarativeParser::Object *baseObj,
2145 QDeclarativeParser::Value *v,
2146 const BindingContext &ctxt)
2148 Q_ASSERT(prop->index != -1);
2149 Q_ASSERT(v->object->type != -1);
2151 if (!obj->metaObject()->property(prop->index).isWritable())
2152 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2155 // Normally buildObject() will set this up, but we need the static
2156 // meta object earlier to test for assignability. It doesn't matter
2157 // that there may still be outstanding synthesized meta object changes
2158 // on this type, as they are not relevant for assignability testing
2159 v->object->metatype = output->types.at(v->object->type).metaObject();
2160 Q_ASSERT(v->object->metaObject());
2162 // Will be true if the assigned type inherits QDeclarativePropertyValueSource
2163 bool isPropertyValue = false;
2164 // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor
2165 bool isPropertyInterceptor = false;
2166 if (QDeclarativeType *valueType = toQmlType(v->object)) {
2167 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2168 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2171 if (isPropertyValue || isPropertyInterceptor) {
2172 // Assign as a property value source
2173 COMPILE_CHECK(buildObject(v->object, ctxt));
2175 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2176 buildDynamicMeta(baseObj, ForceCreation);
2177 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2179 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(QString::fromUtf8(v->object->typeName)).arg(QString::fromUtf8(prop->name.constData())));
2185 // Compile assigning a literal or binding to a regular property
2186 bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeParser::Property *prop,
2187 QDeclarativeParser::Object *obj,
2188 QDeclarativeParser::Value *v,
2189 const BindingContext &ctxt)
2191 Q_ASSERT(prop->index != -1);
2193 if (v->value.isScript()) {
2195 //optimization for <Type>.<EnumValue> enum assignments
2196 bool isEnumAssignment = false;
2197 COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj, v, &isEnumAssignment));
2198 if (isEnumAssignment) {
2199 v->type = Value::Literal;
2203 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2205 v->type = Value::PropertyBinding;
2209 COMPILE_CHECK(testLiteralAssignment(obj->metaObject()->property(prop->index), v));
2211 v->type = Value::Literal;
2217 bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop,
2218 QDeclarativeParser::Object *obj,
2219 QDeclarativeParser::Value *v,
2222 *isAssignment = false;
2223 if (!prop.isEnumType())
2226 if (!prop.isWritable())
2227 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
2229 QString string = v->value.asString();
2230 if (!string.at(0).isUpper())
2233 QStringList parts = string.split(QLatin1Char('.'));
2234 if (parts.count() != 2)
2237 QString typeName = parts.at(0);
2238 QDeclarativeType *type = 0;
2239 unit->imports().resolveType(typeName.toUtf8(), &type, 0, 0, 0, 0);
2241 //handle enums on value types (where obj->typeName is empty)
2242 QByteArray objTypeName = obj->typeName;
2243 if (objTypeName.isEmpty()) {
2244 QDeclarativeType *objType = toQmlType(obj);
2246 objTypeName = objType->qmlTypeName();
2252 QString enumValue = parts.at(1);
2255 if (objTypeName == type->qmlTypeName()) {
2256 // When these two match, we can short cut the search
2257 if (prop.isFlagType()) {
2258 value = prop.enumerator().keysToValue(enumValue.toUtf8().constData());
2260 value = prop.enumerator().keyToValue(enumValue.toUtf8().constData());
2263 // Otherwise we have to search the whole type
2264 // This matches the logic in QDeclarativeTypeNameScriptClass
2265 QByteArray enumName = enumValue.toUtf8();
2266 const QMetaObject *metaObject = type->baseMetaObject();
2267 for (int ii = metaObject->enumeratorCount() - 1; value == -1 && ii >= 0; --ii) {
2268 QMetaEnum e = metaObject->enumerator(ii);
2269 value = e.keyToValue(enumName.constData());
2276 v->type = Value::Literal;
2277 v->value = QDeclarativeParser::Variant((double)value);
2278 *isAssignment = true;
2283 // Similar logic to above, but not knowing target property.
2284 int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const
2286 int dot = script.indexOf('.');
2288 QDeclarativeType *type = 0;
2289 unit->imports().resolveType(script.left(dot), &type, 0, 0, 0, 0);
2292 const QMetaObject *mo = type->metaObject();
2293 const char *key = script.constData() + dot+1;
2294 int i = mo->enumeratorCount();
2296 int v = mo->enumerator(i).keyToValue(key);
2304 const QMetaObject *QDeclarativeCompiler::resolveType(const QByteArray& name) const
2306 QDeclarativeType *qmltype = 0;
2307 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2311 return qmltype->metaObject();
2314 // similar to logic of completeComponentBuild, but also sticks data
2315 // into datas at the end
2316 int QDeclarativeCompiler::rewriteBinding(const QString& expression, const QByteArray& name)
2318 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2319 rewriteBinding.setName('$' + name.mid(name.lastIndexOf('.') + 1));
2320 bool isSharable = false;
2321 QString rewrite = rewriteBinding(expression, 0, &isSharable);
2323 quint32 length = rewrite.length();
2327 pc = output->cachedClosures.count();
2329 output->cachedClosures.append(0);
2331 pc = output->cachedPrograms.length();
2332 output->cachedPrograms.append(0);
2335 QByteArray compiledData =
2336 QByteArray((const char *)&pc, sizeof(quint32)) +
2337 QByteArray((const char *)&length, sizeof(quint32)) +
2338 QByteArray((const char *)rewrite.constData(),
2339 rewrite.length() * sizeof(QChar));
2341 return output->indexForByteArray(compiledData);
2344 // Ensures that the dynamic meta specification on obj is valid
2345 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj)
2347 QSet<QByteArray> propNames;
2348 QSet<QByteArray> methodNames;
2349 bool seenDefaultProperty = false;
2352 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2353 const QDeclarativeParser::Object::DynamicProperty &prop =
2354 obj->dynamicProperties.at(ii);
2356 if (prop.isDefaultProperty) {
2357 if (seenDefaultProperty)
2358 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2359 seenDefaultProperty = true;
2362 if (propNames.contains(prop.name))
2363 COMPILE_EXCEPTION(&prop, tr("Duplicate property name"));
2365 QString propName = QString::fromUtf8(prop.name);
2366 if (propName.at(0).isUpper())
2367 COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
2369 if (enginePrivate->globalClass->illegalNames().contains(propName))
2370 COMPILE_EXCEPTION(&prop, tr("Illegal property name"));
2372 propNames.insert(prop.name);
2375 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2376 QByteArray name = obj->dynamicSignals.at(ii).name;
2377 if (methodNames.contains(name))
2378 COMPILE_EXCEPTION(obj, tr("Duplicate signal name"));
2379 QString nameStr = QString::fromUtf8(name);
2380 if (nameStr.at(0).isUpper())
2381 COMPILE_EXCEPTION(obj, tr("Signal names cannot begin with an upper case letter"));
2382 if (enginePrivate->globalClass->illegalNames().contains(nameStr))
2383 COMPILE_EXCEPTION(obj, tr("Illegal signal name"));
2384 methodNames.insert(name);
2386 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2387 QByteArray name = obj->dynamicSlots.at(ii).name;
2388 if (methodNames.contains(name))
2389 COMPILE_EXCEPTION(obj, tr("Duplicate method name"));
2390 QString nameStr = QString::fromUtf8(name);
2391 if (nameStr.at(0).isUpper())
2392 COMPILE_EXCEPTION(obj, tr("Method names cannot begin with an upper case letter"));
2393 if (enginePrivate->globalClass->illegalNames().contains(nameStr))
2394 COMPILE_EXCEPTION(obj, tr("Illegal method name"));
2395 methodNames.insert(name);
2401 bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeParser::Object *obj)
2403 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2404 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2406 if (!p.defaultValue || p.type == Object::DynamicProperty::Alias)
2409 Property *property = 0;
2410 if (p.isDefaultProperty) {
2411 property = obj->getDefaultProperty();
2413 property = obj->getProperty(p.name);
2414 if (!property->values.isEmpty())
2415 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2418 if (property->value)
2419 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2421 for (int ii = 0; ii < p.defaultValue->values.count(); ++ii) {
2422 QDeclarativeParser::Value *v = p.defaultValue->values.at(ii);
2424 property->values.append(v);
2430 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2432 bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, DynamicMetaMode mode)
2435 Q_ASSERT(obj->metatype);
2437 if (mode != ForceCreation &&
2438 obj->dynamicProperties.isEmpty() &&
2439 obj->dynamicSignals.isEmpty() &&
2440 obj->dynamicSlots.isEmpty())
2443 QByteArray dynamicData(sizeof(QDeclarativeVMEMetaData), (char)0);
2445 QByteArray newClassName = obj->metatype->className();
2446 newClassName.append("_QML_");
2447 int idx = classIndexCounter()->fetchAndAddRelaxed(1);
2448 newClassName.append(QByteArray::number(idx));
2449 if (compileState.root == obj && !compileState.nested) {
2450 QString path = output->url.path();
2451 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2452 if (lastSlash > -1) {
2453 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2454 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2455 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(idx);
2459 QMetaObjectBuilder builder;
2460 builder.setClassName(newClassName);
2461 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
2463 bool hasAlias = false;
2464 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2465 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2467 int propIdx = obj->metaObject()->indexOfProperty(p.name.constData());
2468 if (-1 != propIdx) {
2469 QMetaProperty prop = obj->metaObject()->property(propIdx);
2471 COMPILE_EXCEPTION(&p, tr("Cannot override FINAL property"));
2474 if (p.isDefaultProperty &&
2475 (p.type != Object::DynamicProperty::Alias ||
2476 mode == ResolveAliases))
2477 builder.addClassInfo("DefaultProperty", p.name);
2480 int propertyType = 0;
2481 bool readonly = false;
2483 case Object::DynamicProperty::Alias:
2487 case Object::DynamicProperty::CustomList:
2488 case Object::DynamicProperty::Custom:
2490 QByteArray customTypeName;
2491 QDeclarativeType *qmltype = 0;
2493 if (!unit->imports().resolveType(p.customType, &qmltype, &url, 0, 0, 0))
2494 COMPILE_EXCEPTION(&p, tr("Invalid property type"));
2497 QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(url);
2499 Q_ASSERT(tdata->isComplete());
2501 QDeclarativeCompiledData *data = tdata->compiledData();
2502 customTypeName = data->root->className();
2506 customTypeName = qmltype->typeName();
2509 if (p.type == Object::DynamicProperty::Custom) {
2510 type = customTypeName + '*';
2511 propertyType = QMetaType::QObjectStar;
2514 type = "QDeclarativeListProperty<";
2515 type.append(customTypeName);
2517 propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
2521 case Object::DynamicProperty::Variant:
2525 case Object::DynamicProperty::Int:
2526 propertyType = QVariant::Int;
2529 case Object::DynamicProperty::Bool:
2530 propertyType = QVariant::Bool;
2533 case Object::DynamicProperty::Real:
2534 propertyType = QVariant::Double;
2537 case Object::DynamicProperty::String:
2538 propertyType = QVariant::String;
2541 case Object::DynamicProperty::Url:
2542 propertyType = QVariant::Url;
2545 case Object::DynamicProperty::Color:
2546 propertyType = QVariant::Color;
2549 case Object::DynamicProperty::Time:
2550 propertyType = QVariant::Time;
2553 case Object::DynamicProperty::Date:
2554 propertyType = QVariant::Date;
2557 case Object::DynamicProperty::DateTime:
2558 propertyType = QVariant::DateTime;
2563 ((QDeclarativeVMEMetaData *)dynamicData.data())->propertyCount++;
2564 QDeclarativeVMEMetaData::PropertyData propertyData = { propertyType };
2565 dynamicData.append((char *)&propertyData, sizeof(propertyData));
2567 builder.addSignal(p.name + "Changed()");
2568 QMetaPropertyBuilder propBuilder =
2569 builder.addProperty(p.name, type, builder.methodCount() - 1);
2570 propBuilder.setWritable(!readonly);
2573 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2574 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2576 if (p.type == Object::DynamicProperty::Alias) {
2577 if (mode == ResolveAliases) {
2578 ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++;
2579 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, p));
2581 // Need a fake signal so that the metaobject remains consistent across
2582 // the resolve and non-resolve alias runs
2583 builder.addSignal(p.name + "Changed()");
2588 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2589 const Object::DynamicSignal &s = obj->dynamicSignals.at(ii);
2590 QByteArray sig(s.name + '(');
2591 for (int jj = 0; jj < s.parameterTypes.count(); ++jj) {
2592 if (jj) sig.append(',');
2593 sig.append(s.parameterTypes.at(jj));
2596 QMetaMethodBuilder b = builder.addSignal(sig);
2597 b.setParameterNames(s.parameterNames);
2598 ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++;
2601 QStringList funcScripts;
2603 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2604 Object::DynamicSlot &s = obj->dynamicSlots[ii];
2605 QByteArray sig(s.name + '(');
2606 QString funcScript(QLatin1String("(function ") + s.name + QLatin1Char('('));
2608 for (int jj = 0; jj < s.parameterNames.count(); ++jj) {
2611 funcScript.append(QLatin1Char(','));
2613 funcScript.append(QLatin1String(s.parameterNames.at(jj)));
2614 sig.append("QVariant");
2617 funcScript.append(QLatin1Char(')'));
2618 funcScript.append(s.body);
2619 funcScript.append(QLatin1Char(')'));
2620 funcScripts << funcScript;
2622 QMetaMethodBuilder b = builder.addSlot(sig);
2623 b.setReturnType("QVariant");
2624 b.setParameterNames(s.parameterNames);
2626 ((QDeclarativeVMEMetaData *)dynamicData.data())->methodCount++;
2627 QDeclarativeVMEMetaData::MethodData methodData =
2628 { s.parameterNames.count(), 0, funcScript.length(), s.location.start.line };
2630 dynamicData.append((char *)&methodData, sizeof(methodData));
2633 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2634 const QString &funcScript = funcScripts.at(ii);
2635 QDeclarativeVMEMetaData::MethodData *data =
2636 ((QDeclarativeVMEMetaData *)dynamicData.data())->methodData() + ii;
2638 data->bodyOffset = dynamicData.size();
2640 dynamicData.append((const char *)funcScript.constData(),
2641 (funcScript.length() * sizeof(QChar)));
2644 obj->metadata = builder.toRelocatableData();
2645 builder.fromRelocatableData(&obj->extObject, obj->metatype, obj->metadata);
2647 if (mode == IgnoreAliases && hasAlias)
2648 compileState.aliasingObjects << obj;
2650 obj->synthdata = dynamicData;
2652 if (obj->synthCache) {
2653 obj->synthCache->release();
2654 obj->synthCache = 0;
2657 if (obj->type != -1) {
2658 QDeclarativePropertyCache *cache = output->types[obj->type].createPropertyCache(engine)->copy();
2659 cache->append(engine, &obj->extObject, QDeclarativePropertyCache::Data::NoFlags,
2660 QDeclarativePropertyCache::Data::IsVMEFunction,
2661 QDeclarativePropertyCache::Data::IsVMESignal);
2662 obj->synthCache = cache;
2668 bool QDeclarativeCompiler::checkValidId(QDeclarativeParser::Value *v, const QString &val)
2671 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
2673 if (val.at(0).isLetter() && !val.at(0).isLower())
2674 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
2676 QChar u(QLatin1Char('_'));
2677 for (int ii = 0; ii < val.count(); ++ii) {
2679 if (ii == 0 && !val.at(ii).isLetter() && val.at(ii) != u) {
2680 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
2681 } else if (ii != 0 && !val.at(ii).isLetterOrNumber() && val.at(ii) != u) {
2682 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
2687 if (enginePrivate->globalClass->illegalNames().contains(val))
2688 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
2693 #include <qdeclarativejsparser_p.h>
2695 static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node)
2697 if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) {
2699 static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name->asString();
2700 return QStringList() << name;
2701 } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) {
2702 QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node);
2704 QStringList rv = astNodeToStringList(expr->base);
2707 rv.append(expr->name->asString());
2710 return QStringList();
2713 bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder,
2715 QDeclarativeParser::Object *obj,
2716 const Object::DynamicProperty &prop)
2718 if (!prop.defaultValue)
2719 COMPILE_EXCEPTION(obj, tr("No property alias location"));
2721 if (prop.defaultValue->values.count() != 1 ||
2722 prop.defaultValue->values.at(0)->object ||
2723 !prop.defaultValue->values.at(0)->value.isScript())
2724 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2726 QDeclarativeJS::AST::Node *node = prop.defaultValue->values.at(0)->value.asAST();
2728 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
2730 QStringList alias = astNodeToStringList(node);
2732 if (alias.count() < 1 || alias.count() > 3)
2733 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
2735 if (!compileState.ids.contains(alias.at(0)))
2736 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
2738 QDeclarativeParser::Object *idObject = compileState.ids[alias.at(0)];
2740 QByteArray typeName;
2744 bool writable = false;
2745 if (alias.count() == 2 || alias.count() == 3) {
2746 propIdx = indexOfProperty(idObject, alias.at(1).toUtf8());
2748 if (-1 == propIdx) {
2749 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2750 } else if (propIdx > 0xFFFF) {
2751 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
2754 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
2755 if (!aliasProperty.isScriptable())
2756 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2758 writable = aliasProperty.isWritable();
2760 if (alias.count() == 3) {
2761 QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
2763 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2765 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
2767 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
2768 if (valueTypeIndex == -1)
2769 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2770 Q_ASSERT(valueTypeIndex <= 0xFF);
2772 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
2773 propIdx |= (valueTypeIndex << 16);
2776 if (aliasProperty.isEnumType())
2777 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
2779 typeName = aliasProperty.typeName();
2781 typeName = idObject->metaObject()->className();
2783 //use the base type since it has been registered with metatype system
2784 int index = typeName.indexOf("_QML_");
2786 typeName = typeName.left(index);
2788 index = typeName.indexOf("_QMLTYPE_");
2789 const QMetaObject *mo = idObject->metaObject();
2790 while (index != -1 && mo) {
2791 typeName = mo->superClass()->className();
2792 index = typeName.indexOf("_QMLTYPE_");
2793 mo = mo->superClass();
2800 if (typeName.endsWith('*'))
2801 flags |= QML_ALIAS_FLAG_PTR;
2803 data.append((const char *)&idObject->idIndex, sizeof(idObject->idIndex));
2804 data.append((const char *)&propIdx, sizeof(propIdx));
2805 data.append((const char *)&flags, sizeof(flags));
2807 builder.addSignal(prop.name + "Changed()");
2808 QMetaPropertyBuilder propBuilder =
2809 builder.addProperty(prop.name, typeName.constData(), builder.methodCount() - 1);
2810 propBuilder.setWritable(writable);
2814 bool QDeclarativeCompiler::buildBinding(QDeclarativeParser::Value *value,
2815 QDeclarativeParser::Property *prop,
2816 const BindingContext &ctxt)
2818 Q_ASSERT(prop->index != -1);
2819 Q_ASSERT(prop->parent);
2820 Q_ASSERT(prop->parent->metaObject());
2822 QMetaProperty mp = prop->parent->metaObject()->property(prop->index);
2823 if (!mp.isWritable() && !QDeclarativeMetaType::isList(prop->type))
2824 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2826 BindingReference reference;
2827 reference.expression = value->value;
2828 reference.property = prop;
2829 reference.value = value;
2830 reference.bindingContext = ctxt;
2831 addBindingReference(reference);
2836 void QDeclarativeCompiler::genBindingAssignment(QDeclarativeParser::Value *binding,
2837 QDeclarativeParser::Property *prop,
2838 QDeclarativeParser::Object *obj,
2839 QDeclarativeParser::Property *valueTypeProperty)
2842 Q_ASSERT(compileState.bindings.contains(binding));
2844 const BindingReference &ref = compileState.bindings.value(binding);
2845 if (ref.dataType == BindingReference::Experimental) {
2846 QDeclarativeInstruction store;
2847 store.setType(QDeclarativeInstruction::StoreCompiledBinding);
2848 store.assignBinding.value = ref.compiledIndex;
2849 store.assignBinding.context = ref.bindingContext.stack;
2850 store.assignBinding.owner = ref.bindingContext.owner;
2851 if (valueTypeProperty)
2852 store.assignBinding.property = (valueTypeProperty->index & 0xFFFF) |
2853 ((valueTypeProperty->type & 0xFF)) << 16 |
2854 ((prop->index & 0xFF) << 24);
2856 store.assignBinding.property = prop->index;
2857 store.assignBinding.line = binding->location.start.line;
2858 output->addInstruction(store);
2862 QDeclarativeInstruction store;
2864 store.setType(QDeclarativeInstruction::StoreBinding);
2866 store.setType(QDeclarativeInstruction::StoreBindingOnAlias);
2867 store.assignBinding.value = output->indexForByteArray(ref.compiledData);
2868 store.assignBinding.context = ref.bindingContext.stack;
2869 store.assignBinding.owner = ref.bindingContext.owner;
2870 store.assignBinding.line = binding->location.start.line;
2872 Q_ASSERT(ref.bindingContext.owner == 0 ||
2873 (ref.bindingContext.owner != 0 && valueTypeProperty));
2874 if (ref.bindingContext.owner) {
2875 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
2877 store.assignBinding.property = genPropertyData(prop);
2880 output->addInstruction(store);
2883 int QDeclarativeCompiler::genContextCache()
2885 if (compileState.ids.count() == 0)
2888 QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache(engine);
2890 for (QHash<QString, QDeclarativeParser::Object *>::ConstIterator iter = compileState.ids.begin();
2891 iter != compileState.ids.end();
2893 cache->add(iter.key(), (*iter)->idIndex);
2895 output->contextCaches.append(cache);
2896 return output->contextCaches.count() - 1;
2899 int QDeclarativeCompiler::genValueTypeData(QDeclarativeParser::Property *valueTypeProp,
2900 QDeclarativeParser::Property *prop)
2903 QDeclarativePropertyPrivate::saveValueType(prop->parent->metaObject(), prop->index,
2904 enginePrivate->valueTypes[prop->type]->metaObject(),
2905 valueTypeProp->index);
2906 // valueTypeProp->index, valueTypeProp->type);
2908 return output->indexForByteArray(data);
2911 int QDeclarativeCompiler::genPropertyData(QDeclarativeParser::Property *prop)
2913 return output->indexForByteArray(QDeclarativePropertyPrivate::saveProperty(prop->parent->metaObject(), prop->index));
2916 bool QDeclarativeCompiler::completeComponentBuild()
2918 componentStat.ids = compileState.ids.count();
2920 for (int ii = 0; ii < compileState.aliasingObjects.count(); ++ii) {
2921 QDeclarativeParser::Object *aliasObject = compileState.aliasingObjects.at(ii);
2922 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
2925 QDeclarativeV4Compiler::Expression expr;
2926 expr.component = compileState.root;
2927 expr.ids = compileState.ids;
2928 expr.importCache = output->importCache;
2929 expr.imports = unit->imports();
2931 QDeclarativeV4Compiler bindingCompiler;
2933 for (QHash<QDeclarativeParser::Value*,BindingReference>::Iterator iter = compileState.bindings.begin();
2934 iter != compileState.bindings.end(); ++iter) {
2936 BindingReference &binding = *iter;
2938 // ### We don't currently optimize for bindings on alias's - because
2939 // of the solution to QTBUG-13719
2940 if (!binding.property->isAlias) {
2941 expr.context = binding.bindingContext.object;
2942 expr.property = binding.property;
2943 expr.expression = binding.expression;
2945 int index = bindingCompiler.compile(expr, enginePrivate);
2947 binding.dataType = BindingReference::Experimental;
2948 binding.compiledIndex = index;
2949 componentStat.optimizedBindings.append(iter.key()->location);
2954 binding.dataType = BindingReference::QtScript;
2956 // Pre-rewrite the expression
2957 QString expression = binding.expression.asScript();
2959 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2960 rewriteBinding.setName('$'+binding.property->name);
2961 bool isSharable = false;
2962 expression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
2964 quint32 length = expression.length();
2968 pc = output->cachedClosures.count();
2970 output->cachedClosures.append(0);
2972 pc = output->cachedPrograms.length();
2973 output->cachedPrograms.append(0);
2976 binding.compiledData =
2977 QByteArray((const char *)&pc, sizeof(quint32)) +
2978 QByteArray((const char *)&length, sizeof(quint32)) +
2979 QByteArray((const char *)expression.constData(),
2980 expression.length() * sizeof(QChar));
2982 componentStat.scriptBindings.append(iter.key()->location);
2985 if (bindingCompiler.isValid())
2986 compileState.compiledBindingData = bindingCompiler.program();
2988 saveComponentState();
2993 void QDeclarativeCompiler::dumpStats()
2995 qWarning().nospace() << "QML Document: " << output->url.toString();
2996 for (int ii = 0; ii < savedComponentStats.count(); ++ii) {
2997 const ComponentStat &stat = savedComponentStats.at(ii);
2998 qWarning().nospace() << " Component Line " << stat.lineNumber;
2999 qWarning().nospace() << " Total Objects: " << stat.objects;
3000 qWarning().nospace() << " IDs Used: " << stat.ids;
3001 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3005 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3006 if (0 == (ii % 10)) {
3007 if (ii) output.append("\n");
3012 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3014 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3015 output.append(") ");
3017 if (!output.isEmpty())
3018 qWarning().nospace() << output.constData();
3021 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3024 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3025 if (0 == (ii % 10)) {
3026 if (ii) output.append("\n");
3031 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3033 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3034 output.append(") ");
3036 if (!output.isEmpty())
3037 qWarning().nospace() << output.constData();
3043 Returns true if from can be assigned to a (QObject) property of type
3046 bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeParser::Object *from)
3048 const QMetaObject *toMo =
3049 enginePrivate->rawMetaObjectForType(to);
3050 const QMetaObject *fromMo = from->metaObject();
3053 if (QDeclarativePropertyPrivate::equal(fromMo, toMo))
3055 fromMo = fromMo->superClass();
3060 QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeParser::Object *from)
3063 const QMetaObject *mo = from->metatype;
3064 QDeclarativeType *type = 0;
3065 while (!type && mo) {
3066 type = QDeclarativeMetaType::qmlType(mo);
3067 mo = mo->superClass();
3072 QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeParser::Object *obj)
3074 const QMetaObject *mo = obj->metatype;
3076 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3078 return QStringList();
3080 QMetaClassInfo classInfo = mo->classInfo(idx);
3081 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3085 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3086 int QDeclarativeCompiler::indexOfSignal(QDeclarativeParser::Object *object, const QByteArray &name,
3087 bool *notInRevision)
3089 if (notInRevision) *notInRevision = false;
3091 if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) {
3093 QString strName(QString::fromUtf8(name));
3094 QDeclarativePropertyCache *cache =
3095 object->synthCache?object->synthCache:output->types.at(object->type).propertyCache();
3097 QDeclarativePropertyCache::Data *d = cache->property(strName);
3098 if (notInRevision) *notInRevision = false;
3100 while (d && !(d->flags & QDeclarativePropertyCache::Data::IsFunction))
3101 d = cache->overrideData(d);
3103 if (d && !cache->isAllowedInRevision(d)) {
3104 if (notInRevision) *notInRevision = true;
3107 return d->coreIndex;
3110 if (name.endsWith("Changed")) {
3111 QByteArray propName = name.mid(0, name.length() - 7);
3113 int propIndex = indexOfProperty(object, propName, notInRevision);
3114 if (propIndex != -1) {
3115 d = cache->property(propIndex);
3116 return d->notifyIndex;
3122 return QDeclarativePropertyPrivate::findSignalByName(object->metaObject(), name).methodIndex();
3127 int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QByteArray &name,
3128 bool *notInRevision)
3130 if (notInRevision) *notInRevision = false;
3132 if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) {
3134 QString strName(QString::fromUtf8(name));
3135 QDeclarativePropertyCache *cache =
3136 object->synthCache?object->synthCache:output->types.at(object->type).propertyCache();
3138 QDeclarativePropertyCache::Data *d = cache->property(strName);
3139 // Find the first property
3140 while (d && d->flags & QDeclarativePropertyCache::Data::IsFunction)
3141 d = cache->overrideData(d);
3143 if (d && !cache->isAllowedInRevision(d)) {
3144 if (notInRevision) *notInRevision = true;
3147 return d?d->coreIndex:-1;
3150 const QMetaObject *mo = object->metaObject();
3151 return mo->indexOfProperty(name.constData());