1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "private/qdeclarativecompiler_p.h"
44 #include "private/qdeclarativeparser_p.h"
45 #include "private/qdeclarativescriptparser_p.h"
46 #include "qdeclarativepropertyvaluesource.h"
47 #include "qdeclarativecomponent.h"
48 #include "private/qmetaobjectbuilder_p.h"
49 #include "private/qdeclarativestringconverters_p.h"
50 #include "private/qdeclarativeengine_p.h"
51 #include "qdeclarativeengine.h"
52 #include "qdeclarativecontext.h"
53 #include "private/qdeclarativemetatype_p.h"
54 #include "private/qdeclarativecustomparser_p_p.h"
55 #include "private/qdeclarativecontext_p.h"
56 #include "private/qdeclarativecomponent_p.h"
57 #include "parser/qdeclarativejsast_p.h"
58 #include "private/qdeclarativevmemetaobject_p.h"
59 #include "private/qdeclarativeexpression_p.h"
60 #include "private/qdeclarativeproperty_p.h"
61 #include "private/qdeclarativerewrite_p.h"
62 #include "qdeclarativescriptstring.h"
63 #include "private/qdeclarativeglobal_p.h"
64 #include "private/qdeclarativescriptparser_p.h"
65 #include "private/qdeclarativebinding_p.h"
66 #include "private/qdeclarativev4compiler_p.h"
74 #include <QtCore/qdebug.h>
75 #include <QtCore/qdatetime.h>
79 DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP);
80 DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS);
82 using namespace QDeclarativeParser;
85 Instantiate a new QDeclarativeCompiler.
87 QDeclarativeCompiler::QDeclarativeCompiler()
88 : output(0), engine(0), unitRoot(0), unit(0)
93 Returns true if the last call to compile() caused errors.
97 bool QDeclarativeCompiler::isError() const
99 return !exceptions.isEmpty();
103 Return the list of errors from the last call to compile(), or an empty list
104 if there were no errors.
106 QList<QDeclarativeError> QDeclarativeCompiler::errors() const
112 Returns true if \a name refers to an attached property, false otherwise.
114 Attached property names are those that start with a capital letter.
116 bool QDeclarativeCompiler::isAttachedPropertyName(const QByteArray &name)
118 return !name.isEmpty() && name.at(0) >= 'A' && name.at(0) <= 'Z';
122 Returns true if \a name refers to a signal property, false otherwise.
124 Signal property names are those that start with "on", followed by a first
125 character which is either a capital letter or one or more underscores followed
126 by a capital letter, which is then followed by other allowed characters.
128 Note that although ECMA-262r3 supports dollarsigns and escaped unicode
129 character codes in property names, for simplicity and performance reasons
130 QML only supports letters, numbers and underscores.
132 bool QDeclarativeCompiler::isSignalPropertyName(const QByteArray &name)
134 if (name.length() < 3) return false;
135 if (!name.startsWith("on")) return false;
136 int ns = name.size();
137 for (int i = 2; i < ns; ++i) {
138 char curr = name.at(i);
139 if (curr == '_') continue;
140 if (curr >= 'A' && curr <= 'Z') return true;
143 return false; // consists solely of underscores - invalid.
147 \macro COMPILE_EXCEPTION
149 Inserts an error into the QDeclarativeCompiler error list, and returns false
152 \a token is used to source the error line and column, and \a desc is the
153 error itself. \a desc can be an expression that can be piped into QDebug.
158 COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(QString::fromUtf8(property->name)));
161 #define COMPILE_EXCEPTION(token, desc) \
163 QString exceptionDescription; \
164 QDeclarativeError error; \
165 error.setUrl(output->url); \
166 error.setLine((token)->location.start.line); \
167 error.setColumn((token)->location.start.column); \
168 error.setDescription(desc.trimmed()); \
169 exceptions << error; \
176 Returns false if \a is false, otherwise does nothing.
178 #define COMPILE_CHECK(a) \
180 if (!a) return false; \
184 Returns true if literal \a v can be assigned to property \a prop, otherwise
187 This test corresponds to action taken by genLiteralAssignment(). Any change
188 made here, must have a corresponding action in genLiteralAssigment().
190 bool QDeclarativeCompiler::testLiteralAssignment(const QMetaProperty &prop,
191 QDeclarativeParser::Value *v)
193 QString string = v->value.asString();
195 if (!prop.isWritable())
196 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
198 if (prop.isEnumType()) {
200 if (prop.isFlagType()) {
201 value = prop.enumerator().keysToValue(string.toUtf8().constData());
203 value = prop.enumerator().keyToValue(string.toUtf8().constData());
205 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration"));
208 int type = prop.userType();
212 case QVariant::String:
213 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
215 case QVariant::ByteArray:
216 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected"));
219 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected"));
223 bool ok = v->value.isNumber();
225 double n = v->value.asNumber();
226 if (double(uint(n)) != n)
229 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected"));
234 bool ok = v->value.isNumber();
236 double n = v->value.asNumber();
237 if (double(int(n)) != n)
240 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected"));
243 case QMetaType::Float:
244 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
246 case QVariant::Double:
247 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
249 case QVariant::Color:
252 QDeclarativeStringConverters::colorFromString(string, &ok);
253 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected"));
256 #ifndef QT_NO_DATESTRING
260 QDeclarativeStringConverters::dateFromString(string, &ok);
261 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected"));
267 QDeclarativeStringConverters::timeFromString(string, &ok);
268 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected"));
271 case QVariant::DateTime:
274 QDeclarativeStringConverters::dateTimeFromString(string, &ok);
275 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected"));
278 #endif // QT_NO_DATESTRING
279 case QVariant::Point:
280 case QVariant::PointF:
283 QPointF point = QDeclarativeStringConverters::pointFFromString(string, &ok);
284 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected"));
288 case QVariant::SizeF:
291 QSizeF size = QDeclarativeStringConverters::sizeFFromString(string, &ok);
292 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected"));
296 case QVariant::RectF:
299 QRectF rect = QDeclarativeStringConverters::rectFFromString(string, &ok);
300 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected"));
305 if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected"));
308 case QVariant::Vector3D:
311 QDeclarativeStringConverters::vector3DFromString(string, &ok);
312 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected"));
317 int t = prop.userType();
318 QDeclarativeMetaType::StringConverter converter =
319 QDeclarativeMetaType::customStringConverter(t);
321 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName(prop.type()))));
329 Generate a store instruction for assigning literal \a v to property \a prop.
331 Any literal assignment that is approved in testLiteralAssignment() must have
332 a corresponding action in this method.
334 void QDeclarativeCompiler::genLiteralAssignment(const QMetaProperty &prop,
335 QDeclarativeParser::Value *v)
337 QDeclarativeInstruction instr;
338 if (prop.isEnumType()) {
340 if (v->value.isNumber()) {
342 value = (int)v->value.asNumber();
345 if (prop.isFlagType()) {
346 value = prop.enumerator().keysToValue(v->value.asString().toUtf8().constData());
348 value = prop.enumerator().keyToValue(v->value.asString().toUtf8().constData());
351 instr.setType(QDeclarativeInstruction::StoreInteger);
352 instr.storeInteger.propertyIndex = prop.propertyIndex();
353 instr.storeInteger.value = value;
354 output->addInstruction(instr);
358 QString string = v->value.asString();
360 int type = prop.userType();
364 if (v->value.isNumber()) {
365 double n = v->value.asNumber();
366 if (double(int(n)) == n) {
367 instr.setType(QDeclarativeInstruction::StoreVariantInteger);
368 instr.storeInteger.propertyIndex = prop.propertyIndex();
369 instr.storeInteger.value = int(n);
371 instr.setType(QDeclarativeInstruction::StoreVariantDouble);
372 instr.storeDouble.propertyIndex = prop.propertyIndex();
373 instr.storeDouble.value = n;
375 } else if(v->value.isBoolean()) {
376 instr.setType(QDeclarativeInstruction::StoreVariantBool);
377 instr.storeBool.propertyIndex = prop.propertyIndex();
378 instr.storeBool.value = v->value.asBoolean();
380 instr.setType(QDeclarativeInstruction::StoreVariant);
381 instr.storeString.propertyIndex = prop.propertyIndex();
382 instr.storeString.value = output->indexForString(string);
386 case QVariant::String:
388 instr.setType(QDeclarativeInstruction::StoreString);
389 instr.storeString.propertyIndex = prop.propertyIndex();
390 instr.storeString.value = output->indexForString(string);
393 case QVariant::ByteArray:
395 instr.setType(QDeclarativeInstruction::StoreByteArray);
396 instr.storeByteArray.propertyIndex = prop.propertyIndex();
397 instr.storeByteArray.value = output->indexForByteArray(string.toLatin1());
402 instr.setType(QDeclarativeInstruction::StoreUrl);
403 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
404 instr.storeUrl.propertyIndex = prop.propertyIndex();
405 instr.storeUrl.value = output->indexForUrl(u);
410 instr.setType(QDeclarativeInstruction::StoreInteger);
411 instr.storeInteger.propertyIndex = prop.propertyIndex();
412 instr.storeInteger.value = uint(v->value.asNumber());
417 instr.setType(QDeclarativeInstruction::StoreInteger);
418 instr.storeInteger.propertyIndex = prop.propertyIndex();
419 instr.storeInteger.value = int(v->value.asNumber());
422 case QMetaType::Float:
424 instr.setType(QDeclarativeInstruction::StoreFloat);
425 instr.storeFloat.propertyIndex = prop.propertyIndex();
426 instr.storeFloat.value = float(v->value.asNumber());
429 case QVariant::Double:
431 instr.setType(QDeclarativeInstruction::StoreDouble);
432 instr.storeDouble.propertyIndex = prop.propertyIndex();
433 instr.storeDouble.value = v->value.asNumber();
436 case QVariant::Color:
438 QColor c = QDeclarativeStringConverters::colorFromString(string);
439 instr.setType(QDeclarativeInstruction::StoreColor);
440 instr.storeColor.propertyIndex = prop.propertyIndex();
441 instr.storeColor.value = c.rgba();
444 #ifndef QT_NO_DATESTRING
447 QDate d = QDeclarativeStringConverters::dateFromString(string);
448 instr.setType(QDeclarativeInstruction::StoreDate);
449 instr.storeDate.propertyIndex = prop.propertyIndex();
450 instr.storeDate.value = d.toJulianDay();
455 QTime time = QDeclarativeStringConverters::timeFromString(string);
456 instr.setType(QDeclarativeInstruction::StoreTime);
457 instr.storeTime.propertyIndex = prop.propertyIndex();
458 instr.storeTime.time = *(QDeclarativeInstruction::instr_storeTime::QTime *)&time;
461 case QVariant::DateTime:
463 QDateTime dateTime = QDeclarativeStringConverters::dateTimeFromString(string);
464 QTime time = dateTime.time();
465 instr.setType(QDeclarativeInstruction::StoreDateTime);
466 instr.storeDateTime.propertyIndex = prop.propertyIndex();
467 instr.storeDateTime.date = dateTime.date().toJulianDay();
468 instr.storeDateTime.time = *(QDeclarativeInstruction::instr_storeTime::QTime *)&time;
471 #endif // QT_NO_DATESTRING
472 case QVariant::Point:
475 QPoint point = QDeclarativeStringConverters::pointFFromString(string, &ok).toPoint();
476 instr.setType(QDeclarativeInstruction::StorePoint);
477 instr.storePoint.propertyIndex = prop.propertyIndex();
478 instr.storePoint.point.xp = point.x();
479 instr.storePoint.point.yp = point.y();
482 case QVariant::PointF:
485 QPointF point = QDeclarativeStringConverters::pointFFromString(string, &ok);
486 instr.setType(QDeclarativeInstruction::StorePointF);
487 instr.storePointF.propertyIndex = prop.propertyIndex();
488 instr.storePointF.point.xp = point.x();
489 instr.storePointF.point.yp = point.y();
495 QSize size = QDeclarativeStringConverters::sizeFFromString(string, &ok).toSize();
496 instr.setType(QDeclarativeInstruction::StoreSize);
497 instr.storeSize.propertyIndex = prop.propertyIndex();
498 instr.storeSize.size.wd = size.width();
499 instr.storeSize.size.ht = size.height();
502 case QVariant::SizeF:
505 QSizeF size = QDeclarativeStringConverters::sizeFFromString(string, &ok);
506 instr.setType(QDeclarativeInstruction::StoreSizeF);
507 instr.storeSizeF.propertyIndex = prop.propertyIndex();
508 instr.storeSizeF.size.wd = size.width();
509 instr.storeSizeF.size.ht = size.height();
515 QRect rect = QDeclarativeStringConverters::rectFFromString(string, &ok).toRect();
516 instr.setType(QDeclarativeInstruction::StoreRect);
517 instr.storeRect.propertyIndex = prop.propertyIndex();
518 instr.storeRect.rect.x1 = rect.left();
519 instr.storeRect.rect.y1 = rect.top();
520 instr.storeRect.rect.x2 = rect.right();
521 instr.storeRect.rect.y2 = rect.bottom();
524 case QVariant::RectF:
527 QRectF rect = QDeclarativeStringConverters::rectFFromString(string, &ok);
528 instr.setType(QDeclarativeInstruction::StoreRectF);
529 instr.storeRectF.propertyIndex = prop.propertyIndex();
530 instr.storeRectF.rect.xp = rect.left();
531 instr.storeRectF.rect.yp = rect.top();
532 instr.storeRectF.rect.w = rect.width();
533 instr.storeRectF.rect.h = rect.height();
538 bool b = v->value.asBoolean();
539 instr.setType(QDeclarativeInstruction::StoreBool);
540 instr.storeBool.propertyIndex = prop.propertyIndex();
541 instr.storeBool.value = b;
544 case QVariant::Vector3D:
547 QVector3D vector = QDeclarativeStringConverters::vector3DFromString(string, &ok);
548 instr.setType(QDeclarativeInstruction::StoreVector3D);
549 instr.storeVector3D.propertyIndex = prop.propertyIndex();
550 instr.storeVector3D.vector.xp = vector.x();
551 instr.storeVector3D.vector.yp = vector.y();
552 instr.storeVector3D.vector.zp = vector.z();
557 int t = prop.userType();
558 instr.setType(QDeclarativeInstruction::AssignCustomType);
559 instr.assignCustomType.propertyIndex = prop.propertyIndex();
560 instr.assignCustomType.primitive = output->indexForString(string);
561 instr.assignCustomType.type = t;
565 output->addInstruction(instr);
569 Resets data by clearing the lists that the QDeclarativeCompiler modifies.
571 void QDeclarativeCompiler::reset(QDeclarativeCompiledData *data)
574 data->primitives.clear();
576 data->bytecode.clear();
580 Compile \a unit, and store the output in \a out. \a engine is the QDeclarativeEngine
581 with which the QDeclarativeCompiledData will be associated.
583 Returns true on success, false on failure. On failure, the compile errors
584 are available from errors().
586 If the environment variant QML_COMPILER_DUMP is set
587 (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
588 on a successful compiler.
590 bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine,
591 QDeclarativeTypeData *unit,
592 QDeclarativeCompiledData *out)
602 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
603 QList<QDeclarativeScriptParser::TypeReference *> referencedTypes = unit->parser().referencedTypes();
605 for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
606 QDeclarativeCompiledData::TypeReference ref;
608 const QDeclarativeTypeData::TypeReference &tref = resolvedTypes.at(ii);
609 QDeclarativeScriptParser::TypeReference *parserRef = referencedTypes.at(ii);
612 ref.type = tref.type;
613 if (!ref.type->isCreatable()) {
614 QString err = ref.type->noCreationReason();
616 err = tr( "Element is not creatable.");
617 COMPILE_EXCEPTION(parserRef->refObjects.first(), err);
620 if (ref.type->containsRevisionedAttributes()) {
621 QDeclarativeError cacheError;
622 ref.typePropertyCache =
623 QDeclarativeEnginePrivate::get(engine)->cache(ref.type, resolvedTypes.at(ii).minorVersion, cacheError);
625 if (!ref.typePropertyCache) {
626 COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description());
628 ref.typePropertyCache->addref();
631 } else if (tref.typeData) {
632 ref.component = tref.typeData->compiledData();
634 ref.className = parserRef->name.toUtf8();
638 QDeclarativeParser::Object *root = unit->parser().tree();
641 this->engine = engine;
642 this->enginePrivate = QDeclarativeEnginePrivate::get(engine);
644 this->unitRoot = root;
649 out->dumpInstructions();
650 if (compilerStatDump())
652 Q_ASSERT(out->rootPropertyCache);
657 compileState = ComponentCompileState();
658 savedCompileStates.clear();
661 this->enginePrivate = 0;
668 void QDeclarativeCompiler::compileTree(QDeclarativeParser::Object *tree)
670 compileState.root = tree;
671 componentStat.lineNumber = tree->location.start.line;
673 // Build global import scripts
674 QStringList importedScriptIndexes;
676 foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
677 importedScriptIndexes.append(script.qualifier);
679 QDeclarativeInstruction import;
680 import.setType(QDeclarativeInstruction::StoreImportedScript);
681 import.storeScript.value = output->scripts.count();
683 QDeclarativeScriptData *scriptData = script.script->scriptData();
684 scriptData->addref();
685 output->scripts << scriptData;
686 output->addInstruction(import);
689 // We generate the importCache before we build the tree so that
690 // it can be used in the binding compiler. Given we "expect" the
691 // QML compilation to succeed, this isn't a waste.
692 output->importCache = new QDeclarativeTypeNameCache(engine);
693 for (int ii = 0; ii < importedScriptIndexes.count(); ++ii)
694 output->importCache->add(importedScriptIndexes.at(ii), ii);
695 unit->imports().populateCache(output->importCache, engine);
697 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
700 QDeclarativeInstruction init;
701 init.setType(QDeclarativeInstruction::Init);
702 init.init.bindingsSize = compileState.bindings.count();
703 init.init.parserStatusSize = compileState.parserStatusCount;
704 init.init.contextCache = genContextCache();
705 if (compileState.compiledBindingData.isEmpty())
706 init.init.compiledBinding = -1;
708 init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData);
709 output->addInstruction(init);
711 if (!compileState.v8BindingProgram.isEmpty()) {
712 QDeclarativeInstruction bindings;
713 bindings.setType(QDeclarativeInstruction::InitV8Bindings);
714 bindings.initV8Bindings.program = output->indexForString(compileState.v8BindingProgram);
715 bindings.initV8Bindings.line = compileState.v8BindingProgramLine;
716 output->addInstruction(bindings);
721 QDeclarativeInstruction def;
722 def.setType(QDeclarativeInstruction::SetDefault);
723 output->addInstruction(def);
725 QDeclarativeInstruction done;
726 done.setType(QDeclarativeInstruction::Done);
727 output->addInstruction(done);
729 Q_ASSERT(tree->metatype);
731 if (tree->metadata.isEmpty()) {
732 output->root = tree->metatype;
734 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
735 output->root = &output->rootData;
737 if (!tree->metadata.isEmpty())
738 enginePrivate->registerCompositeType(output);
741 static bool ValuePtrLessThan(const QDeclarativeParser::Value *t1, const QDeclarativeParser::Value *t2)
743 return t1->location.start.line < t2->location.start.line ||
744 (t1->location.start.line == t2->location.start.line &&
745 t1->location.start.column < t2->location.start.column);
748 bool QDeclarativeCompiler::buildObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
750 componentStat.objects++;
752 Q_ASSERT (obj->type != -1);
753 const QDeclarativeCompiledData::TypeReference &tr =
754 output->types.at(obj->type);
755 obj->metatype = tr.metaObject();
758 obj->url = tr.component->url;
760 obj->typeName = tr.type->qmlTypeName();
761 obj->className = tr.className;
763 // This object is a "Component" element
764 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
765 COMPILE_CHECK(buildComponent(obj, ctxt));
769 // Object instantiations reset the binding context
770 BindingContext objCtxt(obj);
772 // Create the synthesized meta object, ignoring aliases
773 COMPILE_CHECK(checkDynamicMeta(obj));
774 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
775 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
777 // Find the native type and check for the QDeclarativeParserStatus interface
778 QDeclarativeType *type = toQmlType(obj);
780 obj->parserStatusCast = type->parserStatusCast();
781 if (obj->parserStatusCast != -1)
782 compileState.parserStatusCount++;
784 // Check if this is a custom parser type. Custom parser types allow
785 // assignments to non-existent properties. These assignments are then
786 // compiled by the type.
787 bool isCustomParser = output->types.at(obj->type).type &&
788 output->types.at(obj->type).type->customParser() != 0;
789 QList<QDeclarativeCustomParserProperty> customProps;
791 // Fetch the list of deferred properties
792 QStringList deferredList = deferredProperties(obj);
794 // Must do id property first. This is to ensure that the id given to any
795 // id reference created matches the order in which the objects are
797 foreach(Property *prop, obj->properties) {
798 if (prop->name == "id") {
799 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
805 Property *defaultProperty = 0;
806 Property *skipProperty = 0;
807 if (obj->defaultProperty) {
808 const QMetaObject *metaObject = obj->metaObject();
809 Q_ASSERT(metaObject);
810 QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
812 Property *explicitProperty = obj->getProperty(p.name(), false);
813 if (explicitProperty && !explicitProperty->value) {
814 skipProperty = explicitProperty;
816 defaultProperty = new Property;
817 defaultProperty->parent = obj;
818 defaultProperty->isDefault = true;
819 defaultProperty->location = obj->defaultProperty->location;
820 defaultProperty->listValueRange = obj->defaultProperty->listValueRange;
821 defaultProperty->listCommaPositions = obj->defaultProperty->listCommaPositions;
823 defaultProperty->values = obj->defaultProperty->values;
824 defaultProperty->values += explicitProperty->values;
825 foreach(QDeclarativeParser::Value *value, defaultProperty->values)
827 qSort(defaultProperty->values.begin(), defaultProperty->values.end(), ValuePtrLessThan);
830 defaultProperty = obj->defaultProperty;
831 defaultProperty->addref();
834 defaultProperty = obj->defaultProperty;
835 defaultProperty->addref();
839 QDeclarativeCustomParser *cp = 0;
841 cp = output->types.at(obj->type).type->customParser();
843 // Build all explicit properties specified
844 foreach(Property *prop, obj->properties) {
846 if (prop == skipProperty)
848 if (prop->name == "id")
851 bool canDefer = false;
852 if (isCustomParser) {
853 if (doesPropertyExist(prop, obj) &&
854 (!(cp->flags() & QDeclarativeCustomParser::AcceptsAttachedProperties) ||
855 !isAttachedPropertyName(prop->name))) {
856 int ids = compileState.ids.count();
857 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
858 canDefer = ids == compileState.ids.count();
860 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
863 if (isSignalPropertyName(prop->name)) {
864 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
866 int ids = compileState.ids.count();
867 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
868 canDefer = ids == compileState.ids.count();
872 if (canDefer && !deferredList.isEmpty() &&
873 deferredList.contains(QString::fromUtf8(prop->name)))
874 prop->isDeferred = true;
878 // Build the default property
879 if (defaultProperty) {
880 Property *prop = defaultProperty;
882 bool canDefer = false;
883 if (isCustomParser) {
884 if (doesPropertyExist(prop, obj)) {
885 int ids = compileState.ids.count();
886 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
887 canDefer = ids == compileState.ids.count();
889 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
892 int ids = compileState.ids.count();
893 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
894 canDefer = ids == compileState.ids.count();
897 if (canDefer && !deferredList.isEmpty() &&
898 deferredList.contains(QString::fromUtf8(prop->name)))
899 prop->isDeferred = true;
903 defaultProperty->release();
905 // Compile custom parser parts
906 if (isCustomParser && !customProps.isEmpty()) {
910 obj->custom = cp->compile(customProps);
913 foreach (QDeclarativeError err, cp->errors()) {
914 err.setUrl(output->url);
922 void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj)
924 QDeclarativeCompiledData::TypeReference &tr = output->types[obj->type];
925 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
931 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
932 !output->types.at(obj->type).type->isExtendedType() && obj != compileState.root) {
934 QDeclarativeInstruction create;
935 create.setType(QDeclarativeInstruction::CreateSimpleObject);
936 create.createSimple.create = output->types.at(obj->type).type->createFunction();
937 create.createSimple.typeSize = output->types.at(obj->type).type->createSize();
938 create.createSimple.type = obj->type;
939 create.createSimple.line = obj->location.start.line;
940 create.createSimple.column = obj->location.start.column;
941 output->addInstruction(create);
945 QDeclarativeInstruction create;
946 create.setType(QDeclarativeInstruction::CreateObject);
947 create.create.line = obj->location.start.line;
948 create.create.column = obj->location.start.column;
949 create.create.data = -1;
950 if (!obj->custom.isEmpty())
951 create.create.data = output->indexForByteArray(obj->custom);
952 create.create.type = obj->type;
953 if (!output->types.at(create.create.type).type &&
954 !obj->bindingBitmask.isEmpty()) {
955 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
956 create.create.bindingBits =
957 output->indexForByteArray(obj->bindingBitmask);
959 create.create.bindingBits = -1;
961 output->addInstruction(create);
965 // Setup the synthesized meta object if necessary
966 if (!obj->metadata.isEmpty()) {
967 QDeclarativeInstruction meta;
968 meta.setType(QDeclarativeInstruction::StoreMetaObject);
969 meta.storeMeta.data = output->indexForByteArray(obj->metadata);
970 meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata);
971 meta.storeMeta.propertyCache = output->propertyCaches.count();
973 QDeclarativePropertyCache *propertyCache = obj->synthCache;
974 Q_ASSERT(propertyCache);
975 propertyCache->addref();
977 // Add flag for alias properties
978 if (!obj->synthdata.isEmpty()) {
979 const QDeclarativeVMEMetaData *vmeMetaData =
980 reinterpret_cast<const QDeclarativeVMEMetaData *>(obj->synthdata.constData());
981 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
982 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
983 propertyCache->property(index)->flags |= QDeclarativePropertyCache::Data::IsAlias;
987 if (obj == unitRoot) {
988 propertyCache->addref();
989 output->rootPropertyCache = propertyCache;
992 output->propertyCaches << propertyCache;
993 output->addInstruction(meta);
994 } else if (obj == unitRoot) {
995 output->rootPropertyCache = tr.createPropertyCache(engine);
996 output->rootPropertyCache->addref();
1000 if (!obj->id.isEmpty()) {
1001 QDeclarativeInstruction id;
1002 id.setType(QDeclarativeInstruction::SetId);
1003 id.setId.value = output->indexForString(obj->id);
1004 id.setId.index = obj->idIndex;
1005 output->addInstruction(id);
1009 if (tr.type && obj->parserStatusCast != -1) {
1010 QDeclarativeInstruction begin;
1011 begin.setType(QDeclarativeInstruction::BeginObject);
1012 begin.begin.castValue = obj->parserStatusCast;
1013 output->addInstruction(begin);
1019 void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj)
1021 typedef QPair<Property *, int> PropPair;
1022 foreach(const PropPair &prop, obj->scriptStringProperties) {
1023 const QString &script = prop.first->values.at(0)->value.asScript();
1024 QDeclarativeInstruction ss;
1025 ss.setType(QDeclarativeInstruction::StoreScriptString);
1026 ss.storeScriptString.propertyIndex = prop.first->index;
1027 ss.storeScriptString.value = output->indexForString(script);
1028 ss.storeScriptString.scope = prop.second;
1029 ss.storeScriptString.bindingId = rewriteBinding(script, prop.first->name);
1030 ss.storeScriptString.line = prop.first->location.start.line;
1031 output->addInstruction(ss);
1034 bool seenDefer = false;
1035 foreach(Property *prop, obj->valueProperties) {
1036 if (prop->isDeferred) {
1041 genValueProperty(prop, obj);
1044 QDeclarativeInstruction defer;
1045 defer.setType(QDeclarativeInstruction::Defer);
1046 defer.defer.deferCount = 0;
1047 int deferIdx = output->addInstruction(defer);
1048 int nextInstructionIndex = output->nextInstructionIndex();
1050 QDeclarativeInstruction init;
1051 init.setType(QDeclarativeInstruction::Init);
1052 init.init.bindingsSize = compileState.bindings.count(); // XXX - bigger than necessary
1053 init.init.parserStatusSize = compileState.parserStatusCount; // XXX - bigger than necessary
1054 init.init.contextCache = -1;
1055 init.init.compiledBinding = -1;
1056 output->addInstruction(init);
1058 foreach(Property *prop, obj->valueProperties) {
1059 if (!prop->isDeferred)
1061 genValueProperty(prop, obj);
1064 QDeclarativeInstruction done;
1065 done.setType(QDeclarativeInstruction::Done);
1066 output->addInstruction(done);
1068 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1071 foreach(Property *prop, obj->signalProperties) {
1073 QDeclarativeParser::Value *v = prop->values.at(0);
1075 if (v->type == Value::SignalObject) {
1077 genObject(v->object);
1079 QDeclarativeInstruction assign;
1080 assign.setType(QDeclarativeInstruction::AssignSignalObject);
1081 assign.assignSignalObject.line = v->location.start.line;
1082 assign.assignSignalObject.signal =
1083 output->indexForByteArray(prop->name);
1084 output->addInstruction(assign);
1086 } else if (v->type == Value::SignalExpression) {
1088 BindingContext ctxt = compileState.signalExpressions.value(v);
1090 QDeclarativeInstruction store;
1091 store.setType(QDeclarativeInstruction::StoreSignal);
1092 store.storeSignal.signalIndex = prop->index;
1093 store.storeSignal.value =
1094 output->indexForString(v->value.asScript().trimmed());
1095 store.storeSignal.context = ctxt.stack;
1096 store.storeSignal.name = output->indexForByteArray(prop->name);
1097 store.storeSignal.line = v->location.start.line;
1098 output->addInstruction(store);
1104 foreach(Property *prop, obj->attachedProperties) {
1105 QDeclarativeInstruction fetch;
1106 fetch.setType(QDeclarativeInstruction::FetchAttached);
1107 fetch.fetchAttached.id = prop->index;
1108 fetch.fetchAttached.line = prop->location.start.line;
1109 output->addInstruction(fetch);
1111 genObjectBody(prop->value);
1113 QDeclarativeInstruction pop;
1114 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1115 output->addInstruction(pop);
1118 foreach(Property *prop, obj->groupedProperties) {
1119 QDeclarativeInstruction fetch;
1120 fetch.setType(QDeclarativeInstruction::FetchObject);
1121 fetch.fetch.property = prop->index;
1122 fetch.fetch.line = prop->location.start.line;
1123 output->addInstruction(fetch);
1125 if (!prop->value->metadata.isEmpty()) {
1126 QDeclarativeInstruction meta;
1127 meta.setType(QDeclarativeInstruction::StoreMetaObject);
1128 meta.storeMeta.data = output->indexForByteArray(prop->value->metadata);
1129 meta.storeMeta.aliasData = output->indexForByteArray(prop->value->synthdata);
1130 meta.storeMeta.propertyCache = -1;
1131 output->addInstruction(meta);
1134 genObjectBody(prop->value);
1136 QDeclarativeInstruction pop;
1137 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1138 output->addInstruction(pop);
1141 foreach(Property *prop, obj->valueTypeProperties) {
1143 genValueTypeProperty(obj, prop);
1146 foreach(Property *prop, obj->valueProperties) {
1147 if (prop->isDeferred)
1150 genValueProperty(prop, obj);
1153 foreach(Property *prop, obj->valueTypeProperties) {
1155 genValueTypeProperty(obj, prop);
1159 void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeParser::Object *obj,QDeclarativeParser::Property *prop)
1161 QDeclarativeInstruction fetch;
1162 fetch.setType(QDeclarativeInstruction::FetchValueType);
1163 fetch.fetchValue.property = prop->index;
1164 fetch.fetchValue.type = prop->type;
1165 fetch.fetchValue.bindingSkipList = 0;
1167 if (obj->type == -1 || output->types.at(obj->type).component) {
1168 // We only have to do this if this is a composite type. If it is a builtin
1169 // type it can't possibly already have bindings that need to be cleared.
1170 foreach(Property *vprop, prop->value->valueProperties) {
1171 if (!vprop->values.isEmpty()) {
1172 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1173 fetch.fetchValue.bindingSkipList |= (1 << vprop->index);
1178 output->addInstruction(fetch);
1180 foreach(Property *vprop, prop->value->valueProperties) {
1181 genPropertyAssignment(vprop, prop->value, prop);
1184 QDeclarativeInstruction pop;
1185 pop.setType(QDeclarativeInstruction::PopValueType);
1186 pop.fetchValue.property = prop->index;
1187 pop.fetchValue.type = prop->type;
1188 pop.fetchValue.bindingSkipList = 0;
1189 output->addInstruction(pop);
1192 void QDeclarativeCompiler::genComponent(QDeclarativeParser::Object *obj)
1194 QDeclarativeParser::Object *root = obj->defaultProperty->values.at(0)->object;
1197 QDeclarativeInstruction create;
1198 create.setType(QDeclarativeInstruction::CreateComponent);
1199 create.createComponent.line = root->location.start.line;
1200 create.createComponent.column = root->location.start.column;
1201 create.createComponent.endLine = root->location.end.line;
1202 int createInstruction = output->addInstruction(create);
1203 int nextInstructionIndex = output->nextInstructionIndex();
1205 ComponentCompileState oldCompileState = compileState;
1206 compileState = componentState(root);
1208 QDeclarativeInstruction init;
1209 init.setType(QDeclarativeInstruction::Init);
1210 init.init.bindingsSize = compileState.bindings.count();
1211 init.init.parserStatusSize = compileState.parserStatusCount;
1212 init.init.contextCache = genContextCache();
1213 if (compileState.compiledBindingData.isEmpty())
1214 init.init.compiledBinding = -1;
1216 init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData);
1217 output->addInstruction(init);
1219 if (!compileState.v8BindingProgram.isEmpty()) {
1220 QDeclarativeInstruction bindings;
1221 bindings.setType(QDeclarativeInstruction::InitV8Bindings);
1222 bindings.initV8Bindings.program = output->indexForString(compileState.v8BindingProgram);
1223 bindings.initV8Bindings.line = compileState.v8BindingProgramLine;
1224 output->addInstruction(bindings);
1229 QDeclarativeInstruction def;
1230 def.setType(QDeclarativeInstruction::SetDefault);
1231 output->addInstruction(def);
1233 QDeclarativeInstruction done;
1234 done.setType(QDeclarativeInstruction::Done);
1235 output->addInstruction(done);
1237 output->instruction(createInstruction)->createComponent.count =
1238 output->nextInstructionIndex() - nextInstructionIndex;
1240 compileState = oldCompileState;
1242 if (!obj->id.isEmpty()) {
1243 QDeclarativeInstruction id;
1244 id.setType(QDeclarativeInstruction::SetId);
1245 id.setId.value = output->indexForString(obj->id);
1246 id.setId.index = obj->idIndex;
1247 output->addInstruction(id);
1250 if (obj == unitRoot) {
1251 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1252 output->rootPropertyCache->addref();
1256 bool QDeclarativeCompiler::buildComponent(QDeclarativeParser::Object *obj,
1257 const BindingContext &ctxt)
1259 // The special "Component" element can only have the id property and a
1260 // default property, that actually defines the component's tree
1262 // Find, check and set the "id" property (if any)
1263 Property *idProp = 0;
1264 if (obj->properties.count() > 1 ||
1265 (obj->properties.count() == 1 && obj->properties.begin().key() != "id"))
1266 COMPILE_EXCEPTION(*obj->properties.begin(), tr("Component elements may not contain properties other than id"));
1268 if (obj->properties.count())
1269 idProp = *obj->properties.begin();
1272 if (idProp->value || idProp->values.count() > 1 || idProp->values.at(0)->object)
1273 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1274 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1276 QString idVal = idProp->values.first()->primitive();
1278 if (compileState.ids.contains(idVal))
1279 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1285 // Check the Component tree is well formed
1286 if (obj->defaultProperty &&
1287 (obj->defaultProperty->value || obj->defaultProperty->values.count() > 1 ||
1288 (obj->defaultProperty->values.count() == 1 && !obj->defaultProperty->values.first()->object)))
1289 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1291 if (!obj->dynamicProperties.isEmpty())
1292 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1293 if (!obj->dynamicSignals.isEmpty())
1294 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1295 if (!obj->dynamicSlots.isEmpty())
1296 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1298 QDeclarativeParser::Object *root = 0;
1299 if (obj->defaultProperty && obj->defaultProperty->values.count())
1300 root = obj->defaultProperty->values.first()->object;
1303 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1305 // Build the component tree
1306 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1311 bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeParser::Object *obj,
1312 const BindingContext &ctxt)
1314 ComponentCompileState oldComponentCompileState = compileState;
1315 ComponentStat oldComponentStat = componentStat;
1317 compileState = ComponentCompileState();
1318 compileState.root = obj;
1319 compileState.nested = true;
1321 componentStat = ComponentStat();
1322 componentStat.lineNumber = obj->location.start.line;
1325 COMPILE_CHECK(buildObject(obj, ctxt));
1327 COMPILE_CHECK(completeComponentBuild());
1329 compileState = oldComponentCompileState;
1330 componentStat = oldComponentStat;
1336 // Build a sub-object. A sub-object is one that was not created directly by
1337 // QML - such as a grouped property object, or an attached object. Sub-object's
1338 // can't have an id, involve a custom parser, have attached properties etc.
1339 bool QDeclarativeCompiler::buildSubObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
1341 Q_ASSERT(obj->metatype);
1342 Q_ASSERT(!obj->defaultProperty);
1343 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1346 foreach(Property *prop, obj->properties) {
1347 if (isSignalPropertyName(prop->name)) {
1348 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1350 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1357 int QDeclarativeCompiler::componentTypeRef()
1359 QDeclarativeType *t = QDeclarativeMetaType::qmlType("QtQuick/Component",1,0);
1360 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1361 if (output->types.at(ii).type == t)
1364 QDeclarativeCompiledData::TypeReference ref;
1365 ref.className = "Component";
1367 output->types << ref;
1368 return output->types.count() - 1;
1371 bool QDeclarativeCompiler::buildSignal(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj,
1372 const BindingContext &ctxt)
1374 Q_ASSERT(obj->metaObject());
1376 QByteArray name = prop->name;
1377 Q_ASSERT(name.startsWith("on"));
1380 // Note that the property name could start with any alpha or '_' or '$' character,
1381 // so we need to do the lower-casing of the first alpha character.
1382 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1383 if (name[firstAlphaIndex] >= 'A' && name[firstAlphaIndex] <= 'Z') {
1384 name[firstAlphaIndex] = name[firstAlphaIndex] - 'A' + 'a';
1389 bool notInRevision = false;
1390 int sigIdx = indexOfSignal(obj, name, ¬InRevision);
1394 if (notInRevision && -1 == indexOfProperty(obj, prop->name, 0)) {
1395 Q_ASSERT(obj->type != -1);
1396 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1397 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1399 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));
1401 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)));
1405 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1407 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1411 if (prop->value || prop->values.count() != 1)
1412 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1414 prop->index = sigIdx;
1415 obj->addSignalProperty(prop);
1417 if (prop->values.at(0)->object) {
1418 COMPILE_CHECK(buildObject(prop->values.at(0)->object, ctxt));
1419 prop->values.at(0)->type = Value::SignalObject;
1421 prop->values.at(0)->type = Value::SignalExpression;
1423 if (!prop->values.at(0)->value.isScript())
1424 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1426 QString script = prop->values.at(0)->value.asScript().trimmed();
1427 if (script.isEmpty())
1428 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1430 compileState.signalExpressions.insert(prop->values.at(0), ctxt);
1439 Returns true if (value) property \a prop exists on obj, false otherwise.
1441 bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeParser::Property *prop,
1442 QDeclarativeParser::Object *obj)
1444 if(isAttachedPropertyName(prop->name) || prop->name == "id")
1447 const QMetaObject *mo = obj->metaObject();
1449 if (prop->isDefault) {
1450 QMetaProperty p = QDeclarativeMetaType::defaultProperty(mo);
1451 return p.name() != 0;
1453 int idx = indexOfProperty(obj, prop->name);
1454 return idx != -1 && mo->property(idx).isScriptable();
1461 bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop,
1462 QDeclarativeParser::Object *obj,
1463 const BindingContext &ctxt)
1465 if (prop->isEmpty())
1466 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1468 const QMetaObject *metaObject = obj->metaObject();
1469 Q_ASSERT(metaObject);
1471 if (isAttachedPropertyName(prop->name)) {
1472 // Setup attached property data
1474 if (ctxt.isSubContext()) {
1475 // Attached properties cannot be used on sub-objects. Sub-objects
1476 // always exist in a binding sub-context, which is what we test
1478 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1481 QDeclarativeType *type = 0;
1482 QDeclarativeImportedNamespace *typeNamespace = 0;
1483 unit->imports().resolveType(prop->name, &type, 0, 0, 0, &typeNamespace);
1485 if (typeNamespace) {
1486 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1489 } else if (!type || !type->attachedPropertiesType()) {
1490 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1494 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1496 Q_ASSERT(type->attachedPropertiesFunction());
1497 prop->index = type->attachedPropertiesId();
1498 prop->value->metatype = type->attachedPropertiesType();
1500 // Setup regular property data
1503 if (prop->isDefault) {
1504 p = QDeclarativeMetaType::defaultProperty(metaObject);
1507 prop->index = p.propertyIndex();
1508 prop->name = p.name();
1512 bool notInRevision = false;
1513 prop->index = indexOfProperty(obj, prop->name, ¬InRevision);
1514 if (prop->index == -1 && notInRevision) {
1515 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1516 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1518 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));
1520 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)));
1524 if (prop->index != -1) {
1525 p = metaObject->property(prop->index);
1528 if (!p.isScriptable()) {
1530 p = QMetaProperty();
1535 // We can't error here as the "id" property does not require a
1536 // successful index resolution
1538 prop->type = p.userType();
1540 // Check if this is an alias
1541 if (prop->index != -1 &&
1543 prop->parent->type != -1 &&
1544 output->types.at(prop->parent->type).component) {
1546 QDeclarativePropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1547 if (cache && cache->property(prop->index) &&
1548 cache->property(prop->index)->flags & QDeclarativePropertyCache::Data::IsAlias)
1549 prop->isAlias = true;
1552 if (prop->index != -1 && !prop->values.isEmpty())
1553 prop->parent->setBindingBit(prop->index);
1556 if (!prop->isDefault && prop->name == "id" && !ctxt.isSubContext()) {
1558 // The magic "id" behavior doesn't apply when "id" is resolved as a
1559 // default property or to sub-objects (which are always in binding
1561 COMPILE_CHECK(buildIdProperty(prop, obj));
1562 if (prop->type == QVariant::String &&
1563 prop->values.at(0)->value.isString())
1564 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1566 } else if (isAttachedPropertyName(prop->name)) {
1568 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1570 } else if (prop->index == -1) {
1572 if (prop->isDefault) {
1573 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1575 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1578 } else if (prop->value) {
1580 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1582 } else if (enginePrivate->isList(prop->type)) {
1584 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1586 } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) {
1588 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1592 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1599 bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
1600 QDeclarativeParser::Property *nsProp,
1601 QDeclarativeParser::Object *obj,
1602 const BindingContext &ctxt)
1605 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1607 foreach (Property *prop, nsProp->value->properties) {
1609 if (!isAttachedPropertyName(prop->name))
1610 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1612 // Setup attached property data
1614 QDeclarativeType *type = 0;
1615 unit->imports().resolveType(ns, prop->name, &type, 0, 0, 0);
1617 if (!type || !type->attachedPropertiesType())
1618 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1621 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1623 Q_ASSERT(type->attachedPropertiesFunction());
1624 prop->index = type->index();
1625 prop->value->metatype = type->attachedPropertiesType();
1627 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1633 void QDeclarativeCompiler::genValueProperty(QDeclarativeParser::Property *prop,
1634 QDeclarativeParser::Object *obj)
1636 if (enginePrivate->isList(prop->type)) {
1637 genListProperty(prop, obj);
1639 genPropertyAssignment(prop, obj);
1643 void QDeclarativeCompiler::genListProperty(QDeclarativeParser::Property *prop,
1644 QDeclarativeParser::Object *obj)
1646 int listType = enginePrivate->listType(prop->type);
1648 QDeclarativeInstruction fetch;
1649 fetch.setType(QDeclarativeInstruction::FetchQList);
1650 fetch.fetchQmlList.property = prop->index;
1651 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1652 fetch.fetchQmlList.type = listType;
1653 output->addInstruction(fetch);
1655 for (int ii = 0; ii < prop->values.count(); ++ii) {
1656 QDeclarativeParser::Value *v = prop->values.at(ii);
1658 if (v->type == Value::CreatedObject) {
1660 genObject(v->object);
1661 if (listTypeIsInterface) {
1662 QDeclarativeInstruction assign;
1663 assign.setType(QDeclarativeInstruction::AssignObjectList);
1664 assign.assignObjectList.line = prop->location.start.line;
1665 output->addInstruction(assign);
1667 QDeclarativeInstruction store;
1668 store.setType(QDeclarativeInstruction::StoreObjectQList);
1669 output->addInstruction(store);
1672 } else if (v->type == Value::PropertyBinding) {
1674 genBindingAssignment(v, prop, obj);
1680 QDeclarativeInstruction pop;
1681 pop.setType(QDeclarativeInstruction::PopQList);
1682 output->addInstruction(pop);
1685 void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *prop,
1686 QDeclarativeParser::Object *obj,
1687 QDeclarativeParser::Property *valueTypeProperty)
1689 for (int ii = 0; ii < prop->values.count(); ++ii) {
1690 QDeclarativeParser::Value *v = prop->values.at(ii);
1692 Q_ASSERT(v->type == Value::CreatedObject ||
1693 v->type == Value::PropertyBinding ||
1694 v->type == Value::Literal);
1696 if (v->type == Value::CreatedObject) {
1698 genObject(v->object);
1700 if (QDeclarativeMetaType::isInterface(prop->type)) {
1702 QDeclarativeInstruction store;
1703 store.setType(QDeclarativeInstruction::StoreInterface);
1704 store.storeObject.line = v->object->location.start.line;
1705 store.storeObject.propertyIndex = prop->index;
1706 output->addInstruction(store);
1708 } else if (prop->type == -1) {
1710 QDeclarativeInstruction store;
1711 store.setType(QDeclarativeInstruction::StoreVariantObject);
1712 store.storeObject.line = v->object->location.start.line;
1713 store.storeObject.propertyIndex = prop->index;
1714 output->addInstruction(store);
1718 QDeclarativeInstruction store;
1719 store.setType(QDeclarativeInstruction::StoreObject);
1720 store.storeObject.line = v->object->location.start.line;
1721 store.storeObject.propertyIndex = prop->index;
1722 output->addInstruction(store);
1725 } else if (v->type == Value::PropertyBinding) {
1727 genBindingAssignment(v, prop, obj, valueTypeProperty);
1729 } else if (v->type == Value::Literal) {
1731 QMetaProperty mp = obj->metaObject()->property(prop->index);
1732 genLiteralAssignment(mp, v);
1738 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
1740 QDeclarativeParser::Value *v = prop->onValues.at(ii);
1742 Q_ASSERT(v->type == Value::ValueSource ||
1743 v->type == Value::ValueInterceptor);
1745 if (v->type == Value::ValueSource) {
1746 genObject(v->object);
1748 QDeclarativeInstruction store;
1749 store.setType(QDeclarativeInstruction::StoreValueSource);
1750 if (valueTypeProperty) {
1751 store.assignValueSource.property = genValueTypeData(prop, valueTypeProperty);
1752 store.assignValueSource.owner = 1;
1754 store.assignValueSource.property = genPropertyData(prop);
1755 store.assignValueSource.owner = 0;
1757 QDeclarativeType *valueType = toQmlType(v->object);
1758 store.assignValueSource.castValue = valueType->propertyValueSourceCast();
1759 output->addInstruction(store);
1761 } else if (v->type == Value::ValueInterceptor) {
1762 genObject(v->object);
1764 QDeclarativeInstruction store;
1765 store.setType(QDeclarativeInstruction::StoreValueInterceptor);
1766 if (valueTypeProperty) {
1767 store.assignValueInterceptor.property = genValueTypeData(prop, valueTypeProperty);
1768 store.assignValueInterceptor.owner = 1;
1770 store.assignValueInterceptor.property = genPropertyData(prop);
1771 store.assignValueInterceptor.owner = 0;
1773 QDeclarativeType *valueType = toQmlType(v->object);
1774 store.assignValueInterceptor.castValue = valueType->propertyValueInterceptorCast();
1775 output->addInstruction(store);
1781 bool QDeclarativeCompiler::buildIdProperty(QDeclarativeParser::Property *prop,
1782 QDeclarativeParser::Object *obj)
1785 prop->values.count() > 1 ||
1786 prop->values.at(0)->object)
1787 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
1789 QDeclarativeParser::Value *idValue = prop->values.at(0);
1790 QString val = idValue->primitive();
1792 COMPILE_CHECK(checkValidId(idValue, val));
1794 if (compileState.ids.contains(val))
1795 COMPILE_EXCEPTION(prop, tr("id is not unique"));
1797 prop->values.at(0)->type = Value::Id;
1805 void QDeclarativeCompiler::addId(const QString &id, QDeclarativeParser::Object *obj)
1807 Q_ASSERT(!compileState.ids.contains(id));
1808 Q_ASSERT(obj->id == id);
1809 obj->idIndex = compileState.ids.count();
1810 compileState.ids.insert(id, obj);
1811 compileState.idIndexes.insert(obj->idIndex, obj);
1814 void QDeclarativeCompiler::addBindingReference(const BindingReference &ref)
1816 Q_ASSERT(ref.value && !compileState.bindings.contains(ref.value));
1817 compileState.bindings.insert(ref.value, ref);
1820 void QDeclarativeCompiler::saveComponentState()
1822 Q_ASSERT(compileState.root);
1823 Q_ASSERT(!savedCompileStates.contains(compileState.root));
1825 savedCompileStates.insert(compileState.root, compileState);
1826 savedComponentStats.append(componentStat);
1829 QDeclarativeCompiler::ComponentCompileState
1830 QDeclarativeCompiler::componentState(QDeclarativeParser::Object *obj)
1832 Q_ASSERT(savedCompileStates.contains(obj));
1833 return savedCompileStates.value(obj);
1836 // Build attached property object. In this example,
1840 // GridView is an attached property object.
1841 bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeParser::Property *prop,
1842 QDeclarativeParser::Object *obj,
1843 const BindingContext &ctxt)
1845 Q_ASSERT(prop->value);
1846 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
1848 obj->addAttachedProperty(prop);
1850 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1856 // Build "grouped" properties. In this example:
1858 // font.pointSize: 12
1859 // font.family: "Helvetica"
1861 // font is a nested property. pointSize and family are not.
1862 bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeParser::Property *prop,
1863 QDeclarativeParser::Object *obj,
1864 const BindingContext &ctxt)
1866 Q_ASSERT(prop->type != 0);
1867 Q_ASSERT(prop->index != -1);
1869 if (QDeclarativeValueTypeFactory::isValueType(prop->type)) {
1870 if (prop->type >= 0 /* QVariant == -1 */ && enginePrivate->valueTypes[prop->type]) {
1872 if (prop->values.count()) {
1873 if (prop->values.at(0)->location < prop->value->location) {
1874 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
1876 COMPILE_EXCEPTION(prop->values.at(0), tr( "Property has already been assigned a value"));
1880 if (!obj->metaObject()->property(prop->index).isWritable()) {
1881 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
1885 if (prop->isAlias) {
1886 foreach (Property *vtProp, prop->value->properties)
1887 vtProp->isAlias = true;
1890 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
1891 prop->value, obj, ctxt.incr()));
1892 obj->addValueTypeProperty(prop);
1894 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1898 // Load the nested property's meta type
1899 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
1900 if (!prop->value->metatype)
1901 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1903 if (prop->values.count())
1904 COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign a value directly to a grouped property"));
1906 obj->addGroupedProperty(prop);
1908 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1914 bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
1915 QDeclarativeParser::Object *obj,
1916 QDeclarativeParser::Object *baseObj,
1917 const BindingContext &ctxt)
1919 if (obj->defaultProperty)
1920 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
1921 obj->metatype = type->metaObject();
1923 foreach (Property *prop, obj->properties) {
1924 int idx = type->metaObject()->indexOfProperty(prop->name.constData());
1926 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1927 QMetaProperty p = type->metaObject()->property(idx);
1928 if (!p.isScriptable())
1929 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1931 prop->type = p.userType();
1932 prop->isValueTypeSubProperty = true;
1935 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
1937 if (prop->values.count() > 1) {
1938 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
1939 } else if (prop->values.count()) {
1940 QDeclarativeParser::Value *value = prop->values.at(0);
1942 if (value->object) {
1943 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
1944 } else if (value->value.isScript()) {
1945 // ### Check for writability
1947 //optimization for <Type>.<EnumValue> enum assignments
1948 bool isEnumAssignment = false;
1949 COMPILE_CHECK(testQualifiedEnumAssignment(p, obj, value, &isEnumAssignment));
1950 if (isEnumAssignment) {
1951 value->type = Value::Literal;
1953 BindingReference reference;
1954 reference.expression = value->value;
1955 reference.property = prop;
1956 reference.value = value;
1957 reference.bindingContext = ctxt;
1958 reference.bindingContext.owner++;
1959 addBindingReference(reference);
1960 value->type = Value::PropertyBinding;
1963 COMPILE_CHECK(testLiteralAssignment(p, value));
1964 value->type = Value::Literal;
1968 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
1969 QDeclarativeParser::Value *v = prop->onValues.at(ii);
1970 Q_ASSERT(v->object);
1972 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
1975 obj->addValueProperty(prop);
1981 // Build assignments to QML lists. QML lists are properties of type
1982 // QDeclarativeListProperty<T>. List properties can accept a list of
1983 // objects, or a single binding.
1984 bool QDeclarativeCompiler::buildListProperty(QDeclarativeParser::Property *prop,
1985 QDeclarativeParser::Object *obj,
1986 const BindingContext &ctxt)
1988 Q_ASSERT(enginePrivate->isList(prop->type));
1992 obj->addValueProperty(prop);
1994 int listType = enginePrivate->listType(t);
1995 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1997 bool assignedBinding = false;
1998 for (int ii = 0; ii < prop->values.count(); ++ii) {
1999 QDeclarativeParser::Value *v = prop->values.at(ii);
2001 v->type = Value::CreatedObject;
2002 COMPILE_CHECK(buildObject(v->object, ctxt));
2004 // We check object coercian here. We check interface assignment
2006 if (!listTypeIsInterface) {
2007 if (!canCoerce(listType, v->object)) {
2008 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2012 } else if (v->value.isScript()) {
2013 if (assignedBinding)
2014 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2016 assignedBinding = true;
2017 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2018 v->type = Value::PropertyBinding;
2020 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2027 // Compiles an assignment to a QDeclarativeScriptString property
2028 bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeParser::Property *prop,
2029 QDeclarativeParser::Object *obj,
2030 const BindingContext &ctxt)
2032 if (prop->values.count() > 1)
2033 COMPILE_EXCEPTION(prop->values.at(1), tr( "Cannot assign multiple values to a script property"));
2035 if (prop->values.at(0)->object)
2036 COMPILE_EXCEPTION(prop->values.at(0), tr( "Invalid property assignment: script expected"));
2038 obj->addScriptStringProperty(prop, ctxt.stack);
2043 // Compile regular property assignments of the form "property: <value>"
2044 bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeParser::Property *prop,
2045 QDeclarativeParser::Object *obj,
2046 const BindingContext &ctxt)
2048 obj->addValueProperty(prop);
2050 if (prop->values.count() > 1)
2051 COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign multiple values to a singular property") );
2053 for (int ii = 0; ii < prop->values.count(); ++ii) {
2054 QDeclarativeParser::Value *v = prop->values.at(ii);
2057 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2061 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2066 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
2067 QDeclarativeParser::Value *v = prop->onValues.at(ii);
2069 Q_ASSERT(v->object);
2070 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2076 // Compile assigning a single object instance to a regular property
2077 bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeParser::Property *prop,
2078 QDeclarativeParser::Object *obj,
2079 QDeclarativeParser::Value *v,
2080 const BindingContext &ctxt)
2082 Q_ASSERT(prop->index != -1);
2083 Q_ASSERT(v->object->type != -1);
2085 if (!obj->metaObject()->property(prop->index).isWritable())
2086 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2088 if (QDeclarativeMetaType::isInterface(prop->type)) {
2090 // Assigning an object to an interface ptr property
2091 COMPILE_CHECK(buildObject(v->object, ctxt));
2093 v->type = Value::CreatedObject;
2095 } else if (prop->type == -1) {
2097 // Assigning an object to a QVariant
2098 COMPILE_CHECK(buildObject(v->object, ctxt));
2100 v->type = Value::CreatedObject;
2102 // Normally buildObject() will set this up, but we need the static
2103 // meta object earlier to test for assignability. It doesn't matter
2104 // that there may still be outstanding synthesized meta object changes
2105 // on this type, as they are not relevant for assignability testing
2106 v->object->metatype = output->types.at(v->object->type).metaObject();
2107 Q_ASSERT(v->object->metaObject());
2109 // We want to raw metaObject here as the raw metaobject is the
2110 // actual property type before we applied any extensions that might
2111 // effect the properties on the type, but don't effect assignability
2112 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2114 // Will be true if the assgned type inherits propertyMetaObject
2115 bool isAssignable = false;
2116 // Determine isAssignable value
2117 if (propertyMetaObject) {
2118 const QMetaObject *c = v->object->metatype;
2120 isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject));
2121 c = c->superClass();
2126 // Simple assignment
2127 COMPILE_CHECK(buildObject(v->object, ctxt));
2129 v->type = Value::CreatedObject;
2130 } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) {
2131 // Automatic "Component" insertion
2132 QDeclarativeParser::Object *root = v->object;
2133 QDeclarativeParser::Object *component = new QDeclarativeParser::Object;
2134 component->type = componentTypeRef();
2135 component->typeName = "Qt/Component";
2136 component->metatype = &QDeclarativeComponent::staticMetaObject;
2137 component->location = root->location;
2138 QDeclarativeParser::Value *componentValue = new QDeclarativeParser::Value;
2139 componentValue->object = root;
2140 component->getDefaultProperty()->addValue(componentValue);
2141 v->object = component;
2142 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2144 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2151 // Compile assigning a single object instance to a regular property using the "on" syntax.
2155 // NumberAnimation on x { }
2157 bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeParser::Property *prop,
2158 QDeclarativeParser::Object *obj,
2159 QDeclarativeParser::Object *baseObj,
2160 QDeclarativeParser::Value *v,
2161 const BindingContext &ctxt)
2163 Q_ASSERT(prop->index != -1);
2164 Q_ASSERT(v->object->type != -1);
2166 if (!obj->metaObject()->property(prop->index).isWritable())
2167 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2170 // Normally buildObject() will set this up, but we need the static
2171 // meta object earlier to test for assignability. It doesn't matter
2172 // that there may still be outstanding synthesized meta object changes
2173 // on this type, as they are not relevant for assignability testing
2174 v->object->metatype = output->types.at(v->object->type).metaObject();
2175 Q_ASSERT(v->object->metaObject());
2177 // Will be true if the assigned type inherits QDeclarativePropertyValueSource
2178 bool isPropertyValue = false;
2179 // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor
2180 bool isPropertyInterceptor = false;
2181 if (QDeclarativeType *valueType = toQmlType(v->object)) {
2182 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2183 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2186 if (isPropertyValue || isPropertyInterceptor) {
2187 // Assign as a property value source
2188 COMPILE_CHECK(buildObject(v->object, ctxt));
2190 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2191 buildDynamicMeta(baseObj, ForceCreation);
2192 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2194 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(QString::fromUtf8(v->object->typeName)).arg(QString::fromUtf8(prop->name.constData())));
2200 // Compile assigning a literal or binding to a regular property
2201 bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeParser::Property *prop,
2202 QDeclarativeParser::Object *obj,
2203 QDeclarativeParser::Value *v,
2204 const BindingContext &ctxt)
2206 Q_ASSERT(prop->index != -1);
2208 if (v->value.isScript()) {
2210 //optimization for <Type>.<EnumValue> enum assignments
2211 bool isEnumAssignment = false;
2212 COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj, v, &isEnumAssignment));
2213 if (isEnumAssignment) {
2214 v->type = Value::Literal;
2218 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2220 v->type = Value::PropertyBinding;
2224 COMPILE_CHECK(testLiteralAssignment(obj->metaObject()->property(prop->index), v));
2226 v->type = Value::Literal;
2232 bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop,
2233 QDeclarativeParser::Object *obj,
2234 QDeclarativeParser::Value *v,
2237 *isAssignment = false;
2238 if (!prop.isEnumType())
2241 if (!prop.isWritable())
2242 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
2244 QString string = v->value.asString();
2245 if (!string.at(0).isUpper())
2248 QStringList parts = string.split(QLatin1Char('.'));
2249 if (parts.count() != 2)
2252 QString typeName = parts.at(0);
2253 QDeclarativeType *type = 0;
2254 unit->imports().resolveType(typeName.toUtf8(), &type, 0, 0, 0, 0);
2256 //handle enums on value types (where obj->typeName is empty)
2257 QByteArray objTypeName = obj->typeName;
2258 if (objTypeName.isEmpty()) {
2259 QDeclarativeType *objType = toQmlType(obj);
2261 objTypeName = objType->qmlTypeName();
2267 QString enumValue = parts.at(1);
2270 if (objTypeName == type->qmlTypeName()) {
2271 // When these two match, we can short cut the search
2272 if (prop.isFlagType()) {
2273 value = prop.enumerator().keysToValue(enumValue.toUtf8().constData());
2275 value = prop.enumerator().keyToValue(enumValue.toUtf8().constData());
2278 // Otherwise we have to search the whole type
2279 // This matches the logic in QV8TypeWrapper
2280 QByteArray enumName = enumValue.toUtf8();
2281 const QMetaObject *metaObject = type->baseMetaObject();
2282 for (int ii = metaObject->enumeratorCount() - 1; value == -1 && ii >= 0; --ii) {
2283 QMetaEnum e = metaObject->enumerator(ii);
2284 value = e.keyToValue(enumName.constData());
2291 v->type = Value::Literal;
2292 v->value = QDeclarativeParser::Variant((double)value);
2293 *isAssignment = true;
2298 // Similar logic to above, but not knowing target property.
2299 int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const
2301 int dot = script.indexOf('.');
2303 QDeclarativeType *type = 0;
2304 unit->imports().resolveType(script.left(dot), &type, 0, 0, 0, 0);
2307 const QMetaObject *mo = type->metaObject();
2308 const char *key = script.constData() + dot+1;
2309 int i = mo->enumeratorCount();
2311 int v = mo->enumerator(i).keyToValue(key);
2319 const QMetaObject *QDeclarativeCompiler::resolveType(const QByteArray& name) const
2321 QDeclarativeType *qmltype = 0;
2322 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2326 return qmltype->metaObject();
2329 // similar to logic of completeComponentBuild, but also sticks data
2330 // into primitives at the end
2331 int QDeclarativeCompiler::rewriteBinding(const QString& expression, const QByteArray& name)
2333 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2334 rewriteBinding.setName('$' + name.mid(name.lastIndexOf('.') + 1));
2336 QString rewrite = rewriteBinding(expression, 0, 0);
2338 return output->indexForString(rewrite);
2341 // Ensures that the dynamic meta specification on obj is valid
2342 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj)
2344 QSet<QByteArray> propNames;
2345 QSet<QByteArray> methodNames;
2346 bool seenDefaultProperty = false;
2349 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2350 const QDeclarativeParser::Object::DynamicProperty &prop =
2351 obj->dynamicProperties.at(ii);
2353 if (prop.isDefaultProperty) {
2354 if (seenDefaultProperty)
2355 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2356 seenDefaultProperty = true;
2359 if (propNames.contains(prop.name))
2360 COMPILE_EXCEPTION(&prop, tr("Duplicate property name"));
2362 QString propName = QString::fromUtf8(prop.name);
2363 if (propName.at(0).isUpper())
2364 COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
2366 if (enginePrivate->v8engine.illegalNames().contains(propName))
2367 COMPILE_EXCEPTION(&prop, tr("Illegal property name"));
2369 propNames.insert(prop.name);
2372 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2373 QByteArray name = obj->dynamicSignals.at(ii).name;
2374 if (methodNames.contains(name))
2375 COMPILE_EXCEPTION(obj, tr("Duplicate signal name"));
2376 QString nameStr = QString::fromUtf8(name);
2377 if (nameStr.at(0).isUpper())
2378 COMPILE_EXCEPTION(obj, tr("Signal names cannot begin with an upper case letter"));
2379 if (enginePrivate->v8engine.illegalNames().contains(nameStr))
2380 COMPILE_EXCEPTION(obj, tr("Illegal signal name"));
2381 methodNames.insert(name);
2383 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2384 QByteArray name = obj->dynamicSlots.at(ii).name;
2385 if (methodNames.contains(name))
2386 COMPILE_EXCEPTION(obj, tr("Duplicate method name"));
2387 QString nameStr = QString::fromUtf8(name);
2388 if (nameStr.at(0).isUpper())
2389 COMPILE_EXCEPTION(obj, tr("Method names cannot begin with an upper case letter"));
2390 if (enginePrivate->v8engine.illegalNames().contains(nameStr))
2391 COMPILE_EXCEPTION(obj, tr("Illegal method name"));
2392 methodNames.insert(name);
2398 bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeParser::Object *obj)
2400 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2401 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2403 if (!p.defaultValue || p.type == Object::DynamicProperty::Alias)
2406 Property *property = 0;
2407 if (p.isDefaultProperty) {
2408 property = obj->getDefaultProperty();
2410 property = obj->getProperty(p.name);
2411 if (!property->values.isEmpty())
2412 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2415 if (property->value)
2416 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2418 for (int ii = 0; ii < p.defaultValue->values.count(); ++ii) {
2419 QDeclarativeParser::Value *v = p.defaultValue->values.at(ii);
2421 property->values.append(v);
2427 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2429 bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, DynamicMetaMode mode)
2432 Q_ASSERT(obj->metatype);
2434 if (mode != ForceCreation &&
2435 obj->dynamicProperties.isEmpty() &&
2436 obj->dynamicSignals.isEmpty() &&
2437 obj->dynamicSlots.isEmpty())
2440 QByteArray dynamicData(sizeof(QDeclarativeVMEMetaData), (char)0);
2442 QByteArray newClassName = obj->metatype->className();
2443 newClassName.append("_QML_");
2444 int idx = classIndexCounter()->fetchAndAddRelaxed(1);
2445 newClassName.append(QByteArray::number(idx));
2446 if (compileState.root == obj && !compileState.nested) {
2447 QString path = output->url.path();
2448 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2449 if (lastSlash > -1) {
2450 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2451 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2452 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(idx);
2456 QMetaObjectBuilder builder;
2457 builder.setClassName(newClassName);
2458 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
2460 bool hasAlias = false;
2461 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2462 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2464 int propIdx = obj->metaObject()->indexOfProperty(p.name.constData());
2465 if (-1 != propIdx) {
2466 QMetaProperty prop = obj->metaObject()->property(propIdx);
2468 COMPILE_EXCEPTION(&p, tr("Cannot override FINAL property"));
2471 if (p.isDefaultProperty &&
2472 (p.type != Object::DynamicProperty::Alias ||
2473 mode == ResolveAliases))
2474 builder.addClassInfo("DefaultProperty", p.name);
2477 int propertyType = 0;
2478 bool readonly = false;
2480 case Object::DynamicProperty::Alias:
2484 case Object::DynamicProperty::CustomList:
2485 case Object::DynamicProperty::Custom:
2487 QByteArray customTypeName;
2488 QDeclarativeType *qmltype = 0;
2490 if (!unit->imports().resolveType(p.customType, &qmltype, &url, 0, 0, 0))
2491 COMPILE_EXCEPTION(&p, tr("Invalid property type"));
2494 QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(url);
2496 Q_ASSERT(tdata->isComplete());
2498 QDeclarativeCompiledData *data = tdata->compiledData();
2499 customTypeName = data->root->className();
2503 customTypeName = qmltype->typeName();
2506 if (p.type == Object::DynamicProperty::Custom) {
2507 type = customTypeName + '*';
2508 propertyType = QMetaType::QObjectStar;
2511 type = "QDeclarativeListProperty<";
2512 type.append(customTypeName);
2514 propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
2518 case Object::DynamicProperty::Variant:
2522 case Object::DynamicProperty::Int:
2523 propertyType = QVariant::Int;
2526 case Object::DynamicProperty::Bool:
2527 propertyType = QVariant::Bool;
2530 case Object::DynamicProperty::Real:
2531 propertyType = QVariant::Double;
2534 case Object::DynamicProperty::String:
2535 propertyType = QVariant::String;
2538 case Object::DynamicProperty::Url:
2539 propertyType = QVariant::Url;
2542 case Object::DynamicProperty::Color:
2543 propertyType = QVariant::Color;
2546 case Object::DynamicProperty::Time:
2547 propertyType = QVariant::Time;
2550 case Object::DynamicProperty::Date:
2551 propertyType = QVariant::Date;
2554 case Object::DynamicProperty::DateTime:
2555 propertyType = QVariant::DateTime;
2560 ((QDeclarativeVMEMetaData *)dynamicData.data())->propertyCount++;
2561 QDeclarativeVMEMetaData::PropertyData propertyData = { propertyType };
2562 dynamicData.append((char *)&propertyData, sizeof(propertyData));
2564 builder.addSignal(p.name + "Changed()");
2565 QMetaPropertyBuilder propBuilder =
2566 builder.addProperty(p.name, type, builder.methodCount() - 1);
2567 propBuilder.setWritable(!readonly);
2570 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2571 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2573 if (p.type == Object::DynamicProperty::Alias) {
2574 if (mode == ResolveAliases) {
2575 ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++;
2576 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, p));
2578 // Need a fake signal so that the metaobject remains consistent across
2579 // the resolve and non-resolve alias runs
2580 builder.addSignal(p.name + "Changed()");
2585 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2586 const Object::DynamicSignal &s = obj->dynamicSignals.at(ii);
2587 QByteArray sig(s.name + '(');
2588 for (int jj = 0; jj < s.parameterTypes.count(); ++jj) {
2589 if (jj) sig.append(',');
2590 sig.append(s.parameterTypes.at(jj));
2593 QMetaMethodBuilder b = builder.addSignal(sig);
2594 b.setParameterNames(s.parameterNames);
2595 ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++;
2598 QStringList funcScripts;
2600 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2601 Object::DynamicSlot &s = obj->dynamicSlots[ii];
2602 QByteArray sig(s.name + '(');
2603 QString funcScript(QLatin1String("(function ") + s.name + QLatin1Char('('));
2605 for (int jj = 0; jj < s.parameterNames.count(); ++jj) {
2608 funcScript.append(QLatin1Char(','));
2610 funcScript.append(QLatin1String(s.parameterNames.at(jj)));
2611 sig.append("QVariant");
2614 funcScript.append(QLatin1Char(')'));
2615 funcScript.append(s.body);
2616 funcScript.append(QLatin1Char(')'));
2617 funcScripts << funcScript;
2619 QMetaMethodBuilder b = builder.addSlot(sig);
2620 b.setReturnType("QVariant");
2621 b.setParameterNames(s.parameterNames);
2623 ((QDeclarativeVMEMetaData *)dynamicData.data())->methodCount++;
2624 QDeclarativeVMEMetaData::MethodData methodData =
2625 { s.parameterNames.count(), 0, funcScript.length(), s.location.start.line };
2627 dynamicData.append((char *)&methodData, sizeof(methodData));
2630 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2631 const QString &funcScript = funcScripts.at(ii);
2632 QDeclarativeVMEMetaData::MethodData *data =
2633 ((QDeclarativeVMEMetaData *)dynamicData.data())->methodData() + ii;
2635 data->bodyOffset = dynamicData.size();
2637 dynamicData.append((const char *)funcScript.constData(),
2638 (funcScript.length() * sizeof(QChar)));
2641 obj->metadata = builder.toRelocatableData();
2642 builder.fromRelocatableData(&obj->extObject, obj->metatype, obj->metadata);
2644 if (mode == IgnoreAliases && hasAlias)
2645 compileState.aliasingObjects << obj;
2647 obj->synthdata = dynamicData;
2649 if (obj->synthCache) {
2650 obj->synthCache->release();
2651 obj->synthCache = 0;
2654 if (obj->type != -1) {
2655 QDeclarativePropertyCache *cache = output->types[obj->type].createPropertyCache(engine)->copy();
2656 cache->append(engine, &obj->extObject, QDeclarativePropertyCache::Data::NoFlags,
2657 QDeclarativePropertyCache::Data::IsVMEFunction,
2658 QDeclarativePropertyCache::Data::IsVMESignal);
2659 obj->synthCache = cache;
2665 bool QDeclarativeCompiler::checkValidId(QDeclarativeParser::Value *v, const QString &val)
2668 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
2670 if (val.at(0).isLetter() && !val.at(0).isLower())
2671 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
2673 QChar u(QLatin1Char('_'));
2674 for (int ii = 0; ii < val.count(); ++ii) {
2676 if (ii == 0 && !val.at(ii).isLetter() && val.at(ii) != u) {
2677 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
2678 } else if (ii != 0 && !val.at(ii).isLetterOrNumber() && val.at(ii) != u) {
2679 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
2684 if (enginePrivate->v8engine.illegalNames().contains(val))
2685 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
2690 #include <qdeclarativejsparser_p.h>
2692 static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node)
2694 if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) {
2696 static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name->asString();
2697 return QStringList() << name;
2698 } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) {
2699 QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node);
2701 QStringList rv = astNodeToStringList(expr->base);
2704 rv.append(expr->name->asString());
2707 return QStringList();
2710 bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder,
2712 QDeclarativeParser::Object *obj,
2713 const Object::DynamicProperty &prop)
2715 if (!prop.defaultValue)
2716 COMPILE_EXCEPTION(obj, tr("No property alias location"));
2718 if (prop.defaultValue->values.count() != 1 ||
2719 prop.defaultValue->values.at(0)->object ||
2720 !prop.defaultValue->values.at(0)->value.isScript())
2721 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2723 QDeclarativeJS::AST::Node *node = prop.defaultValue->values.at(0)->value.asAST();
2725 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
2727 QStringList alias = astNodeToStringList(node);
2729 if (alias.count() < 1 || alias.count() > 3)
2730 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
2732 if (!compileState.ids.contains(alias.at(0)))
2733 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
2735 QDeclarativeParser::Object *idObject = compileState.ids[alias.at(0)];
2737 QByteArray typeName;
2741 bool writable = false;
2742 if (alias.count() == 2 || alias.count() == 3) {
2743 propIdx = indexOfProperty(idObject, alias.at(1).toUtf8());
2745 if (-1 == propIdx) {
2746 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2747 } else if (propIdx > 0xFFFF) {
2748 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
2751 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
2752 if (!aliasProperty.isScriptable())
2753 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2755 writable = aliasProperty.isWritable();
2757 if (alias.count() == 3) {
2758 QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
2760 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2762 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
2764 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
2765 if (valueTypeIndex == -1)
2766 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2767 Q_ASSERT(valueTypeIndex <= 0xFF);
2769 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
2770 propIdx |= (valueTypeIndex << 16);
2773 if (aliasProperty.isEnumType())
2774 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
2776 typeName = aliasProperty.typeName();
2778 typeName = idObject->metaObject()->className();
2780 //use the base type since it has been registered with metatype system
2781 int index = typeName.indexOf("_QML_");
2783 typeName = typeName.left(index);
2785 index = typeName.indexOf("_QMLTYPE_");
2786 const QMetaObject *mo = idObject->metaObject();
2787 while (index != -1 && mo) {
2788 typeName = mo->superClass()->className();
2789 index = typeName.indexOf("_QMLTYPE_");
2790 mo = mo->superClass();
2797 if (typeName.endsWith('*'))
2798 flags |= QML_ALIAS_FLAG_PTR;
2800 data.append((const char *)&idObject->idIndex, sizeof(idObject->idIndex));
2801 data.append((const char *)&propIdx, sizeof(propIdx));
2802 data.append((const char *)&flags, sizeof(flags));
2804 builder.addSignal(prop.name + "Changed()");
2805 QMetaPropertyBuilder propBuilder =
2806 builder.addProperty(prop.name, typeName.constData(), builder.methodCount() - 1);
2807 propBuilder.setWritable(writable);
2811 bool QDeclarativeCompiler::buildBinding(QDeclarativeParser::Value *value,
2812 QDeclarativeParser::Property *prop,
2813 const BindingContext &ctxt)
2815 Q_ASSERT(prop->index != -1);
2816 Q_ASSERT(prop->parent);
2817 Q_ASSERT(prop->parent->metaObject());
2819 QMetaProperty mp = prop->parent->metaObject()->property(prop->index);
2820 if (!mp.isWritable() && !QDeclarativeMetaType::isList(prop->type))
2821 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2823 BindingReference reference;
2824 reference.expression = value->value;
2825 reference.property = prop;
2826 reference.value = value;
2827 reference.bindingContext = ctxt;
2828 addBindingReference(reference);
2833 void QDeclarativeCompiler::genBindingAssignment(QDeclarativeParser::Value *binding,
2834 QDeclarativeParser::Property *prop,
2835 QDeclarativeParser::Object *obj,
2836 QDeclarativeParser::Property *valueTypeProperty)
2839 Q_ASSERT(compileState.bindings.contains(binding));
2841 const BindingReference &ref = compileState.bindings.value(binding);
2842 if (ref.dataType == BindingReference::V4) {
2843 QDeclarativeInstruction store;
2844 store.setType(QDeclarativeInstruction::StoreV4Binding);
2845 store.assignBinding.value = ref.compiledIndex;
2846 store.assignBinding.context = ref.bindingContext.stack;
2847 store.assignBinding.owner = ref.bindingContext.owner;
2848 if (valueTypeProperty)
2849 store.assignBinding.property = (valueTypeProperty->index & 0xFFFF) |
2850 ((valueTypeProperty->type & 0xFF)) << 16 |
2851 ((prop->index & 0xFF) << 24);
2853 store.assignBinding.property = prop->index;
2854 store.assignBinding.line = binding->location.start.line;
2855 output->addInstruction(store);
2856 } else if (ref.dataType == BindingReference::V8) {
2857 QDeclarativeInstruction store;
2858 store.setType(QDeclarativeInstruction::StoreV8Binding);
2859 store.assignBinding.value = ref.compiledIndex;
2860 store.assignBinding.context = ref.bindingContext.stack;
2861 store.assignBinding.owner = ref.bindingContext.owner;
2862 store.assignBinding.line = binding->location.start.line;
2864 Q_ASSERT(ref.bindingContext.owner == 0 ||
2865 (ref.bindingContext.owner != 0 && valueTypeProperty));
2866 if (ref.bindingContext.owner) {
2867 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
2869 store.assignBinding.property = genPropertyData(prop);
2872 output->addInstruction(store);
2874 QDeclarativeInstruction store;
2876 store.setType(QDeclarativeInstruction::StoreBinding);
2878 store.setType(QDeclarativeInstruction::StoreBindingOnAlias);
2879 store.assignBinding.value = output->indexForString(ref.rewrittenExpression);
2880 store.assignBinding.context = ref.bindingContext.stack;
2881 store.assignBinding.owner = ref.bindingContext.owner;
2882 store.assignBinding.line = binding->location.start.line;
2884 Q_ASSERT(ref.bindingContext.owner == 0 ||
2885 (ref.bindingContext.owner != 0 && valueTypeProperty));
2886 if (ref.bindingContext.owner) {
2887 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
2889 store.assignBinding.property = genPropertyData(prop);
2891 output->addInstruction(store);
2895 int QDeclarativeCompiler::genContextCache()
2897 if (compileState.ids.count() == 0)
2900 QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache();
2902 for (QHash<QString, QDeclarativeParser::Object *>::ConstIterator iter = compileState.ids.begin();
2903 iter != compileState.ids.end();
2905 cache->add(iter.key(), (*iter)->idIndex);
2907 output->contextCaches.append(cache);
2908 return output->contextCaches.count() - 1;
2911 int QDeclarativeCompiler::genValueTypeData(QDeclarativeParser::Property *valueTypeProp,
2912 QDeclarativeParser::Property *prop)
2915 QDeclarativePropertyPrivate::saveValueType(prop->parent->metaObject(), prop->index,
2916 enginePrivate->valueTypes[prop->type]->metaObject(),
2917 valueTypeProp->index);
2918 // valueTypeProp->index, valueTypeProp->type);
2920 return output->indexForByteArray(data);
2923 int QDeclarativeCompiler::genPropertyData(QDeclarativeParser::Property *prop)
2925 return output->indexForByteArray(QDeclarativePropertyPrivate::saveProperty(prop->parent->metaObject(), prop->index));
2928 bool QDeclarativeCompiler::completeComponentBuild()
2930 componentStat.ids = compileState.ids.count();
2932 for (int ii = 0; ii < compileState.aliasingObjects.count(); ++ii) {
2933 QDeclarativeParser::Object *aliasObject = compileState.aliasingObjects.at(ii);
2934 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
2937 QDeclarativeV4Compiler::Expression expr;
2938 expr.component = compileState.root;
2939 expr.ids = compileState.ids;
2940 expr.importCache = output->importCache;
2941 expr.imports = unit->imports();
2943 QDeclarativeV4Compiler bindingCompiler;
2945 QList<BindingReference*> sharedBindings;
2947 for (QHash<QDeclarativeParser::Value*,BindingReference>::Iterator iter = compileState.bindings.begin();
2948 iter != compileState.bindings.end(); ++iter) {
2950 BindingReference &binding = *iter;
2952 // ### We don't currently optimize for bindings on alias's - because
2953 // of the solution to QTBUG-13719
2954 if (!binding.property->isAlias) {
2955 expr.context = binding.bindingContext.object;
2956 expr.property = binding.property;
2957 expr.expression = binding.expression;
2959 int index = bindingCompiler.compile(expr, enginePrivate);
2961 binding.dataType = BindingReference::V4;
2962 binding.compiledIndex = index;
2963 componentStat.optimizedBindings.append(iter.key()->location);
2968 // Pre-rewrite the expression
2969 QString expression = binding.expression.asScript();
2971 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2972 rewriteBinding.setName('$'+binding.property->name);
2973 bool isSharable = false;
2974 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
2976 if (isSharable && !binding.property->isAlias /* See above re alias */ &&
2977 binding.property->type != qMetaTypeId<QDeclarativeBinding*>()) {
2978 binding.dataType = BindingReference::V8;
2979 sharedBindings.append(&iter.value());
2981 binding.dataType = BindingReference::QtScript;
2984 componentStat.scriptBindings.append(iter.key()->location);
2987 if (!sharedBindings.isEmpty()) {
2989 static bool lt(const BindingReference *lhs, const BindingReference *rhs)
2991 return lhs->value->location.start.line < rhs->value->location.start.line;
2995 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
2997 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
2998 int lineNumber = startLineNumber;
3000 QString functionArray(QLatin1String("["));
3001 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3002 BindingReference *reference = sharedBindings.at(ii);
3003 QDeclarativeParser::Value *value = reference->value;
3004 const QString &expression = reference->rewrittenExpression;
3006 if (ii != 0) functionArray += QLatin1String(",");
3008 while (lineNumber < value->location.start.line) {
3010 functionArray += QLatin1String("\n");
3013 functionArray += expression;
3014 reference->compiledIndex = ii;
3016 functionArray += QLatin1String("]");
3018 compileState.v8BindingProgram = functionArray;
3019 compileState.v8BindingProgramLine = startLineNumber;
3022 if (bindingCompiler.isValid())
3023 compileState.compiledBindingData = bindingCompiler.program();
3025 saveComponentState();
3030 void QDeclarativeCompiler::dumpStats()
3032 qWarning().nospace() << "QML Document: " << output->url.toString();
3033 for (int ii = 0; ii < savedComponentStats.count(); ++ii) {
3034 const ComponentStat &stat = savedComponentStats.at(ii);
3035 qWarning().nospace() << " Component Line " << stat.lineNumber;
3036 qWarning().nospace() << " Total Objects: " << stat.objects;
3037 qWarning().nospace() << " IDs Used: " << stat.ids;
3038 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3042 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3043 if (0 == (ii % 10)) {
3044 if (ii) output.append("\n");
3049 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3051 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3052 output.append(") ");
3054 if (!output.isEmpty())
3055 qWarning().nospace() << output.constData();
3058 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3061 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3062 if (0 == (ii % 10)) {
3063 if (ii) output.append("\n");
3068 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3070 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3071 output.append(") ");
3073 if (!output.isEmpty())
3074 qWarning().nospace() << output.constData();
3080 Returns true if from can be assigned to a (QObject) property of type
3083 bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeParser::Object *from)
3085 const QMetaObject *toMo =
3086 enginePrivate->rawMetaObjectForType(to);
3087 const QMetaObject *fromMo = from->metaObject();
3090 if (QDeclarativePropertyPrivate::equal(fromMo, toMo))
3092 fromMo = fromMo->superClass();
3097 QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeParser::Object *from)
3100 const QMetaObject *mo = from->metatype;
3101 QDeclarativeType *type = 0;
3102 while (!type && mo) {
3103 type = QDeclarativeMetaType::qmlType(mo);
3104 mo = mo->superClass();
3109 QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeParser::Object *obj)
3111 const QMetaObject *mo = obj->metatype;
3113 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3115 return QStringList();
3117 QMetaClassInfo classInfo = mo->classInfo(idx);
3118 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3122 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3123 int QDeclarativeCompiler::indexOfSignal(QDeclarativeParser::Object *object, const QByteArray &name,
3124 bool *notInRevision)
3126 if (notInRevision) *notInRevision = false;
3128 if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) {
3130 QString strName(QString::fromUtf8(name));
3131 QDeclarativePropertyCache *cache =
3132 object->synthCache?object->synthCache:output->types.at(object->type).propertyCache();
3134 QDeclarativePropertyCache::Data *d = cache->property(strName);
3135 if (notInRevision) *notInRevision = false;
3137 while (d && !(d->flags & QDeclarativePropertyCache::Data::IsFunction))
3138 d = cache->overrideData(d);
3140 if (d && !cache->isAllowedInRevision(d)) {
3141 if (notInRevision) *notInRevision = true;
3144 return d->coreIndex;
3147 if (name.endsWith("Changed")) {
3148 QByteArray propName = name.mid(0, name.length() - 7);
3150 int propIndex = indexOfProperty(object, propName, notInRevision);
3151 if (propIndex != -1) {
3152 d = cache->property(propIndex);
3153 return d->notifyIndex;
3159 return QDeclarativePropertyPrivate::findSignalByName(object->metaObject(), name).methodIndex();
3164 int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QByteArray &name,
3165 bool *notInRevision)
3167 if (notInRevision) *notInRevision = false;
3169 if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) {
3171 QString strName(QString::fromUtf8(name));
3172 QDeclarativePropertyCache *cache =
3173 object->synthCache?object->synthCache:output->types.at(object->type).propertyCache();
3175 QDeclarativePropertyCache::Data *d = cache->property(strName);
3176 // Find the first property
3177 while (d && d->flags & QDeclarativePropertyCache::Data::IsFunction)
3178 d = cache->overrideData(d);
3180 if (d && !cache->isAllowedInRevision(d)) {
3181 if (notInRevision) *notInRevision = true;
3184 return d?d->coreIndex:-1;
3187 const QMetaObject *mo = object->metaObject();
3188 return mo->indexOfProperty(name.constData());