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.programIndex = compileState.v8BindingProgramIndex;
716 bindings.initV8Bindings.line = compileState.v8BindingProgramLine;
717 output->addInstruction(bindings);
722 QDeclarativeInstruction def;
723 def.setType(QDeclarativeInstruction::SetDefault);
724 output->addInstruction(def);
726 QDeclarativeInstruction done;
727 done.setType(QDeclarativeInstruction::Done);
728 output->addInstruction(done);
730 Q_ASSERT(tree->metatype);
732 if (tree->metadata.isEmpty()) {
733 output->root = tree->metatype;
735 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
736 output->root = &output->rootData;
738 if (!tree->metadata.isEmpty())
739 enginePrivate->registerCompositeType(output);
742 static bool ValuePtrLessThan(const QDeclarativeParser::Value *t1, const QDeclarativeParser::Value *t2)
744 return t1->location.start.line < t2->location.start.line ||
745 (t1->location.start.line == t2->location.start.line &&
746 t1->location.start.column < t2->location.start.column);
749 bool QDeclarativeCompiler::buildObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
751 componentStat.objects++;
753 Q_ASSERT (obj->type != -1);
754 const QDeclarativeCompiledData::TypeReference &tr =
755 output->types.at(obj->type);
756 obj->metatype = tr.metaObject();
759 obj->typeName = tr.type->qmlTypeName();
760 obj->className = tr.className;
762 // This object is a "Component" element
763 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
764 COMPILE_CHECK(buildComponent(obj, ctxt));
768 // Object instantiations reset the binding context
769 BindingContext objCtxt(obj);
771 // Create the synthesized meta object, ignoring aliases
772 COMPILE_CHECK(checkDynamicMeta(obj));
773 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
774 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
776 // Find the native type and check for the QDeclarativeParserStatus interface
777 QDeclarativeType *type = toQmlType(obj);
779 obj->parserStatusCast = type->parserStatusCast();
780 if (obj->parserStatusCast != -1)
781 compileState.parserStatusCount++;
783 // Check if this is a custom parser type. Custom parser types allow
784 // assignments to non-existent properties. These assignments are then
785 // compiled by the type.
786 bool isCustomParser = output->types.at(obj->type).type &&
787 output->types.at(obj->type).type->customParser() != 0;
788 QList<QDeclarativeCustomParserProperty> customProps;
790 // Fetch the list of deferred properties
791 QStringList deferredList = deferredProperties(obj);
793 // Must do id property first. This is to ensure that the id given to any
794 // id reference created matches the order in which the objects are
796 foreach(Property *prop, obj->properties) {
797 if (prop->name == "id") {
798 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
804 Property *defaultProperty = 0;
805 Property *skipProperty = 0;
806 if (obj->defaultProperty) {
807 const QMetaObject *metaObject = obj->metaObject();
808 Q_ASSERT(metaObject);
809 QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
811 Property *explicitProperty = obj->getProperty(p.name(), false);
812 if (explicitProperty && !explicitProperty->value) {
813 skipProperty = explicitProperty;
815 defaultProperty = new Property;
816 defaultProperty->parent = obj;
817 defaultProperty->isDefault = true;
818 defaultProperty->location = obj->defaultProperty->location;
819 defaultProperty->listValueRange = obj->defaultProperty->listValueRange;
821 defaultProperty->values = obj->defaultProperty->values;
822 defaultProperty->values += explicitProperty->values;
823 foreach(QDeclarativeParser::Value *value, defaultProperty->values)
825 qSort(defaultProperty->values.begin(), defaultProperty->values.end(), ValuePtrLessThan);
828 defaultProperty = obj->defaultProperty;
829 defaultProperty->addref();
832 defaultProperty = obj->defaultProperty;
833 defaultProperty->addref();
837 QDeclarativeCustomParser *cp = 0;
839 cp = output->types.at(obj->type).type->customParser();
841 // Build all explicit properties specified
842 foreach(Property *prop, obj->properties) {
844 if (prop == skipProperty)
846 if (prop->name == "id")
849 bool canDefer = false;
850 if (isCustomParser) {
851 if (doesPropertyExist(prop, obj) &&
852 (!(cp->flags() & QDeclarativeCustomParser::AcceptsAttachedProperties) ||
853 !isAttachedPropertyName(prop->name))) {
854 int ids = compileState.ids.count();
855 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
856 canDefer = ids == compileState.ids.count();
858 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
861 if (isSignalPropertyName(prop->name)) {
862 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
864 int ids = compileState.ids.count();
865 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
866 canDefer = ids == compileState.ids.count();
870 if (canDefer && !deferredList.isEmpty() &&
871 deferredList.contains(QString::fromUtf8(prop->name)))
872 prop->isDeferred = true;
876 // Build the default property
877 if (defaultProperty) {
878 Property *prop = defaultProperty;
880 bool canDefer = false;
881 if (isCustomParser) {
882 if (doesPropertyExist(prop, obj)) {
883 int ids = compileState.ids.count();
884 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
885 canDefer = ids == compileState.ids.count();
887 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
890 int ids = compileState.ids.count();
891 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
892 canDefer = ids == compileState.ids.count();
895 if (canDefer && !deferredList.isEmpty() &&
896 deferredList.contains(QString::fromUtf8(prop->name)))
897 prop->isDeferred = true;
901 defaultProperty->release();
903 // Compile custom parser parts
904 if (isCustomParser && !customProps.isEmpty()) {
908 obj->custom = cp->compile(customProps);
911 foreach (QDeclarativeError err, cp->errors()) {
912 err.setUrl(output->url);
920 void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj)
922 QDeclarativeCompiledData::TypeReference &tr = output->types[obj->type];
923 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
929 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
930 !output->types.at(obj->type).type->isExtendedType() && obj != compileState.root) {
932 QDeclarativeInstruction create;
933 create.setType(QDeclarativeInstruction::CreateSimpleObject);
934 create.createSimple.create = output->types.at(obj->type).type->createFunction();
935 create.createSimple.typeSize = output->types.at(obj->type).type->createSize();
936 create.createSimple.type = obj->type;
937 create.createSimple.line = obj->location.start.line;
938 create.createSimple.column = obj->location.start.column;
939 output->addInstruction(create);
943 QDeclarativeInstruction create;
944 create.setType(QDeclarativeInstruction::CreateObject);
945 create.create.line = obj->location.start.line;
946 create.create.column = obj->location.start.column;
947 create.create.data = -1;
948 if (!obj->custom.isEmpty())
949 create.create.data = output->indexForByteArray(obj->custom);
950 create.create.type = obj->type;
951 if (!output->types.at(create.create.type).type &&
952 !obj->bindingBitmask.isEmpty()) {
953 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
954 create.create.bindingBits =
955 output->indexForByteArray(obj->bindingBitmask);
957 create.create.bindingBits = -1;
959 output->addInstruction(create);
963 // Setup the synthesized meta object if necessary
964 if (!obj->metadata.isEmpty()) {
965 QDeclarativeInstruction meta;
966 meta.setType(QDeclarativeInstruction::StoreMetaObject);
967 meta.storeMeta.data = output->indexForByteArray(obj->metadata);
968 meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata);
969 meta.storeMeta.propertyCache = output->propertyCaches.count();
971 QDeclarativePropertyCache *propertyCache = obj->synthCache;
972 Q_ASSERT(propertyCache);
973 propertyCache->addref();
975 // Add flag for alias properties
976 if (!obj->synthdata.isEmpty()) {
977 const QDeclarativeVMEMetaData *vmeMetaData =
978 reinterpret_cast<const QDeclarativeVMEMetaData *>(obj->synthdata.constData());
979 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
980 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
981 QDeclarativePropertyCache::Data *data = propertyCache->property(index);
982 data->setFlags(data->getFlags() | QDeclarativePropertyCache::Data::IsAlias);
986 if (obj == unitRoot) {
987 propertyCache->addref();
988 output->rootPropertyCache = propertyCache;
991 output->propertyCaches << propertyCache;
992 output->addInstruction(meta);
993 } else if (obj == unitRoot) {
994 output->rootPropertyCache = tr.createPropertyCache(engine);
995 output->rootPropertyCache->addref();
999 if (!obj->id.isEmpty()) {
1000 QDeclarativeInstruction id;
1001 id.setType(QDeclarativeInstruction::SetId);
1002 id.setId.value = output->indexForString(obj->id);
1003 id.setId.index = obj->idIndex;
1004 output->addInstruction(id);
1008 if (tr.type && obj->parserStatusCast != -1) {
1009 QDeclarativeInstruction begin;
1010 begin.setType(QDeclarativeInstruction::BeginObject);
1011 begin.begin.castValue = obj->parserStatusCast;
1012 output->addInstruction(begin);
1018 void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj)
1020 typedef QPair<Property *, int> PropPair;
1021 foreach(const PropPair &prop, obj->scriptStringProperties) {
1022 const QString &script = prop.first->values.at(0)->value.asScript();
1023 QDeclarativeInstruction ss;
1024 ss.setType(QDeclarativeInstruction::StoreScriptString);
1025 ss.storeScriptString.propertyIndex = prop.first->index;
1026 ss.storeScriptString.value = output->indexForString(script);
1027 ss.storeScriptString.scope = prop.second;
1028 ss.storeScriptString.bindingId = rewriteBinding(script, prop.first->name);
1029 ss.storeScriptString.line = prop.first->location.start.line;
1030 output->addInstruction(ss);
1033 bool seenDefer = false;
1034 foreach(Property *prop, obj->valueProperties) {
1035 if (prop->isDeferred) {
1040 genValueProperty(prop, obj);
1043 QDeclarativeInstruction defer;
1044 defer.setType(QDeclarativeInstruction::Defer);
1045 defer.defer.deferCount = 0;
1046 int deferIdx = output->addInstruction(defer);
1047 int nextInstructionIndex = output->nextInstructionIndex();
1049 QDeclarativeInstruction init;
1050 init.setType(QDeclarativeInstruction::Init);
1051 init.init.bindingsSize = compileState.bindings.count(); // XXX - bigger than necessary
1052 init.init.parserStatusSize = compileState.parserStatusCount; // XXX - bigger than necessary
1053 init.init.contextCache = -1;
1054 init.init.compiledBinding = -1;
1055 output->addInstruction(init);
1057 foreach(Property *prop, obj->valueProperties) {
1058 if (!prop->isDeferred)
1060 genValueProperty(prop, obj);
1063 QDeclarativeInstruction done;
1064 done.setType(QDeclarativeInstruction::Done);
1065 output->addInstruction(done);
1067 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1070 foreach(Property *prop, obj->signalProperties) {
1072 QDeclarativeParser::Value *v = prop->values.at(0);
1074 if (v->type == Value::SignalObject) {
1076 genObject(v->object);
1078 QDeclarativeInstruction assign;
1079 assign.setType(QDeclarativeInstruction::AssignSignalObject);
1080 assign.assignSignalObject.line = v->location.start.line;
1081 assign.assignSignalObject.signal =
1082 output->indexForByteArray(prop->name);
1083 output->addInstruction(assign);
1085 } else if (v->type == Value::SignalExpression) {
1087 BindingContext ctxt = compileState.signalExpressions.value(v);
1089 QDeclarativeInstruction store;
1090 store.setType(QDeclarativeInstruction::StoreSignal);
1091 store.storeSignal.signalIndex = prop->index;
1092 store.storeSignal.value =
1093 output->indexForString(v->value.asScript().trimmed());
1094 store.storeSignal.context = ctxt.stack;
1095 store.storeSignal.name = output->indexForByteArray(prop->name);
1096 store.storeSignal.line = v->location.start.line;
1097 output->addInstruction(store);
1103 foreach(Property *prop, obj->attachedProperties) {
1104 QDeclarativeInstruction fetch;
1105 fetch.setType(QDeclarativeInstruction::FetchAttached);
1106 fetch.fetchAttached.id = prop->index;
1107 fetch.fetchAttached.line = prop->location.start.line;
1108 output->addInstruction(fetch);
1110 genObjectBody(prop->value);
1112 QDeclarativeInstruction pop;
1113 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1114 output->addInstruction(pop);
1117 foreach(Property *prop, obj->groupedProperties) {
1118 QDeclarativeInstruction fetch;
1119 fetch.setType(QDeclarativeInstruction::FetchObject);
1120 fetch.fetch.property = prop->index;
1121 fetch.fetch.line = prop->location.start.line;
1122 output->addInstruction(fetch);
1124 if (!prop->value->metadata.isEmpty()) {
1125 QDeclarativeInstruction meta;
1126 meta.setType(QDeclarativeInstruction::StoreMetaObject);
1127 meta.storeMeta.data = output->indexForByteArray(prop->value->metadata);
1128 meta.storeMeta.aliasData = output->indexForByteArray(prop->value->synthdata);
1129 meta.storeMeta.propertyCache = -1;
1130 output->addInstruction(meta);
1133 genObjectBody(prop->value);
1135 QDeclarativeInstruction pop;
1136 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1137 output->addInstruction(pop);
1140 foreach(Property *prop, obj->valueTypeProperties) {
1142 genValueTypeProperty(obj, prop);
1145 foreach(Property *prop, obj->valueProperties) {
1146 if (prop->isDeferred)
1149 genValueProperty(prop, obj);
1152 foreach(Property *prop, obj->valueTypeProperties) {
1154 genValueTypeProperty(obj, prop);
1158 void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeParser::Object *obj,QDeclarativeParser::Property *prop)
1160 QDeclarativeInstruction fetch;
1161 fetch.setType(QDeclarativeInstruction::FetchValueType);
1162 fetch.fetchValue.property = prop->index;
1163 fetch.fetchValue.type = prop->type;
1164 fetch.fetchValue.bindingSkipList = 0;
1166 if (obj->type == -1 || output->types.at(obj->type).component) {
1167 // We only have to do this if this is a composite type. If it is a builtin
1168 // type it can't possibly already have bindings that need to be cleared.
1169 foreach(Property *vprop, prop->value->valueProperties) {
1170 if (!vprop->values.isEmpty()) {
1171 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1172 fetch.fetchValue.bindingSkipList |= (1 << vprop->index);
1177 output->addInstruction(fetch);
1179 foreach(Property *vprop, prop->value->valueProperties) {
1180 genPropertyAssignment(vprop, prop->value, prop);
1183 QDeclarativeInstruction pop;
1184 pop.setType(QDeclarativeInstruction::PopValueType);
1185 pop.fetchValue.property = prop->index;
1186 pop.fetchValue.type = prop->type;
1187 pop.fetchValue.bindingSkipList = 0;
1188 output->addInstruction(pop);
1191 void QDeclarativeCompiler::genComponent(QDeclarativeParser::Object *obj)
1193 QDeclarativeParser::Object *root = obj->defaultProperty->values.at(0)->object;
1196 QDeclarativeInstruction create;
1197 create.setType(QDeclarativeInstruction::CreateComponent);
1198 create.createComponent.line = root->location.start.line;
1199 create.createComponent.column = root->location.start.column;
1200 create.createComponent.endLine = root->location.end.line;
1201 int createInstruction = output->addInstruction(create);
1202 int nextInstructionIndex = output->nextInstructionIndex();
1204 ComponentCompileState oldCompileState = compileState;
1205 compileState = componentState(root);
1207 QDeclarativeInstruction init;
1208 init.setType(QDeclarativeInstruction::Init);
1209 init.init.bindingsSize = compileState.bindings.count();
1210 init.init.parserStatusSize = compileState.parserStatusCount;
1211 init.init.contextCache = genContextCache();
1212 if (compileState.compiledBindingData.isEmpty())
1213 init.init.compiledBinding = -1;
1215 init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData);
1216 output->addInstruction(init);
1218 if (!compileState.v8BindingProgram.isEmpty()) {
1219 QDeclarativeInstruction bindings;
1220 bindings.setType(QDeclarativeInstruction::InitV8Bindings);
1221 bindings.initV8Bindings.program = output->indexForString(compileState.v8BindingProgram);
1222 bindings.initV8Bindings.programIndex = compileState.v8BindingProgramIndex;
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",2,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) && cache->property(prop->index)->isAlias())
1548 prop->isAlias = true;
1551 if (prop->index != -1 && !prop->values.isEmpty())
1552 prop->parent->setBindingBit(prop->index);
1555 if (!prop->isDefault && prop->name == "id" && !ctxt.isSubContext()) {
1557 // The magic "id" behavior doesn't apply when "id" is resolved as a
1558 // default property or to sub-objects (which are always in binding
1560 COMPILE_CHECK(buildIdProperty(prop, obj));
1561 if (prop->type == QVariant::String &&
1562 prop->values.at(0)->value.isString())
1563 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1565 } else if (isAttachedPropertyName(prop->name)) {
1567 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1569 } else if (prop->index == -1) {
1571 if (prop->isDefault) {
1572 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1574 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1577 } else if (prop->value) {
1579 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1581 } else if (enginePrivate->isList(prop->type)) {
1583 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1585 } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) {
1587 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1591 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1598 bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
1599 QDeclarativeParser::Property *nsProp,
1600 QDeclarativeParser::Object *obj,
1601 const BindingContext &ctxt)
1604 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1606 foreach (Property *prop, nsProp->value->properties) {
1608 if (!isAttachedPropertyName(prop->name))
1609 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1611 // Setup attached property data
1613 QDeclarativeType *type = 0;
1614 unit->imports().resolveType(ns, prop->name, &type, 0, 0, 0);
1616 if (!type || !type->attachedPropertiesType())
1617 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1620 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1622 Q_ASSERT(type->attachedPropertiesFunction());
1623 prop->index = type->index();
1624 prop->value->metatype = type->attachedPropertiesType();
1626 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1632 void QDeclarativeCompiler::genValueProperty(QDeclarativeParser::Property *prop,
1633 QDeclarativeParser::Object *obj)
1635 if (enginePrivate->isList(prop->type)) {
1636 genListProperty(prop, obj);
1638 genPropertyAssignment(prop, obj);
1642 void QDeclarativeCompiler::genListProperty(QDeclarativeParser::Property *prop,
1643 QDeclarativeParser::Object *obj)
1645 int listType = enginePrivate->listType(prop->type);
1647 QDeclarativeInstruction fetch;
1648 fetch.setType(QDeclarativeInstruction::FetchQList);
1649 fetch.fetchQmlList.property = prop->index;
1650 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1651 fetch.fetchQmlList.type = listType;
1652 output->addInstruction(fetch);
1654 for (int ii = 0; ii < prop->values.count(); ++ii) {
1655 QDeclarativeParser::Value *v = prop->values.at(ii);
1657 if (v->type == Value::CreatedObject) {
1659 genObject(v->object);
1660 if (listTypeIsInterface) {
1661 QDeclarativeInstruction assign;
1662 assign.setType(QDeclarativeInstruction::AssignObjectList);
1663 assign.assignObjectList.line = prop->location.start.line;
1664 output->addInstruction(assign);
1666 QDeclarativeInstruction store;
1667 store.setType(QDeclarativeInstruction::StoreObjectQList);
1668 output->addInstruction(store);
1671 } else if (v->type == Value::PropertyBinding) {
1673 genBindingAssignment(v, prop, obj);
1679 QDeclarativeInstruction pop;
1680 pop.setType(QDeclarativeInstruction::PopQList);
1681 output->addInstruction(pop);
1684 void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *prop,
1685 QDeclarativeParser::Object *obj,
1686 QDeclarativeParser::Property *valueTypeProperty)
1688 for (int ii = 0; ii < prop->values.count(); ++ii) {
1689 QDeclarativeParser::Value *v = prop->values.at(ii);
1691 Q_ASSERT(v->type == Value::CreatedObject ||
1692 v->type == Value::PropertyBinding ||
1693 v->type == Value::Literal);
1695 if (v->type == Value::CreatedObject) {
1697 genObject(v->object);
1699 if (QDeclarativeMetaType::isInterface(prop->type)) {
1701 QDeclarativeInstruction store;
1702 store.setType(QDeclarativeInstruction::StoreInterface);
1703 store.storeObject.line = v->object->location.start.line;
1704 store.storeObject.propertyIndex = prop->index;
1705 output->addInstruction(store);
1707 } else if (prop->type == -1) {
1709 QDeclarativeInstruction store;
1710 store.setType(QDeclarativeInstruction::StoreVariantObject);
1711 store.storeObject.line = v->object->location.start.line;
1712 store.storeObject.propertyIndex = prop->index;
1713 output->addInstruction(store);
1717 QDeclarativeInstruction store;
1718 store.setType(QDeclarativeInstruction::StoreObject);
1719 store.storeObject.line = v->object->location.start.line;
1720 store.storeObject.propertyIndex = prop->index;
1721 output->addInstruction(store);
1724 } else if (v->type == Value::PropertyBinding) {
1726 genBindingAssignment(v, prop, obj, valueTypeProperty);
1728 } else if (v->type == Value::Literal) {
1730 QMetaProperty mp = obj->metaObject()->property(prop->index);
1731 genLiteralAssignment(mp, v);
1737 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
1739 QDeclarativeParser::Value *v = prop->onValues.at(ii);
1741 Q_ASSERT(v->type == Value::ValueSource ||
1742 v->type == Value::ValueInterceptor);
1744 if (v->type == Value::ValueSource) {
1745 genObject(v->object);
1747 QDeclarativeInstruction store;
1748 store.setType(QDeclarativeInstruction::StoreValueSource);
1749 if (valueTypeProperty) {
1750 store.assignValueSource.property = genValueTypeData(prop, valueTypeProperty);
1751 store.assignValueSource.owner = 1;
1753 store.assignValueSource.property = genPropertyData(prop);
1754 store.assignValueSource.owner = 0;
1756 QDeclarativeType *valueType = toQmlType(v->object);
1757 store.assignValueSource.castValue = valueType->propertyValueSourceCast();
1758 output->addInstruction(store);
1760 } else if (v->type == Value::ValueInterceptor) {
1761 genObject(v->object);
1763 QDeclarativeInstruction store;
1764 store.setType(QDeclarativeInstruction::StoreValueInterceptor);
1765 if (valueTypeProperty) {
1766 store.assignValueInterceptor.property = genValueTypeData(prop, valueTypeProperty);
1767 store.assignValueInterceptor.owner = 1;
1769 store.assignValueInterceptor.property = genPropertyData(prop);
1770 store.assignValueInterceptor.owner = 0;
1772 QDeclarativeType *valueType = toQmlType(v->object);
1773 store.assignValueInterceptor.castValue = valueType->propertyValueInterceptorCast();
1774 output->addInstruction(store);
1780 bool QDeclarativeCompiler::buildIdProperty(QDeclarativeParser::Property *prop,
1781 QDeclarativeParser::Object *obj)
1784 prop->values.count() > 1 ||
1785 prop->values.at(0)->object)
1786 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
1788 QDeclarativeParser::Value *idValue = prop->values.at(0);
1789 QString val = idValue->primitive();
1791 COMPILE_CHECK(checkValidId(idValue, val));
1793 if (compileState.ids.contains(val))
1794 COMPILE_EXCEPTION(prop, tr("id is not unique"));
1796 prop->values.at(0)->type = Value::Id;
1804 void QDeclarativeCompiler::addId(const QString &id, QDeclarativeParser::Object *obj)
1806 Q_ASSERT(!compileState.ids.contains(id));
1807 Q_ASSERT(obj->id == id);
1808 obj->idIndex = compileState.ids.count();
1809 compileState.ids.insert(id, obj);
1810 compileState.idIndexes.insert(obj->idIndex, obj);
1813 void QDeclarativeCompiler::addBindingReference(const BindingReference &ref)
1815 Q_ASSERT(ref.value && !compileState.bindings.contains(ref.value));
1816 compileState.bindings.insert(ref.value, ref);
1819 void QDeclarativeCompiler::saveComponentState()
1821 Q_ASSERT(compileState.root);
1822 Q_ASSERT(!savedCompileStates.contains(compileState.root));
1824 savedCompileStates.insert(compileState.root, compileState);
1825 savedComponentStats.append(componentStat);
1828 QDeclarativeCompiler::ComponentCompileState
1829 QDeclarativeCompiler::componentState(QDeclarativeParser::Object *obj)
1831 Q_ASSERT(savedCompileStates.contains(obj));
1832 return savedCompileStates.value(obj);
1835 // Build attached property object. In this example,
1839 // GridView is an attached property object.
1840 bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeParser::Property *prop,
1841 QDeclarativeParser::Object *obj,
1842 const BindingContext &ctxt)
1844 Q_ASSERT(prop->value);
1845 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
1847 obj->addAttachedProperty(prop);
1849 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1855 // Build "grouped" properties. In this example:
1857 // font.pointSize: 12
1858 // font.family: "Helvetica"
1860 // font is a nested property. pointSize and family are not.
1861 bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeParser::Property *prop,
1862 QDeclarativeParser::Object *obj,
1863 const BindingContext &ctxt)
1865 Q_ASSERT(prop->type != 0);
1866 Q_ASSERT(prop->index != -1);
1868 if (QDeclarativeValueTypeFactory::isValueType(prop->type)) {
1869 if (prop->type >= 0 /* QVariant == -1 */ && enginePrivate->valueTypes[prop->type]) {
1871 if (prop->values.count()) {
1872 if (prop->values.at(0)->location < prop->value->location) {
1873 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
1875 COMPILE_EXCEPTION(prop->values.at(0), tr( "Property has already been assigned a value"));
1879 if (!obj->metaObject()->property(prop->index).isWritable()) {
1880 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
1884 if (prop->isAlias) {
1885 foreach (Property *vtProp, prop->value->properties)
1886 vtProp->isAlias = true;
1889 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
1890 prop->value, obj, ctxt.incr()));
1891 obj->addValueTypeProperty(prop);
1893 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1897 // Load the nested property's meta type
1898 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
1899 if (!prop->value->metatype)
1900 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1902 if (prop->values.count())
1903 COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign a value directly to a grouped property"));
1905 obj->addGroupedProperty(prop);
1907 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1913 bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
1914 QDeclarativeParser::Object *obj,
1915 QDeclarativeParser::Object *baseObj,
1916 const BindingContext &ctxt)
1918 if (obj->defaultProperty)
1919 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
1920 obj->metatype = type->metaObject();
1922 foreach (Property *prop, obj->properties) {
1923 int idx = type->metaObject()->indexOfProperty(prop->name.constData());
1925 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1926 QMetaProperty p = type->metaObject()->property(idx);
1927 if (!p.isScriptable())
1928 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1930 prop->type = p.userType();
1931 prop->isValueTypeSubProperty = true;
1934 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
1936 if (prop->values.count() > 1) {
1937 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
1938 } else if (prop->values.count()) {
1939 QDeclarativeParser::Value *value = prop->values.at(0);
1941 if (value->object) {
1942 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
1943 } else if (value->value.isScript()) {
1944 // ### Check for writability
1946 //optimization for <Type>.<EnumValue> enum assignments
1947 bool isEnumAssignment = false;
1948 COMPILE_CHECK(testQualifiedEnumAssignment(p, obj, value, &isEnumAssignment));
1949 if (isEnumAssignment) {
1950 value->type = Value::Literal;
1952 BindingReference reference;
1953 reference.expression = value->value;
1954 reference.property = prop;
1955 reference.value = value;
1956 reference.bindingContext = ctxt;
1957 reference.bindingContext.owner++;
1958 addBindingReference(reference);
1959 value->type = Value::PropertyBinding;
1962 COMPILE_CHECK(testLiteralAssignment(p, value));
1963 value->type = Value::Literal;
1967 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
1968 QDeclarativeParser::Value *v = prop->onValues.at(ii);
1969 Q_ASSERT(v->object);
1971 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
1974 obj->addValueProperty(prop);
1980 // Build assignments to QML lists. QML lists are properties of type
1981 // QDeclarativeListProperty<T>. List properties can accept a list of
1982 // objects, or a single binding.
1983 bool QDeclarativeCompiler::buildListProperty(QDeclarativeParser::Property *prop,
1984 QDeclarativeParser::Object *obj,
1985 const BindingContext &ctxt)
1987 Q_ASSERT(enginePrivate->isList(prop->type));
1991 obj->addValueProperty(prop);
1993 int listType = enginePrivate->listType(t);
1994 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1996 bool assignedBinding = false;
1997 for (int ii = 0; ii < prop->values.count(); ++ii) {
1998 QDeclarativeParser::Value *v = prop->values.at(ii);
2000 v->type = Value::CreatedObject;
2001 COMPILE_CHECK(buildObject(v->object, ctxt));
2003 // We check object coercian here. We check interface assignment
2005 if (!listTypeIsInterface) {
2006 if (!canCoerce(listType, v->object)) {
2007 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2011 } else if (v->value.isScript()) {
2012 if (assignedBinding)
2013 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2015 assignedBinding = true;
2016 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2017 v->type = Value::PropertyBinding;
2019 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2026 // Compiles an assignment to a QDeclarativeScriptString property
2027 bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeParser::Property *prop,
2028 QDeclarativeParser::Object *obj,
2029 const BindingContext &ctxt)
2031 if (prop->values.count() > 1)
2032 COMPILE_EXCEPTION(prop->values.at(1), tr( "Cannot assign multiple values to a script property"));
2034 if (prop->values.at(0)->object)
2035 COMPILE_EXCEPTION(prop->values.at(0), tr( "Invalid property assignment: script expected"));
2037 obj->addScriptStringProperty(prop, ctxt.stack);
2042 // Compile regular property assignments of the form "property: <value>"
2043 bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeParser::Property *prop,
2044 QDeclarativeParser::Object *obj,
2045 const BindingContext &ctxt)
2047 obj->addValueProperty(prop);
2049 if (prop->values.count() > 1)
2050 COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign multiple values to a singular property") );
2052 for (int ii = 0; ii < prop->values.count(); ++ii) {
2053 QDeclarativeParser::Value *v = prop->values.at(ii);
2056 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2060 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2065 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
2066 QDeclarativeParser::Value *v = prop->onValues.at(ii);
2068 Q_ASSERT(v->object);
2069 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2075 // Compile assigning a single object instance to a regular property
2076 bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeParser::Property *prop,
2077 QDeclarativeParser::Object *obj,
2078 QDeclarativeParser::Value *v,
2079 const BindingContext &ctxt)
2081 Q_ASSERT(prop->index != -1);
2082 Q_ASSERT(v->object->type != -1);
2084 if (!obj->metaObject()->property(prop->index).isWritable())
2085 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2087 if (QDeclarativeMetaType::isInterface(prop->type)) {
2089 // Assigning an object to an interface ptr property
2090 COMPILE_CHECK(buildObject(v->object, ctxt));
2092 v->type = Value::CreatedObject;
2094 } else if (prop->type == -1) {
2096 // Assigning an object to a QVariant
2097 COMPILE_CHECK(buildObject(v->object, ctxt));
2099 v->type = Value::CreatedObject;
2101 // Normally buildObject() will set this up, but we need the static
2102 // meta object earlier to test for assignability. It doesn't matter
2103 // that there may still be outstanding synthesized meta object changes
2104 // on this type, as they are not relevant for assignability testing
2105 v->object->metatype = output->types.at(v->object->type).metaObject();
2106 Q_ASSERT(v->object->metaObject());
2108 // We want to raw metaObject here as the raw metaobject is the
2109 // actual property type before we applied any extensions that might
2110 // effect the properties on the type, but don't effect assignability
2111 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2113 // Will be true if the assgned type inherits propertyMetaObject
2114 bool isAssignable = false;
2115 // Determine isAssignable value
2116 if (propertyMetaObject) {
2117 const QMetaObject *c = v->object->metatype;
2119 isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject));
2120 c = c->superClass();
2125 // Simple assignment
2126 COMPILE_CHECK(buildObject(v->object, ctxt));
2128 v->type = Value::CreatedObject;
2129 } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) {
2130 // Automatic "Component" insertion
2131 QDeclarativeParser::Object *root = v->object;
2132 QDeclarativeParser::Object *component = new QDeclarativeParser::Object;
2133 component->type = componentTypeRef();
2134 component->typeName = "Qt/Component";
2135 component->metatype = &QDeclarativeComponent::staticMetaObject;
2136 component->location = root->location;
2137 QDeclarativeParser::Value *componentValue = new QDeclarativeParser::Value;
2138 componentValue->object = root;
2139 component->getDefaultProperty()->addValue(componentValue);
2140 v->object = component;
2141 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2143 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2150 // Compile assigning a single object instance to a regular property using the "on" syntax.
2154 // NumberAnimation on x { }
2156 bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeParser::Property *prop,
2157 QDeclarativeParser::Object *obj,
2158 QDeclarativeParser::Object *baseObj,
2159 QDeclarativeParser::Value *v,
2160 const BindingContext &ctxt)
2162 Q_ASSERT(prop->index != -1);
2163 Q_ASSERT(v->object->type != -1);
2165 if (!obj->metaObject()->property(prop->index).isWritable())
2166 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2169 // Normally buildObject() will set this up, but we need the static
2170 // meta object earlier to test for assignability. It doesn't matter
2171 // that there may still be outstanding synthesized meta object changes
2172 // on this type, as they are not relevant for assignability testing
2173 v->object->metatype = output->types.at(v->object->type).metaObject();
2174 Q_ASSERT(v->object->metaObject());
2176 // Will be true if the assigned type inherits QDeclarativePropertyValueSource
2177 bool isPropertyValue = false;
2178 // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor
2179 bool isPropertyInterceptor = false;
2180 if (QDeclarativeType *valueType = toQmlType(v->object)) {
2181 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2182 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2185 if (isPropertyValue || isPropertyInterceptor) {
2186 // Assign as a property value source
2187 COMPILE_CHECK(buildObject(v->object, ctxt));
2189 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2190 buildDynamicMeta(baseObj, ForceCreation);
2191 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2193 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(QString::fromUtf8(v->object->typeName)).arg(QString::fromUtf8(prop->name.constData())));
2199 // Compile assigning a literal or binding to a regular property
2200 bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeParser::Property *prop,
2201 QDeclarativeParser::Object *obj,
2202 QDeclarativeParser::Value *v,
2203 const BindingContext &ctxt)
2205 Q_ASSERT(prop->index != -1);
2207 if (v->value.isScript()) {
2209 //optimization for <Type>.<EnumValue> enum assignments
2210 bool isEnumAssignment = false;
2211 COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj, v, &isEnumAssignment));
2212 if (isEnumAssignment) {
2213 v->type = Value::Literal;
2217 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2219 v->type = Value::PropertyBinding;
2223 COMPILE_CHECK(testLiteralAssignment(obj->metaObject()->property(prop->index), v));
2225 v->type = Value::Literal;
2231 bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop,
2232 QDeclarativeParser::Object *obj,
2233 QDeclarativeParser::Value *v,
2236 *isAssignment = false;
2237 if (!prop.isEnumType())
2240 if (!prop.isWritable())
2241 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
2243 QString string = v->value.asString();
2244 if (!string.at(0).isUpper())
2247 QStringList parts = string.split(QLatin1Char('.'));
2248 if (parts.count() != 2)
2251 QString typeName = parts.at(0);
2252 QDeclarativeType *type = 0;
2253 unit->imports().resolveType(typeName.toUtf8(), &type, 0, 0, 0, 0);
2255 //handle enums on value types (where obj->typeName is empty)
2256 QByteArray objTypeName = obj->typeName;
2257 if (objTypeName.isEmpty()) {
2258 QDeclarativeType *objType = toQmlType(obj);
2260 objTypeName = objType->qmlTypeName();
2266 QString enumValue = parts.at(1);
2269 if (objTypeName == type->qmlTypeName()) {
2270 // When these two match, we can short cut the search
2271 if (prop.isFlagType()) {
2272 value = prop.enumerator().keysToValue(enumValue.toUtf8().constData());
2274 value = prop.enumerator().keyToValue(enumValue.toUtf8().constData());
2277 // Otherwise we have to search the whole type
2278 // This matches the logic in QV8TypeWrapper
2279 QByteArray enumName = enumValue.toUtf8();
2280 const QMetaObject *metaObject = type->baseMetaObject();
2281 for (int ii = metaObject->enumeratorCount() - 1; value == -1 && ii >= 0; --ii) {
2282 QMetaEnum e = metaObject->enumerator(ii);
2283 value = e.keyToValue(enumName.constData());
2290 v->type = Value::Literal;
2291 v->value = QDeclarativeParser::Variant((double)value);
2292 *isAssignment = true;
2297 // Similar logic to above, but not knowing target property.
2298 int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const
2300 int dot = script.indexOf('.');
2302 QDeclarativeType *type = 0;
2303 unit->imports().resolveType(script.left(dot), &type, 0, 0, 0, 0);
2306 const QMetaObject *mo = type->metaObject();
2307 const char *key = script.constData() + dot+1;
2308 int i = mo->enumeratorCount();
2310 int v = mo->enumerator(i).keyToValue(key);
2318 const QMetaObject *QDeclarativeCompiler::resolveType(const QByteArray& name) const
2320 QDeclarativeType *qmltype = 0;
2321 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2325 return qmltype->metaObject();
2328 // similar to logic of completeComponentBuild, but also sticks data
2329 // into primitives at the end
2330 int QDeclarativeCompiler::rewriteBinding(const QString& expression, const QByteArray& name)
2332 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2333 rewriteBinding.setName('$' + name.mid(name.lastIndexOf('.') + 1));
2335 QString rewrite = rewriteBinding(expression, 0, 0);
2337 return output->indexForString(rewrite);
2340 // Ensures that the dynamic meta specification on obj is valid
2341 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj)
2343 QSet<QByteArray> propNames;
2344 QSet<QByteArray> methodNames;
2345 bool seenDefaultProperty = false;
2348 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2349 const QDeclarativeParser::Object::DynamicProperty &prop =
2350 obj->dynamicProperties.at(ii);
2352 if (prop.isDefaultProperty) {
2353 if (seenDefaultProperty)
2354 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2355 seenDefaultProperty = true;
2358 if (propNames.contains(prop.name))
2359 COMPILE_EXCEPTION(&prop, tr("Duplicate property name"));
2361 QString propName = QString::fromUtf8(prop.name);
2362 if (propName.at(0).isUpper())
2363 COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
2365 if (enginePrivate->v8engine.illegalNames().contains(propName))
2366 COMPILE_EXCEPTION(&prop, tr("Illegal property name"));
2368 propNames.insert(prop.name);
2371 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2372 QByteArray name = obj->dynamicSignals.at(ii).name;
2373 if (methodNames.contains(name))
2374 COMPILE_EXCEPTION(obj, tr("Duplicate signal name"));
2375 QString nameStr = QString::fromUtf8(name);
2376 if (nameStr.at(0).isUpper())
2377 COMPILE_EXCEPTION(obj, tr("Signal names cannot begin with an upper case letter"));
2378 if (enginePrivate->v8engine.illegalNames().contains(nameStr))
2379 COMPILE_EXCEPTION(obj, tr("Illegal signal name"));
2380 methodNames.insert(name);
2382 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2383 QByteArray name = obj->dynamicSlots.at(ii).name;
2384 if (methodNames.contains(name))
2385 COMPILE_EXCEPTION(obj, tr("Duplicate method name"));
2386 QString nameStr = QString::fromUtf8(name);
2387 if (nameStr.at(0).isUpper())
2388 COMPILE_EXCEPTION(obj, tr("Method names cannot begin with an upper case letter"));
2389 if (enginePrivate->v8engine.illegalNames().contains(nameStr))
2390 COMPILE_EXCEPTION(obj, tr("Illegal method name"));
2391 methodNames.insert(name);
2397 bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeParser::Object *obj)
2399 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2400 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2402 if (!p.defaultValue || p.type == Object::DynamicProperty::Alias)
2405 Property *property = 0;
2406 if (p.isDefaultProperty) {
2407 property = obj->getDefaultProperty();
2409 property = obj->getProperty(p.name);
2410 if (!property->values.isEmpty())
2411 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2414 if (property->value)
2415 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2417 for (int ii = 0; ii < p.defaultValue->values.count(); ++ii) {
2418 QDeclarativeParser::Value *v = p.defaultValue->values.at(ii);
2420 property->values.append(v);
2426 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2428 bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, DynamicMetaMode mode)
2431 Q_ASSERT(obj->metatype);
2433 if (mode != ForceCreation &&
2434 obj->dynamicProperties.isEmpty() &&
2435 obj->dynamicSignals.isEmpty() &&
2436 obj->dynamicSlots.isEmpty())
2439 QByteArray dynamicData(sizeof(QDeclarativeVMEMetaData), (char)0);
2441 QByteArray newClassName = obj->metatype->className();
2442 newClassName.append("_QML_");
2443 int idx = classIndexCounter()->fetchAndAddRelaxed(1);
2444 newClassName.append(QByteArray::number(idx));
2445 if (compileState.root == obj && !compileState.nested) {
2446 QString path = output->url.path();
2447 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2448 if (lastSlash > -1) {
2449 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2450 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2451 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(idx);
2455 QMetaObjectBuilder builder;
2456 builder.setClassName(newClassName);
2457 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
2459 bool hasAlias = false;
2460 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2461 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2463 int propIdx = obj->metaObject()->indexOfProperty(p.name.constData());
2464 if (-1 != propIdx) {
2465 QMetaProperty prop = obj->metaObject()->property(propIdx);
2467 COMPILE_EXCEPTION(&p, tr("Cannot override FINAL property"));
2470 if (p.isDefaultProperty &&
2471 (p.type != Object::DynamicProperty::Alias ||
2472 mode == ResolveAliases))
2473 builder.addClassInfo("DefaultProperty", p.name);
2476 int propertyType = 0;
2477 bool readonly = false;
2479 case Object::DynamicProperty::Alias:
2483 case Object::DynamicProperty::CustomList:
2484 case Object::DynamicProperty::Custom:
2486 QByteArray customTypeName;
2487 QDeclarativeType *qmltype = 0;
2489 if (!unit->imports().resolveType(p.customType, &qmltype, &url, 0, 0, 0))
2490 COMPILE_EXCEPTION(&p, tr("Invalid property type"));
2493 QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(url);
2495 Q_ASSERT(tdata->isComplete());
2497 QDeclarativeCompiledData *data = tdata->compiledData();
2498 customTypeName = data->root->className();
2502 customTypeName = qmltype->typeName();
2505 if (p.type == Object::DynamicProperty::Custom) {
2506 type = customTypeName + '*';
2507 propertyType = QMetaType::QObjectStar;
2510 type = "QDeclarativeListProperty<";
2511 type.append(customTypeName);
2513 propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
2517 case Object::DynamicProperty::Variant:
2521 case Object::DynamicProperty::Int:
2522 propertyType = QVariant::Int;
2525 case Object::DynamicProperty::Bool:
2526 propertyType = QVariant::Bool;
2529 case Object::DynamicProperty::Real:
2530 propertyType = QVariant::Double;
2533 case Object::DynamicProperty::String:
2534 propertyType = QVariant::String;
2537 case Object::DynamicProperty::Url:
2538 propertyType = QVariant::Url;
2541 case Object::DynamicProperty::Color:
2542 propertyType = QVariant::Color;
2545 case Object::DynamicProperty::Time:
2546 propertyType = QVariant::Time;
2549 case Object::DynamicProperty::Date:
2550 propertyType = QVariant::Date;
2553 case Object::DynamicProperty::DateTime:
2554 propertyType = QVariant::DateTime;
2559 ((QDeclarativeVMEMetaData *)dynamicData.data())->propertyCount++;
2560 QDeclarativeVMEMetaData::PropertyData propertyData = { propertyType };
2561 dynamicData.append((char *)&propertyData, sizeof(propertyData));
2563 builder.addSignal(p.name + "Changed()");
2564 QMetaPropertyBuilder propBuilder =
2565 builder.addProperty(p.name, type, builder.methodCount() - 1);
2566 propBuilder.setWritable(!readonly);
2569 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2570 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2572 if (p.type == Object::DynamicProperty::Alias) {
2573 if (mode == ResolveAliases) {
2574 ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++;
2575 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, p));
2577 // Need a fake signal so that the metaobject remains consistent across
2578 // the resolve and non-resolve alias runs
2579 builder.addSignal(p.name + "Changed()");
2584 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2585 const Object::DynamicSignal &s = obj->dynamicSignals.at(ii);
2586 QByteArray sig(s.name + '(');
2587 for (int jj = 0; jj < s.parameterTypes.count(); ++jj) {
2588 if (jj) sig.append(',');
2589 sig.append(s.parameterTypes.at(jj));
2592 QMetaMethodBuilder b = builder.addSignal(sig);
2593 b.setParameterNames(s.parameterNames);
2594 ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++;
2597 QStringList funcScripts;
2599 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2600 Object::DynamicSlot &s = obj->dynamicSlots[ii];
2601 QByteArray sig(s.name + '(');
2602 QString funcScript(QLatin1String("(function ") + s.name + QLatin1Char('('));
2604 for (int jj = 0; jj < s.parameterNames.count(); ++jj) {
2607 funcScript.append(QLatin1Char(','));
2609 funcScript.append(QLatin1String(s.parameterNames.at(jj)));
2610 sig.append("QVariant");
2613 funcScript.append(QLatin1Char(')'));
2614 funcScript.append(s.body);
2615 funcScript.append(QLatin1Char(')'));
2616 funcScripts << funcScript;
2618 QMetaMethodBuilder b = builder.addSlot(sig);
2619 b.setReturnType("QVariant");
2620 b.setParameterNames(s.parameterNames);
2622 ((QDeclarativeVMEMetaData *)dynamicData.data())->methodCount++;
2623 QDeclarativeVMEMetaData::MethodData methodData =
2624 { s.parameterNames.count(), 0, funcScript.length(), s.location.start.line };
2626 dynamicData.append((char *)&methodData, sizeof(methodData));
2629 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2630 const QString &funcScript = funcScripts.at(ii);
2631 QDeclarativeVMEMetaData::MethodData *data =
2632 ((QDeclarativeVMEMetaData *)dynamicData.data())->methodData() + ii;
2634 data->bodyOffset = dynamicData.size();
2636 dynamicData.append((const char *)funcScript.constData(),
2637 (funcScript.length() * sizeof(QChar)));
2640 obj->metadata = builder.toRelocatableData();
2641 builder.fromRelocatableData(&obj->extObject, obj->metatype, obj->metadata);
2643 if (mode == IgnoreAliases && hasAlias)
2644 compileState.aliasingObjects << obj;
2646 obj->synthdata = dynamicData;
2648 if (obj->synthCache) {
2649 obj->synthCache->release();
2650 obj->synthCache = 0;
2653 if (obj->type != -1) {
2654 QDeclarativePropertyCache *cache = output->types[obj->type].createPropertyCache(engine)->copy();
2655 cache->append(engine, &obj->extObject, QDeclarativePropertyCache::Data::NoFlags,
2656 QDeclarativePropertyCache::Data::IsVMEFunction,
2657 QDeclarativePropertyCache::Data::IsVMESignal);
2658 obj->synthCache = cache;
2664 bool QDeclarativeCompiler::checkValidId(QDeclarativeParser::Value *v, const QString &val)
2667 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
2669 if (val.at(0).isLetter() && !val.at(0).isLower())
2670 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
2672 QChar u(QLatin1Char('_'));
2673 for (int ii = 0; ii < val.count(); ++ii) {
2675 if (ii == 0 && !val.at(ii).isLetter() && val.at(ii) != u) {
2676 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
2677 } else if (ii != 0 && !val.at(ii).isLetterOrNumber() && val.at(ii) != u) {
2678 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
2683 if (enginePrivate->v8engine.illegalNames().contains(val))
2684 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
2689 #include <qdeclarativejsparser_p.h>
2691 static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node)
2693 if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) {
2695 static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name->asString();
2696 return QStringList() << name;
2697 } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) {
2698 QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node);
2700 QStringList rv = astNodeToStringList(expr->base);
2703 rv.append(expr->name->asString());
2706 return QStringList();
2709 bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder,
2711 QDeclarativeParser::Object *obj,
2712 const Object::DynamicProperty &prop)
2714 if (!prop.defaultValue)
2715 COMPILE_EXCEPTION(obj, tr("No property alias location"));
2717 if (prop.defaultValue->values.count() != 1 ||
2718 prop.defaultValue->values.at(0)->object ||
2719 !prop.defaultValue->values.at(0)->value.isScript())
2720 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2722 QDeclarativeJS::AST::Node *node = prop.defaultValue->values.at(0)->value.asAST();
2724 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
2726 QStringList alias = astNodeToStringList(node);
2728 if (alias.count() < 1 || alias.count() > 3)
2729 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
2731 if (!compileState.ids.contains(alias.at(0)))
2732 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
2734 QDeclarativeParser::Object *idObject = compileState.ids[alias.at(0)];
2736 QByteArray typeName;
2740 bool writable = false;
2741 if (alias.count() == 2 || alias.count() == 3) {
2742 propIdx = indexOfProperty(idObject, alias.at(1).toUtf8());
2744 if (-1 == propIdx) {
2745 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2746 } else if (propIdx > 0xFFFF) {
2747 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
2750 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
2751 if (!aliasProperty.isScriptable())
2752 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2754 writable = aliasProperty.isWritable();
2756 if (alias.count() == 3) {
2757 QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
2759 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2761 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
2763 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
2764 if (valueTypeIndex == -1)
2765 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2766 Q_ASSERT(valueTypeIndex <= 0xFF);
2768 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
2769 propIdx |= (valueTypeIndex << 16);
2772 if (aliasProperty.isEnumType())
2773 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
2775 typeName = aliasProperty.typeName();
2777 typeName = idObject->metaObject()->className();
2779 //use the base type since it has been registered with metatype system
2780 int index = typeName.indexOf("_QML_");
2782 typeName = typeName.left(index);
2784 index = typeName.indexOf("_QMLTYPE_");
2785 const QMetaObject *mo = idObject->metaObject();
2786 while (index != -1 && mo) {
2787 typeName = mo->superClass()->className();
2788 index = typeName.indexOf("_QMLTYPE_");
2789 mo = mo->superClass();
2796 if (typeName.endsWith('*'))
2797 flags |= QML_ALIAS_FLAG_PTR;
2799 data.append((const char *)&idObject->idIndex, sizeof(idObject->idIndex));
2800 data.append((const char *)&propIdx, sizeof(propIdx));
2801 data.append((const char *)&flags, sizeof(flags));
2803 builder.addSignal(prop.name + "Changed()");
2804 QMetaPropertyBuilder propBuilder =
2805 builder.addProperty(prop.name, typeName.constData(), builder.methodCount() - 1);
2806 propBuilder.setWritable(writable);
2810 bool QDeclarativeCompiler::buildBinding(QDeclarativeParser::Value *value,
2811 QDeclarativeParser::Property *prop,
2812 const BindingContext &ctxt)
2814 Q_ASSERT(prop->index != -1);
2815 Q_ASSERT(prop->parent);
2816 Q_ASSERT(prop->parent->metaObject());
2818 QMetaProperty mp = prop->parent->metaObject()->property(prop->index);
2819 if (!mp.isWritable() && !QDeclarativeMetaType::isList(prop->type))
2820 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2822 BindingReference reference;
2823 reference.expression = value->value;
2824 reference.property = prop;
2825 reference.value = value;
2826 reference.bindingContext = ctxt;
2827 addBindingReference(reference);
2832 void QDeclarativeCompiler::genBindingAssignment(QDeclarativeParser::Value *binding,
2833 QDeclarativeParser::Property *prop,
2834 QDeclarativeParser::Object *obj,
2835 QDeclarativeParser::Property *valueTypeProperty)
2838 Q_ASSERT(compileState.bindings.contains(binding));
2840 const BindingReference &ref = compileState.bindings.value(binding);
2841 if (ref.dataType == BindingReference::V4) {
2842 QDeclarativeInstruction store;
2843 store.setType(QDeclarativeInstruction::StoreV4Binding);
2844 store.assignBinding.value = ref.compiledIndex;
2845 store.assignBinding.context = ref.bindingContext.stack;
2846 store.assignBinding.owner = ref.bindingContext.owner;
2847 if (valueTypeProperty)
2848 store.assignBinding.property = (valueTypeProperty->index & 0xFFFF) |
2849 ((valueTypeProperty->type & 0xFF)) << 16 |
2850 ((prop->index & 0xFF) << 24);
2852 store.assignBinding.property = prop->index;
2853 store.assignBinding.line = binding->location.start.line;
2854 output->addInstruction(store);
2855 } else if (ref.dataType == BindingReference::V8) {
2856 QDeclarativeInstruction store;
2857 store.setType(QDeclarativeInstruction::StoreV8Binding);
2858 store.assignBinding.value = ref.compiledIndex;
2859 store.assignBinding.context = ref.bindingContext.stack;
2860 store.assignBinding.owner = ref.bindingContext.owner;
2861 store.assignBinding.line = binding->location.start.line;
2863 Q_ASSERT(ref.bindingContext.owner == 0 ||
2864 (ref.bindingContext.owner != 0 && valueTypeProperty));
2865 if (ref.bindingContext.owner) {
2866 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
2868 store.assignBinding.property = genPropertyData(prop);
2871 output->addInstruction(store);
2873 QDeclarativeInstruction store;
2875 store.setType(QDeclarativeInstruction::StoreBinding);
2877 store.setType(QDeclarativeInstruction::StoreBindingOnAlias);
2878 store.assignBinding.value = output->indexForString(ref.rewrittenExpression);
2879 store.assignBinding.context = ref.bindingContext.stack;
2880 store.assignBinding.owner = ref.bindingContext.owner;
2881 store.assignBinding.line = binding->location.start.line;
2883 Q_ASSERT(ref.bindingContext.owner == 0 ||
2884 (ref.bindingContext.owner != 0 && valueTypeProperty));
2885 if (ref.bindingContext.owner) {
2886 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
2888 store.assignBinding.property = genPropertyData(prop);
2890 output->addInstruction(store);
2894 int QDeclarativeCompiler::genContextCache()
2896 if (compileState.ids.count() == 0)
2899 QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache();
2901 for (QHash<QString, QDeclarativeParser::Object *>::ConstIterator iter = compileState.ids.begin();
2902 iter != compileState.ids.end();
2904 cache->add(iter.key(), (*iter)->idIndex);
2906 output->contextCaches.append(cache);
2907 return output->contextCaches.count() - 1;
2910 int QDeclarativeCompiler::genValueTypeData(QDeclarativeParser::Property *valueTypeProp,
2911 QDeclarativeParser::Property *prop)
2913 typedef QDeclarativePropertyPrivate QDPP;
2914 QByteArray data = QDPP::saveValueType(prop->parent->metaObject(), prop->index,
2915 enginePrivate->valueTypes[prop->type]->metaObject(),
2916 valueTypeProp->index, engine);
2918 return output->indexForByteArray(data);
2921 int QDeclarativeCompiler::genPropertyData(QDeclarativeParser::Property *prop)
2923 typedef QDeclarativePropertyPrivate QDPP;
2924 QByteArray data = QDPP::saveProperty(prop->parent->metaObject(), prop->index, engine);
2926 return output->indexForByteArray(data);
2929 bool QDeclarativeCompiler::completeComponentBuild()
2931 componentStat.ids = compileState.ids.count();
2933 for (int ii = 0; ii < compileState.aliasingObjects.count(); ++ii) {
2934 QDeclarativeParser::Object *aliasObject = compileState.aliasingObjects.at(ii);
2935 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
2938 QDeclarativeV4Compiler::Expression expr;
2939 expr.component = compileState.root;
2940 expr.ids = compileState.ids;
2941 expr.importCache = output->importCache;
2942 expr.imports = unit->imports();
2944 QDeclarativeV4Compiler bindingCompiler;
2946 QList<BindingReference*> sharedBindings;
2948 for (QHash<QDeclarativeParser::Value*,BindingReference>::Iterator iter = compileState.bindings.begin();
2949 iter != compileState.bindings.end(); ++iter) {
2951 BindingReference &binding = *iter;
2953 // ### We don't currently optimize for bindings on alias's - because
2954 // of the solution to QTBUG-13719
2955 if (!binding.property->isAlias) {
2956 expr.context = binding.bindingContext.object;
2957 expr.property = binding.property;
2958 expr.expression = binding.expression;
2960 int index = bindingCompiler.compile(expr, enginePrivate);
2962 binding.dataType = BindingReference::V4;
2963 binding.compiledIndex = index;
2964 componentStat.optimizedBindings.append(iter.key()->location);
2969 // Pre-rewrite the expression
2970 QString expression = binding.expression.asScript();
2972 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2973 rewriteBinding.setName('$'+binding.property->name);
2974 bool isSharable = false;
2975 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
2977 if (isSharable && !binding.property->isAlias /* See above re alias */ &&
2978 binding.property->type != qMetaTypeId<QDeclarativeBinding*>()) {
2979 binding.dataType = BindingReference::V8;
2980 sharedBindings.append(&iter.value());
2982 binding.dataType = BindingReference::QtScript;
2985 componentStat.scriptBindings.append(iter.key()->location);
2988 if (!sharedBindings.isEmpty()) {
2990 static bool lt(const BindingReference *lhs, const BindingReference *rhs)
2992 return lhs->value->location.start.line < rhs->value->location.start.line;
2996 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
2998 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
2999 int lineNumber = startLineNumber;
3001 QString functionArray(QLatin1String("["));
3002 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3003 BindingReference *reference = sharedBindings.at(ii);
3004 QDeclarativeParser::Value *value = reference->value;
3005 const QString &expression = reference->rewrittenExpression;
3007 if (ii != 0) functionArray += QLatin1String(",");
3009 while (lineNumber < value->location.start.line) {
3011 functionArray += QLatin1String("\n");
3014 functionArray += expression;
3015 reference->compiledIndex = ii;
3017 functionArray += QLatin1String("]");
3019 compileState.v8BindingProgram = functionArray;
3020 compileState.v8BindingProgramLine = startLineNumber;
3021 compileState.v8BindingProgramIndex = output->v8bindings.count();
3022 output->v8bindings.append(v8::Persistent<v8::Array>());
3025 if (bindingCompiler.isValid())
3026 compileState.compiledBindingData = bindingCompiler.program();
3028 saveComponentState();
3033 void QDeclarativeCompiler::dumpStats()
3035 qWarning().nospace() << "QML Document: " << output->url.toString();
3036 for (int ii = 0; ii < savedComponentStats.count(); ++ii) {
3037 const ComponentStat &stat = savedComponentStats.at(ii);
3038 qWarning().nospace() << " Component Line " << stat.lineNumber;
3039 qWarning().nospace() << " Total Objects: " << stat.objects;
3040 qWarning().nospace() << " IDs Used: " << stat.ids;
3041 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3045 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3046 if (0 == (ii % 10)) {
3047 if (ii) output.append("\n");
3052 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3054 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3055 output.append(") ");
3057 if (!output.isEmpty())
3058 qWarning().nospace() << output.constData();
3061 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3064 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3065 if (0 == (ii % 10)) {
3066 if (ii) output.append("\n");
3071 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3073 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3074 output.append(") ");
3076 if (!output.isEmpty())
3077 qWarning().nospace() << output.constData();
3083 Returns true if from can be assigned to a (QObject) property of type
3086 bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeParser::Object *from)
3088 const QMetaObject *toMo =
3089 enginePrivate->rawMetaObjectForType(to);
3090 const QMetaObject *fromMo = from->metaObject();
3093 if (QDeclarativePropertyPrivate::equal(fromMo, toMo))
3095 fromMo = fromMo->superClass();
3100 QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeParser::Object *from)
3103 const QMetaObject *mo = from->metatype;
3104 QDeclarativeType *type = 0;
3105 while (!type && mo) {
3106 type = QDeclarativeMetaType::qmlType(mo);
3107 mo = mo->superClass();
3112 QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeParser::Object *obj)
3114 const QMetaObject *mo = obj->metatype;
3116 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3118 return QStringList();
3120 QMetaClassInfo classInfo = mo->classInfo(idx);
3121 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3125 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3126 int QDeclarativeCompiler::indexOfSignal(QDeclarativeParser::Object *object, const QByteArray &name,
3127 bool *notInRevision)
3129 if (notInRevision) *notInRevision = false;
3131 if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) {
3133 QString strName(QString::fromUtf8(name));
3134 QDeclarativePropertyCache *cache =
3135 object->synthCache?object->synthCache:output->types.at(object->type).propertyCache();
3137 QDeclarativePropertyCache::Data *d = cache->property(strName);
3138 if (notInRevision) *notInRevision = false;
3140 while (d && !(d->isFunction()))
3141 d = cache->overrideData(d);
3143 if (d && !cache->isAllowedInRevision(d)) {
3144 if (notInRevision) *notInRevision = true;
3147 return d->coreIndex;
3150 if (name.endsWith("Changed")) {
3151 QByteArray propName = name.mid(0, name.length() - 7);
3153 int propIndex = indexOfProperty(object, propName, notInRevision);
3154 if (propIndex != -1) {
3155 d = cache->property(propIndex);
3156 return d->notifyIndex;
3162 return QDeclarativePropertyPrivate::findSignalByName(object->metaObject(), name).methodIndex();
3167 int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QByteArray &name,
3168 bool *notInRevision)
3170 if (notInRevision) *notInRevision = false;
3172 if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) {
3174 QString strName(QString::fromUtf8(name));
3175 QDeclarativePropertyCache *cache =
3176 object->synthCache?object->synthCache:output->types.at(object->type).propertyCache();
3178 QDeclarativePropertyCache::Data *d = cache->property(strName);
3179 // Find the first property
3180 while (d && d->isFunction())
3181 d = cache->overrideData(d);
3183 if (d && !cache->isAllowedInRevision(d)) {
3184 if (notInRevision) *notInRevision = true;
3187 return d?d->coreIndex:-1;
3190 const QMetaObject *mo = object->metaObject();
3191 return mo->indexOfProperty(name.constData());