1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "private/qdeclarativecompiler_p.h"
44 #include "private/qdeclarativeparser_p.h"
45 #include "private/qdeclarativescriptparser_p.h"
46 #include "qdeclarativepropertyvaluesource.h"
47 #include "qdeclarativecomponent.h"
48 #include "private/qmetaobjectbuilder_p.h"
49 #include "private/qdeclarativestringconverters_p.h"
50 #include "private/qdeclarativeengine_p.h"
51 #include "qdeclarativeengine.h"
52 #include "qdeclarativecontext.h"
53 #include "private/qdeclarativemetatype_p.h"
54 #include "private/qdeclarativecustomparser_p_p.h"
55 #include "private/qdeclarativecontext_p.h"
56 #include "private/qdeclarativecomponent_p.h"
57 #include "parser/qdeclarativejsast_p.h"
58 #include "private/qdeclarativevmemetaobject_p.h"
59 #include "private/qdeclarativeexpression_p.h"
60 #include "private/qdeclarativeproperty_p.h"
61 #include "private/qdeclarativerewrite_p.h"
62 #include "qdeclarativescriptstring.h"
63 #include "private/qdeclarativeglobal_p.h"
64 #include "private/qdeclarativescriptparser_p.h"
65 #include "private/qdeclarativebinding_p.h"
66 #include "private/qdeclarativev4compiler_p.h"
74 #include <QtCore/qdebug.h>
75 #include <QtCore/qdatetime.h>
79 DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP);
80 DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS);
82 using namespace QDeclarativeParser;
85 Instantiate a new QDeclarativeCompiler.
87 QDeclarativeCompiler::QDeclarativeCompiler()
88 : output(0), engine(0), unitRoot(0), unit(0)
93 Returns true if the last call to compile() caused errors.
97 bool QDeclarativeCompiler::isError() const
99 return !exceptions.isEmpty();
103 Return the list of errors from the last call to compile(), or an empty list
104 if there were no errors.
106 QList<QDeclarativeError> QDeclarativeCompiler::errors() const
112 Returns true if \a name refers to an attached property, false otherwise.
114 Attached property names are those that start with a capital letter.
116 bool QDeclarativeCompiler::isAttachedPropertyName(const QByteArray &name)
118 return !name.isEmpty() && name.at(0) >= 'A' && name.at(0) <= 'Z';
122 Returns true if \a name refers to a signal property, false otherwise.
124 Signal property names are those that start with "on", followed by a first
125 character which is either a capital letter or one or more underscores followed
126 by a capital letter, which is then followed by other allowed characters.
128 Note that although ECMA-262r3 supports dollarsigns and escaped unicode
129 character codes in property names, for simplicity and performance reasons
130 QML only supports letters, numbers and underscores.
132 bool QDeclarativeCompiler::isSignalPropertyName(const QByteArray &name)
134 if (name.length() < 3) return false;
135 if (!name.startsWith("on")) return false;
136 int ns = name.size();
137 for (int i = 2; i < ns; ++i) {
138 char curr = name.at(i);
139 if (curr == '_') continue;
140 if (curr >= 'A' && curr <= 'Z') return true;
143 return false; // consists solely of underscores - invalid.
147 \macro COMPILE_EXCEPTION
149 Inserts an error into the QDeclarativeCompiler error list, and returns false
152 \a token is used to source the error line and column, and \a desc is the
153 error itself. \a desc can be an expression that can be piped into QDebug.
158 COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(QString::fromUtf8(property->name)));
161 #define COMPILE_EXCEPTION(token, desc) \
163 QString exceptionDescription; \
164 QDeclarativeError error; \
165 error.setUrl(output->url); \
166 error.setLine((token)->location.start.line); \
167 error.setColumn((token)->location.start.column); \
168 error.setDescription(desc.trimmed()); \
169 exceptions << error; \
176 Returns false if \a is false, otherwise does nothing.
178 #define COMPILE_CHECK(a) \
180 if (!a) return false; \
184 Returns true if literal \a v can be assigned to property \a prop, otherwise
187 This test corresponds to action taken by genLiteralAssignment(). Any change
188 made here, must have a corresponding action in genLiteralAssigment().
190 bool QDeclarativeCompiler::testLiteralAssignment(const QMetaProperty &prop,
191 QDeclarativeParser::Value *v)
193 QString string = v->value.asString();
195 if (!prop.isWritable())
196 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
198 if (prop.isEnumType()) {
200 if (prop.isFlagType()) {
201 value = prop.enumerator().keysToValue(string.toUtf8().constData());
203 value = prop.enumerator().keyToValue(string.toUtf8().constData());
205 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration"));
208 int type = prop.userType();
212 case QVariant::String:
213 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
215 case QVariant::ByteArray:
216 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected"));
219 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected"));
223 bool ok = v->value.isNumber();
225 double n = v->value.asNumber();
226 if (double(uint(n)) != n)
229 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected"));
234 bool ok = v->value.isNumber();
236 double n = v->value.asNumber();
237 if (double(int(n)) != n)
240 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected"));
243 case QMetaType::Float:
244 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
246 case QVariant::Double:
247 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
249 case QVariant::Color:
252 QDeclarativeStringConverters::colorFromString(string, &ok);
253 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected"));
256 #ifndef QT_NO_DATESTRING
260 QDeclarativeStringConverters::dateFromString(string, &ok);
261 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected"));
267 QDeclarativeStringConverters::timeFromString(string, &ok);
268 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected"));
271 case QVariant::DateTime:
274 QDeclarativeStringConverters::dateTimeFromString(string, &ok);
275 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected"));
278 #endif // QT_NO_DATESTRING
279 case QVariant::Point:
280 case QVariant::PointF:
283 QPointF point = QDeclarativeStringConverters::pointFFromString(string, &ok);
284 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected"));
288 case QVariant::SizeF:
291 QSizeF size = QDeclarativeStringConverters::sizeFFromString(string, &ok);
292 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected"));
296 case QVariant::RectF:
299 QRectF rect = QDeclarativeStringConverters::rectFFromString(string, &ok);
300 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected"));
305 if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected"));
308 case QVariant::Vector3D:
311 QDeclarativeStringConverters::vector3DFromString(string, &ok);
312 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected"));
317 int t = prop.userType();
318 QDeclarativeMetaType::StringConverter converter =
319 QDeclarativeMetaType::customStringConverter(t);
321 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName(prop.type()))));
329 Generate a store instruction for assigning literal \a v to property \a prop.
331 Any literal assignment that is approved in testLiteralAssignment() must have
332 a corresponding action in this method.
334 void QDeclarativeCompiler::genLiteralAssignment(const QMetaProperty &prop,
335 QDeclarativeParser::Value *v)
337 QDeclarativeInstruction instr;
338 if (prop.isEnumType()) {
340 if (v->value.isNumber()) {
342 value = (int)v->value.asNumber();
345 if (prop.isFlagType()) {
346 value = prop.enumerator().keysToValue(v->value.asString().toUtf8().constData());
348 value = prop.enumerator().keyToValue(v->value.asString().toUtf8().constData());
351 instr.setType(QDeclarativeInstruction::StoreInteger);
352 instr.storeInteger.propertyIndex = prop.propertyIndex();
353 instr.storeInteger.value = value;
354 output->addInstruction(instr);
358 QString string = v->value.asString();
360 int type = prop.userType();
364 if (v->value.isNumber()) {
365 double n = v->value.asNumber();
366 if (double(int(n)) == n) {
367 instr.setType(QDeclarativeInstruction::StoreVariantInteger);
368 instr.storeInteger.propertyIndex = prop.propertyIndex();
369 instr.storeInteger.value = int(n);
371 instr.setType(QDeclarativeInstruction::StoreVariantDouble);
372 instr.storeDouble.propertyIndex = prop.propertyIndex();
373 instr.storeDouble.value = n;
375 } else if(v->value.isBoolean()) {
376 instr.setType(QDeclarativeInstruction::StoreVariantBool);
377 instr.storeBool.propertyIndex = prop.propertyIndex();
378 instr.storeBool.value = v->value.asBoolean();
380 instr.setType(QDeclarativeInstruction::StoreVariant);
381 instr.storeString.propertyIndex = prop.propertyIndex();
382 instr.storeString.value = output->indexForString(string);
386 case QVariant::String:
388 instr.setType(QDeclarativeInstruction::StoreString);
389 instr.storeString.propertyIndex = prop.propertyIndex();
390 instr.storeString.value = output->indexForString(string);
393 case QVariant::ByteArray:
395 instr.setType(QDeclarativeInstruction::StoreByteArray);
396 instr.storeByteArray.propertyIndex = prop.propertyIndex();
397 instr.storeByteArray.value = output->indexForByteArray(string.toLatin1());
402 instr.setType(QDeclarativeInstruction::StoreUrl);
403 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
404 instr.storeUrl.propertyIndex = prop.propertyIndex();
405 instr.storeUrl.value = output->indexForUrl(u);
410 instr.setType(QDeclarativeInstruction::StoreInteger);
411 instr.storeInteger.propertyIndex = prop.propertyIndex();
412 instr.storeInteger.value = uint(v->value.asNumber());
417 instr.setType(QDeclarativeInstruction::StoreInteger);
418 instr.storeInteger.propertyIndex = prop.propertyIndex();
419 instr.storeInteger.value = int(v->value.asNumber());
422 case QMetaType::Float:
424 instr.setType(QDeclarativeInstruction::StoreFloat);
425 instr.storeFloat.propertyIndex = prop.propertyIndex();
426 instr.storeFloat.value = float(v->value.asNumber());
429 case QVariant::Double:
431 instr.setType(QDeclarativeInstruction::StoreDouble);
432 instr.storeDouble.propertyIndex = prop.propertyIndex();
433 instr.storeDouble.value = v->value.asNumber();
436 case QVariant::Color:
438 QColor c = QDeclarativeStringConverters::colorFromString(string);
439 instr.setType(QDeclarativeInstruction::StoreColor);
440 instr.storeColor.propertyIndex = prop.propertyIndex();
441 instr.storeColor.value = c.rgba();
444 #ifndef QT_NO_DATESTRING
447 QDate d = QDeclarativeStringConverters::dateFromString(string);
448 instr.setType(QDeclarativeInstruction::StoreDate);
449 instr.storeDate.propertyIndex = prop.propertyIndex();
450 instr.storeDate.value = d.toJulianDay();
455 QTime time = QDeclarativeStringConverters::timeFromString(string);
456 instr.setType(QDeclarativeInstruction::StoreTime);
457 instr.storeTime.propertyIndex = prop.propertyIndex();
458 Q_ASSERT(sizeof(instr.storeTime.time) == sizeof(QTime));
459 ::memcpy(&instr.storeTime.time, &time, sizeof(QTime));
462 case QVariant::DateTime:
464 QDateTime dateTime = QDeclarativeStringConverters::dateTimeFromString(string);
465 QTime time = dateTime.time();
466 instr.setType(QDeclarativeInstruction::StoreDateTime);
467 instr.storeDateTime.propertyIndex = prop.propertyIndex();
468 instr.storeDateTime.date = dateTime.date().toJulianDay();
469 Q_ASSERT(sizeof(instr.storeDateTime.time) == sizeof(QTime));
470 ::memcmp(&instr.storeDateTime.time, &time, sizeof(QTime));
473 #endif // QT_NO_DATESTRING
474 case QVariant::Point:
477 QPoint point = QDeclarativeStringConverters::pointFFromString(string, &ok).toPoint();
478 instr.setType(QDeclarativeInstruction::StorePoint);
479 instr.storePoint.propertyIndex = prop.propertyIndex();
480 instr.storePoint.point.xp = point.x();
481 instr.storePoint.point.yp = point.y();
484 case QVariant::PointF:
487 QPointF point = QDeclarativeStringConverters::pointFFromString(string, &ok);
488 instr.setType(QDeclarativeInstruction::StorePointF);
489 instr.storePointF.propertyIndex = prop.propertyIndex();
490 instr.storePointF.point.xp = point.x();
491 instr.storePointF.point.yp = point.y();
497 QSize size = QDeclarativeStringConverters::sizeFFromString(string, &ok).toSize();
498 instr.setType(QDeclarativeInstruction::StoreSize);
499 instr.storeSize.propertyIndex = prop.propertyIndex();
500 instr.storeSize.size.wd = size.width();
501 instr.storeSize.size.ht = size.height();
504 case QVariant::SizeF:
507 QSizeF size = QDeclarativeStringConverters::sizeFFromString(string, &ok);
508 instr.setType(QDeclarativeInstruction::StoreSizeF);
509 instr.storeSizeF.propertyIndex = prop.propertyIndex();
510 instr.storeSizeF.size.wd = size.width();
511 instr.storeSizeF.size.ht = size.height();
517 QRect rect = QDeclarativeStringConverters::rectFFromString(string, &ok).toRect();
518 instr.setType(QDeclarativeInstruction::StoreRect);
519 instr.storeRect.propertyIndex = prop.propertyIndex();
520 instr.storeRect.rect.x1 = rect.left();
521 instr.storeRect.rect.y1 = rect.top();
522 instr.storeRect.rect.x2 = rect.right();
523 instr.storeRect.rect.y2 = rect.bottom();
526 case QVariant::RectF:
529 QRectF rect = QDeclarativeStringConverters::rectFFromString(string, &ok);
530 instr.setType(QDeclarativeInstruction::StoreRectF);
531 instr.storeRectF.propertyIndex = prop.propertyIndex();
532 instr.storeRectF.rect.xp = rect.left();
533 instr.storeRectF.rect.yp = rect.top();
534 instr.storeRectF.rect.w = rect.width();
535 instr.storeRectF.rect.h = rect.height();
540 bool b = v->value.asBoolean();
541 instr.setType(QDeclarativeInstruction::StoreBool);
542 instr.storeBool.propertyIndex = prop.propertyIndex();
543 instr.storeBool.value = b;
546 case QVariant::Vector3D:
549 QVector3D vector = QDeclarativeStringConverters::vector3DFromString(string, &ok);
550 instr.setType(QDeclarativeInstruction::StoreVector3D);
551 instr.storeVector3D.propertyIndex = prop.propertyIndex();
552 instr.storeVector3D.vector.xp = vector.x();
553 instr.storeVector3D.vector.yp = vector.y();
554 instr.storeVector3D.vector.zp = vector.z();
559 int t = prop.userType();
560 instr.setType(QDeclarativeInstruction::AssignCustomType);
561 instr.assignCustomType.propertyIndex = prop.propertyIndex();
562 instr.assignCustomType.primitive = output->indexForString(string);
563 instr.assignCustomType.type = t;
567 output->addInstruction(instr);
571 Resets data by clearing the lists that the QDeclarativeCompiler modifies.
573 void QDeclarativeCompiler::reset(QDeclarativeCompiledData *data)
576 data->primitives.clear();
578 data->bytecode.clear();
582 Compile \a unit, and store the output in \a out. \a engine is the QDeclarativeEngine
583 with which the QDeclarativeCompiledData will be associated.
585 Returns true on success, false on failure. On failure, the compile errors
586 are available from errors().
588 If the environment variant QML_COMPILER_DUMP is set
589 (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
590 on a successful compiler.
592 bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine,
593 QDeclarativeTypeData *unit,
594 QDeclarativeCompiledData *out)
604 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
605 QList<QDeclarativeScriptParser::TypeReference *> referencedTypes = unit->parser().referencedTypes();
607 for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
608 QDeclarativeCompiledData::TypeReference ref;
610 const QDeclarativeTypeData::TypeReference &tref = resolvedTypes.at(ii);
611 QDeclarativeScriptParser::TypeReference *parserRef = referencedTypes.at(ii);
614 ref.type = tref.type;
615 if (!ref.type->isCreatable()) {
616 QString err = ref.type->noCreationReason();
618 err = tr( "Element is not creatable.");
619 COMPILE_EXCEPTION(parserRef->refObjects.first(), err);
622 if (ref.type->containsRevisionedAttributes()) {
623 QDeclarativeError cacheError;
624 ref.typePropertyCache =
625 QDeclarativeEnginePrivate::get(engine)->cache(ref.type, resolvedTypes.at(ii).minorVersion, cacheError);
627 if (!ref.typePropertyCache) {
628 COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description());
630 ref.typePropertyCache->addref();
633 } else if (tref.typeData) {
634 ref.component = tref.typeData->compiledData();
636 ref.className = parserRef->name.toUtf8();
640 QDeclarativeParser::Object *root = unit->parser().tree();
643 this->engine = engine;
644 this->enginePrivate = QDeclarativeEnginePrivate::get(engine);
646 this->unitRoot = root;
651 out->dumpInstructions();
652 if (compilerStatDump())
654 Q_ASSERT(out->rootPropertyCache);
659 compileState = ComponentCompileState();
660 savedCompileStates.clear();
663 this->enginePrivate = 0;
670 void QDeclarativeCompiler::compileTree(QDeclarativeParser::Object *tree)
672 compileState.root = tree;
673 componentStat.lineNumber = tree->location.start.line;
675 // Build global import scripts
676 QStringList importedScriptIndexes;
678 foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
679 importedScriptIndexes.append(script.qualifier);
681 QDeclarativeInstruction import;
682 import.setType(QDeclarativeInstruction::StoreImportedScript);
683 import.storeScript.value = output->scripts.count();
685 QDeclarativeScriptData *scriptData = script.script->scriptData();
686 scriptData->addref();
687 output->scripts << scriptData;
688 output->addInstruction(import);
691 // We generate the importCache before we build the tree so that
692 // it can be used in the binding compiler. Given we "expect" the
693 // QML compilation to succeed, this isn't a waste.
694 output->importCache = new QDeclarativeTypeNameCache(engine);
695 for (int ii = 0; ii < importedScriptIndexes.count(); ++ii)
696 output->importCache->add(importedScriptIndexes.at(ii), ii);
697 unit->imports().populateCache(output->importCache, engine);
699 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
702 QDeclarativeInstruction init;
703 init.setType(QDeclarativeInstruction::Init);
704 init.init.bindingsSize = compileState.bindings.count();
705 init.init.parserStatusSize = compileState.parserStatusCount;
706 init.init.contextCache = genContextCache();
707 if (compileState.compiledBindingData.isEmpty())
708 init.init.compiledBinding = -1;
710 init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData);
711 output->addInstruction(init);
713 if (!compileState.v8BindingProgram.isEmpty()) {
714 QDeclarativeInstruction bindings;
715 bindings.setType(QDeclarativeInstruction::InitV8Bindings);
716 bindings.initV8Bindings.program = output->indexForString(compileState.v8BindingProgram);
717 bindings.initV8Bindings.programIndex = compileState.v8BindingProgramIndex;
718 bindings.initV8Bindings.line = compileState.v8BindingProgramLine;
719 output->addInstruction(bindings);
724 QDeclarativeInstruction def;
725 def.setType(QDeclarativeInstruction::SetDefault);
726 output->addInstruction(def);
728 QDeclarativeInstruction done;
729 done.setType(QDeclarativeInstruction::Done);
730 output->addInstruction(done);
732 Q_ASSERT(tree->metatype);
734 if (tree->metadata.isEmpty()) {
735 output->root = tree->metatype;
737 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
738 output->root = &output->rootData;
740 if (!tree->metadata.isEmpty())
741 enginePrivate->registerCompositeType(output);
744 static bool ValuePtrLessThan(const QDeclarativeParser::Value *t1, const QDeclarativeParser::Value *t2)
746 return t1->location.start.line < t2->location.start.line ||
747 (t1->location.start.line == t2->location.start.line &&
748 t1->location.start.column < t2->location.start.column);
751 bool QDeclarativeCompiler::buildObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
753 componentStat.objects++;
755 Q_ASSERT (obj->type != -1);
756 const QDeclarativeCompiledData::TypeReference &tr =
757 output->types.at(obj->type);
758 obj->metatype = tr.metaObject();
761 obj->typeName = tr.type->qmlTypeName();
762 obj->className = tr.className;
764 // This object is a "Component" element
765 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
766 COMPILE_CHECK(buildComponent(obj, ctxt));
770 // Object instantiations reset the binding context
771 BindingContext objCtxt(obj);
773 // Create the synthesized meta object, ignoring aliases
774 COMPILE_CHECK(checkDynamicMeta(obj));
775 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
776 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
778 // Find the native type and check for the QDeclarativeParserStatus interface
779 QDeclarativeType *type = toQmlType(obj);
781 obj->parserStatusCast = type->parserStatusCast();
782 if (obj->parserStatusCast != -1)
783 compileState.parserStatusCount++;
785 // Check if this is a custom parser type. Custom parser types allow
786 // assignments to non-existent properties. These assignments are then
787 // compiled by the type.
788 bool isCustomParser = output->types.at(obj->type).type &&
789 output->types.at(obj->type).type->customParser() != 0;
790 QList<QDeclarativeCustomParserProperty> customProps;
792 // Fetch the list of deferred properties
793 QStringList deferredList = deferredProperties(obj);
795 // Must do id property first. This is to ensure that the id given to any
796 // id reference created matches the order in which the objects are
798 foreach(Property *prop, obj->properties) {
799 if (prop->name == "id") {
800 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
806 Property *defaultProperty = 0;
807 Property *skipProperty = 0;
808 if (obj->defaultProperty) {
809 const QMetaObject *metaObject = obj->metaObject();
810 Q_ASSERT(metaObject);
811 QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
813 Property *explicitProperty = obj->getProperty(p.name(), false);
814 if (explicitProperty && !explicitProperty->value) {
815 skipProperty = explicitProperty;
817 defaultProperty = new Property;
818 defaultProperty->parent = obj;
819 defaultProperty->isDefault = true;
820 defaultProperty->location = obj->defaultProperty->location;
821 defaultProperty->listValueRange = obj->defaultProperty->listValueRange;
823 defaultProperty->values = obj->defaultProperty->values;
824 defaultProperty->values += explicitProperty->values;
825 foreach(QDeclarativeParser::Value *value, defaultProperty->values)
827 qSort(defaultProperty->values.begin(), defaultProperty->values.end(), ValuePtrLessThan);
830 defaultProperty = obj->defaultProperty;
831 defaultProperty->addref();
834 defaultProperty = obj->defaultProperty;
835 defaultProperty->addref();
839 QDeclarativeCustomParser *cp = 0;
841 cp = output->types.at(obj->type).type->customParser();
843 // Build all explicit properties specified
844 foreach(Property *prop, obj->properties) {
846 if (prop == skipProperty)
848 if (prop->name == "id")
851 bool canDefer = false;
852 if (isCustomParser) {
853 if (doesPropertyExist(prop, obj) &&
854 (!(cp->flags() & QDeclarativeCustomParser::AcceptsAttachedProperties) ||
855 !isAttachedPropertyName(prop->name))) {
856 int ids = compileState.ids.count();
857 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
858 canDefer = ids == compileState.ids.count();
859 } else if (isSignalPropertyName(prop->name) &&
860 (cp->flags() & QDeclarativeCustomParser::AcceptsSignalHandlers)) {
861 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
863 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
866 if (isSignalPropertyName(prop->name)) {
867 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
869 int ids = compileState.ids.count();
870 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
871 canDefer = ids == compileState.ids.count();
875 if (canDefer && !deferredList.isEmpty() &&
876 deferredList.contains(QString::fromUtf8(prop->name)))
877 prop->isDeferred = true;
881 // Build the default property
882 if (defaultProperty) {
883 Property *prop = defaultProperty;
885 bool canDefer = false;
886 if (isCustomParser) {
887 if (doesPropertyExist(prop, obj)) {
888 int ids = compileState.ids.count();
889 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
890 canDefer = ids == compileState.ids.count();
892 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
895 int ids = compileState.ids.count();
896 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
897 canDefer = ids == compileState.ids.count();
900 if (canDefer && !deferredList.isEmpty() &&
901 deferredList.contains(QString::fromUtf8(prop->name)))
902 prop->isDeferred = true;
906 defaultProperty->release();
908 // Compile custom parser parts
909 if (isCustomParser && !customProps.isEmpty()) {
913 obj->custom = cp->compile(customProps);
916 foreach (QDeclarativeError err, cp->errors()) {
917 err.setUrl(output->url);
925 void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj)
927 QDeclarativeCompiledData::TypeReference &tr = output->types[obj->type];
928 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
934 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
935 !output->types.at(obj->type).type->isExtendedType() && obj != compileState.root) {
937 QDeclarativeInstruction create;
938 create.setType(QDeclarativeInstruction::CreateSimpleObject);
939 create.createSimple.create = output->types.at(obj->type).type->createFunction();
940 create.createSimple.typeSize = output->types.at(obj->type).type->createSize();
941 create.createSimple.type = obj->type;
942 create.createSimple.line = obj->location.start.line;
943 create.createSimple.column = obj->location.start.column;
944 output->addInstruction(create);
948 QDeclarativeInstruction create;
949 create.setType(QDeclarativeInstruction::CreateObject);
950 create.create.line = obj->location.start.line;
951 create.create.column = obj->location.start.column;
952 create.create.data = -1;
953 if (!obj->custom.isEmpty())
954 create.create.data = output->indexForByteArray(obj->custom);
955 create.create.type = obj->type;
956 if (!output->types.at(create.create.type).type &&
957 !obj->bindingBitmask.isEmpty()) {
958 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
959 create.create.bindingBits =
960 output->indexForByteArray(obj->bindingBitmask);
962 create.create.bindingBits = -1;
964 output->addInstruction(create);
968 // Setup the synthesized meta object if necessary
969 if (!obj->metadata.isEmpty()) {
970 QDeclarativeInstruction meta;
971 meta.setType(QDeclarativeInstruction::StoreMetaObject);
972 meta.storeMeta.data = output->indexForByteArray(obj->metadata);
973 meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata);
974 meta.storeMeta.propertyCache = output->propertyCaches.count();
976 QDeclarativePropertyCache *propertyCache = obj->synthCache;
977 Q_ASSERT(propertyCache);
978 propertyCache->addref();
980 // Add flag for alias properties
981 if (!obj->synthdata.isEmpty()) {
982 const QDeclarativeVMEMetaData *vmeMetaData =
983 reinterpret_cast<const QDeclarativeVMEMetaData *>(obj->synthdata.constData());
984 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
985 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
986 QDeclarativePropertyCache::Data *data = propertyCache->property(index);
987 data->setFlags(data->getFlags() | QDeclarativePropertyCache::Data::IsAlias);
991 if (obj == unitRoot) {
992 propertyCache->addref();
993 output->rootPropertyCache = propertyCache;
996 output->propertyCaches << propertyCache;
997 output->addInstruction(meta);
998 } else if (obj == unitRoot) {
999 output->rootPropertyCache = tr.createPropertyCache(engine);
1000 output->rootPropertyCache->addref();
1003 // Set the object id
1004 if (!obj->id.isEmpty()) {
1005 QDeclarativeInstruction id;
1006 id.setType(QDeclarativeInstruction::SetId);
1007 id.setId.value = output->indexForString(obj->id);
1008 id.setId.index = obj->idIndex;
1009 output->addInstruction(id);
1013 if (tr.type && obj->parserStatusCast != -1) {
1014 QDeclarativeInstruction begin;
1015 begin.setType(QDeclarativeInstruction::BeginObject);
1016 begin.begin.castValue = obj->parserStatusCast;
1017 output->addInstruction(begin);
1023 void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj)
1025 typedef QPair<Property *, int> PropPair;
1026 foreach(const PropPair &prop, obj->scriptStringProperties) {
1027 const QString &script = prop.first->values.at(0)->value.asScript();
1028 QDeclarativeInstruction ss;
1029 ss.setType(QDeclarativeInstruction::StoreScriptString);
1030 ss.storeScriptString.propertyIndex = prop.first->index;
1031 ss.storeScriptString.value = output->indexForString(script);
1032 ss.storeScriptString.scope = prop.second;
1033 ss.storeScriptString.bindingId = rewriteBinding(script, prop.first->name);
1034 ss.storeScriptString.line = prop.first->location.start.line;
1035 output->addInstruction(ss);
1038 bool seenDefer = false;
1039 foreach(Property *prop, obj->valueProperties) {
1040 if (prop->isDeferred) {
1045 genValueProperty(prop, obj);
1048 QDeclarativeInstruction defer;
1049 defer.setType(QDeclarativeInstruction::Defer);
1050 defer.defer.deferCount = 0;
1051 int deferIdx = output->addInstruction(defer);
1052 int nextInstructionIndex = output->nextInstructionIndex();
1054 QDeclarativeInstruction init;
1055 init.setType(QDeclarativeInstruction::Init);
1056 init.init.bindingsSize = compileState.bindings.count(); // XXX - bigger than necessary
1057 init.init.parserStatusSize = compileState.parserStatusCount; // XXX - bigger than necessary
1058 init.init.contextCache = -1;
1059 init.init.compiledBinding = -1;
1060 output->addInstruction(init);
1062 foreach(Property *prop, obj->valueProperties) {
1063 if (!prop->isDeferred)
1065 genValueProperty(prop, obj);
1068 QDeclarativeInstruction done;
1069 done.setType(QDeclarativeInstruction::Done);
1070 output->addInstruction(done);
1072 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1075 foreach(Property *prop, obj->signalProperties) {
1077 QDeclarativeParser::Value *v = prop->values.at(0);
1079 if (v->type == Value::SignalObject) {
1081 genObject(v->object);
1083 QDeclarativeInstruction assign;
1084 assign.setType(QDeclarativeInstruction::AssignSignalObject);
1085 assign.assignSignalObject.line = v->location.start.line;
1086 assign.assignSignalObject.signal =
1087 output->indexForByteArray(prop->name);
1088 output->addInstruction(assign);
1090 } else if (v->type == Value::SignalExpression) {
1092 BindingContext ctxt = compileState.signalExpressions.value(v);
1094 QDeclarativeInstruction store;
1095 store.setType(QDeclarativeInstruction::StoreSignal);
1096 store.storeSignal.signalIndex = prop->index;
1097 store.storeSignal.value =
1098 output->indexForString(v->value.asScript().trimmed());
1099 store.storeSignal.context = ctxt.stack;
1100 store.storeSignal.name = output->indexForByteArray(prop->name);
1101 store.storeSignal.line = v->location.start.line;
1102 output->addInstruction(store);
1108 foreach(Property *prop, obj->attachedProperties) {
1109 QDeclarativeInstruction fetch;
1110 fetch.setType(QDeclarativeInstruction::FetchAttached);
1111 fetch.fetchAttached.id = prop->index;
1112 fetch.fetchAttached.line = prop->location.start.line;
1113 output->addInstruction(fetch);
1115 genObjectBody(prop->value);
1117 QDeclarativeInstruction pop;
1118 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1119 output->addInstruction(pop);
1122 foreach(Property *prop, obj->groupedProperties) {
1123 QDeclarativeInstruction fetch;
1124 fetch.setType(QDeclarativeInstruction::FetchObject);
1125 fetch.fetch.property = prop->index;
1126 fetch.fetch.line = prop->location.start.line;
1127 output->addInstruction(fetch);
1129 if (!prop->value->metadata.isEmpty()) {
1130 QDeclarativeInstruction meta;
1131 meta.setType(QDeclarativeInstruction::StoreMetaObject);
1132 meta.storeMeta.data = output->indexForByteArray(prop->value->metadata);
1133 meta.storeMeta.aliasData = output->indexForByteArray(prop->value->synthdata);
1134 meta.storeMeta.propertyCache = -1;
1135 output->addInstruction(meta);
1138 genObjectBody(prop->value);
1140 QDeclarativeInstruction pop;
1141 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1142 output->addInstruction(pop);
1145 foreach(Property *prop, obj->valueTypeProperties) {
1147 genValueTypeProperty(obj, prop);
1150 foreach(Property *prop, obj->valueProperties) {
1151 if (prop->isDeferred)
1154 genValueProperty(prop, obj);
1157 foreach(Property *prop, obj->valueTypeProperties) {
1159 genValueTypeProperty(obj, prop);
1163 void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeParser::Object *obj,QDeclarativeParser::Property *prop)
1165 QDeclarativeInstruction fetch;
1166 fetch.setType(QDeclarativeInstruction::FetchValueType);
1167 fetch.fetchValue.property = prop->index;
1168 fetch.fetchValue.type = prop->type;
1169 fetch.fetchValue.bindingSkipList = 0;
1171 if (obj->type == -1 || output->types.at(obj->type).component) {
1172 // We only have to do this if this is a composite type. If it is a builtin
1173 // type it can't possibly already have bindings that need to be cleared.
1174 foreach(Property *vprop, prop->value->valueProperties) {
1175 if (!vprop->values.isEmpty()) {
1176 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1177 fetch.fetchValue.bindingSkipList |= (1 << vprop->index);
1182 output->addInstruction(fetch);
1184 foreach(Property *vprop, prop->value->valueProperties) {
1185 genPropertyAssignment(vprop, prop->value, prop);
1188 QDeclarativeInstruction pop;
1189 pop.setType(QDeclarativeInstruction::PopValueType);
1190 pop.fetchValue.property = prop->index;
1191 pop.fetchValue.type = prop->type;
1192 pop.fetchValue.bindingSkipList = 0;
1193 output->addInstruction(pop);
1196 void QDeclarativeCompiler::genComponent(QDeclarativeParser::Object *obj)
1198 QDeclarativeParser::Object *root = obj->defaultProperty->values.at(0)->object;
1201 QDeclarativeInstruction create;
1202 create.setType(QDeclarativeInstruction::CreateComponent);
1203 create.createComponent.line = root->location.start.line;
1204 create.createComponent.column = root->location.start.column;
1205 create.createComponent.endLine = root->location.end.line;
1206 int createInstruction = output->addInstruction(create);
1207 int nextInstructionIndex = output->nextInstructionIndex();
1209 ComponentCompileState oldCompileState = compileState;
1210 compileState = componentState(root);
1212 QDeclarativeInstruction init;
1213 init.setType(QDeclarativeInstruction::Init);
1214 init.init.bindingsSize = compileState.bindings.count();
1215 init.init.parserStatusSize = compileState.parserStatusCount;
1216 init.init.contextCache = genContextCache();
1217 if (compileState.compiledBindingData.isEmpty())
1218 init.init.compiledBinding = -1;
1220 init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData);
1221 output->addInstruction(init);
1223 if (!compileState.v8BindingProgram.isEmpty()) {
1224 QDeclarativeInstruction bindings;
1225 bindings.setType(QDeclarativeInstruction::InitV8Bindings);
1226 bindings.initV8Bindings.program = output->indexForString(compileState.v8BindingProgram);
1227 bindings.initV8Bindings.programIndex = compileState.v8BindingProgramIndex;
1228 bindings.initV8Bindings.line = compileState.v8BindingProgramLine;
1229 output->addInstruction(bindings);
1234 QDeclarativeInstruction def;
1235 def.setType(QDeclarativeInstruction::SetDefault);
1236 output->addInstruction(def);
1238 QDeclarativeInstruction done;
1239 done.setType(QDeclarativeInstruction::Done);
1240 output->addInstruction(done);
1242 output->instruction(createInstruction)->createComponent.count =
1243 output->nextInstructionIndex() - nextInstructionIndex;
1245 compileState = oldCompileState;
1247 if (!obj->id.isEmpty()) {
1248 QDeclarativeInstruction id;
1249 id.setType(QDeclarativeInstruction::SetId);
1250 id.setId.value = output->indexForString(obj->id);
1251 id.setId.index = obj->idIndex;
1252 output->addInstruction(id);
1255 if (obj == unitRoot) {
1256 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1257 output->rootPropertyCache->addref();
1261 bool QDeclarativeCompiler::buildComponent(QDeclarativeParser::Object *obj,
1262 const BindingContext &ctxt)
1264 // The special "Component" element can only have the id property and a
1265 // default property, that actually defines the component's tree
1267 // Find, check and set the "id" property (if any)
1268 Property *idProp = 0;
1269 if (obj->properties.count() > 1 ||
1270 (obj->properties.count() == 1 && obj->properties.begin().key() != "id"))
1271 COMPILE_EXCEPTION(*obj->properties.begin(), tr("Component elements may not contain properties other than id"));
1273 if (obj->properties.count())
1274 idProp = *obj->properties.begin();
1277 if (idProp->value || idProp->values.count() > 1 || idProp->values.at(0)->object)
1278 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1279 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1281 QString idVal = idProp->values.first()->primitive();
1283 if (compileState.ids.contains(idVal))
1284 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1290 // Check the Component tree is well formed
1291 if (obj->defaultProperty &&
1292 (obj->defaultProperty->value || obj->defaultProperty->values.count() > 1 ||
1293 (obj->defaultProperty->values.count() == 1 && !obj->defaultProperty->values.first()->object)))
1294 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1296 if (!obj->dynamicProperties.isEmpty())
1297 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1298 if (!obj->dynamicSignals.isEmpty())
1299 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1300 if (!obj->dynamicSlots.isEmpty())
1301 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1303 QDeclarativeParser::Object *root = 0;
1304 if (obj->defaultProperty && obj->defaultProperty->values.count())
1305 root = obj->defaultProperty->values.first()->object;
1308 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1310 // Build the component tree
1311 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1316 bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeParser::Object *obj,
1317 const BindingContext &ctxt)
1319 ComponentCompileState oldComponentCompileState = compileState;
1320 ComponentStat oldComponentStat = componentStat;
1322 compileState = ComponentCompileState();
1323 compileState.root = obj;
1324 compileState.nested = true;
1326 componentStat = ComponentStat();
1327 componentStat.lineNumber = obj->location.start.line;
1330 COMPILE_CHECK(buildObject(obj, ctxt));
1332 COMPILE_CHECK(completeComponentBuild());
1334 compileState = oldComponentCompileState;
1335 componentStat = oldComponentStat;
1341 // Build a sub-object. A sub-object is one that was not created directly by
1342 // QML - such as a grouped property object, or an attached object. Sub-object's
1343 // can't have an id, involve a custom parser, have attached properties etc.
1344 bool QDeclarativeCompiler::buildSubObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
1346 Q_ASSERT(obj->metatype);
1347 Q_ASSERT(!obj->defaultProperty);
1348 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1351 foreach(Property *prop, obj->properties) {
1352 if (isSignalPropertyName(prop->name)) {
1353 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1355 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1362 int QDeclarativeCompiler::componentTypeRef()
1364 QDeclarativeType *t = QDeclarativeMetaType::qmlType("QtQuick/Component",2,0);
1365 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1366 if (output->types.at(ii).type == t)
1369 QDeclarativeCompiledData::TypeReference ref;
1370 ref.className = "Component";
1372 output->types << ref;
1373 return output->types.count() - 1;
1376 bool QDeclarativeCompiler::buildSignal(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj,
1377 const BindingContext &ctxt)
1379 Q_ASSERT(obj->metaObject());
1381 QByteArray name = prop->name;
1382 Q_ASSERT(name.startsWith("on"));
1385 // Note that the property name could start with any alpha or '_' or '$' character,
1386 // so we need to do the lower-casing of the first alpha character.
1387 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1388 if (name[firstAlphaIndex] >= 'A' && name[firstAlphaIndex] <= 'Z') {
1389 name[firstAlphaIndex] = name[firstAlphaIndex] - 'A' + 'a';
1394 bool notInRevision = false;
1395 int sigIdx = indexOfSignal(obj, name, ¬InRevision);
1399 if (notInRevision && -1 == indexOfProperty(obj, prop->name, 0)) {
1400 Q_ASSERT(obj->type != -1);
1401 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1402 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1404 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));
1406 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)));
1410 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1412 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1416 if (prop->value || prop->values.count() != 1)
1417 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1419 prop->index = sigIdx;
1420 obj->addSignalProperty(prop);
1422 if (prop->values.at(0)->object) {
1423 COMPILE_CHECK(buildObject(prop->values.at(0)->object, ctxt));
1424 prop->values.at(0)->type = Value::SignalObject;
1426 prop->values.at(0)->type = Value::SignalExpression;
1428 if (!prop->values.at(0)->value.isScript())
1429 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1431 QString script = prop->values.at(0)->value.asScript().trimmed();
1432 if (script.isEmpty())
1433 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1435 compileState.signalExpressions.insert(prop->values.at(0), ctxt);
1444 Returns true if (value) property \a prop exists on obj, false otherwise.
1446 bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeParser::Property *prop,
1447 QDeclarativeParser::Object *obj)
1449 if(isAttachedPropertyName(prop->name) || prop->name == "id")
1452 const QMetaObject *mo = obj->metaObject();
1454 if (prop->isDefault) {
1455 QMetaProperty p = QDeclarativeMetaType::defaultProperty(mo);
1456 return p.name() != 0;
1458 int idx = indexOfProperty(obj, prop->name);
1459 return idx != -1 && mo->property(idx).isScriptable();
1466 bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop,
1467 QDeclarativeParser::Object *obj,
1468 const BindingContext &ctxt)
1470 if (prop->isEmpty())
1471 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1473 const QMetaObject *metaObject = obj->metaObject();
1474 Q_ASSERT(metaObject);
1476 if (isAttachedPropertyName(prop->name)) {
1477 // Setup attached property data
1479 if (ctxt.isSubContext()) {
1480 // Attached properties cannot be used on sub-objects. Sub-objects
1481 // always exist in a binding sub-context, which is what we test
1483 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1486 QDeclarativeType *type = 0;
1487 QDeclarativeImportedNamespace *typeNamespace = 0;
1488 unit->imports().resolveType(prop->name, &type, 0, 0, 0, &typeNamespace);
1490 if (typeNamespace) {
1491 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1494 } else if (!type || !type->attachedPropertiesType()) {
1495 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1499 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1501 Q_ASSERT(type->attachedPropertiesFunction());
1502 prop->index = type->attachedPropertiesId();
1503 prop->value->metatype = type->attachedPropertiesType();
1505 // Setup regular property data
1508 if (prop->isDefault) {
1509 p = QDeclarativeMetaType::defaultProperty(metaObject);
1512 prop->index = p.propertyIndex();
1513 prop->name = p.name();
1517 bool notInRevision = false;
1518 prop->index = indexOfProperty(obj, prop->name, ¬InRevision);
1519 if (prop->index == -1 && notInRevision) {
1520 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1521 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1523 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));
1525 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)));
1529 if (prop->index != -1) {
1530 p = metaObject->property(prop->index);
1533 if (!p.isScriptable()) {
1535 p = QMetaProperty();
1540 // We can't error here as the "id" property does not require a
1541 // successful index resolution
1543 prop->type = p.userType();
1545 // Check if this is an alias
1546 if (prop->index != -1 &&
1548 prop->parent->type != -1 &&
1549 output->types.at(prop->parent->type).component) {
1551 QDeclarativePropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1552 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1553 prop->isAlias = true;
1556 if (prop->index != -1 && !prop->values.isEmpty())
1557 prop->parent->setBindingBit(prop->index);
1560 if (!prop->isDefault && prop->name == "id" && !ctxt.isSubContext()) {
1562 // The magic "id" behavior doesn't apply when "id" is resolved as a
1563 // default property or to sub-objects (which are always in binding
1565 COMPILE_CHECK(buildIdProperty(prop, obj));
1566 if (prop->type == QVariant::String &&
1567 prop->values.at(0)->value.isString())
1568 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1570 } else if (isAttachedPropertyName(prop->name)) {
1572 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1574 } else if (prop->index == -1) {
1576 if (prop->isDefault) {
1577 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1579 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1582 } else if (prop->value) {
1584 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1586 } else if (enginePrivate->isList(prop->type)) {
1588 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1590 } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) {
1592 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1596 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1603 bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
1604 QDeclarativeParser::Property *nsProp,
1605 QDeclarativeParser::Object *obj,
1606 const BindingContext &ctxt)
1609 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1611 foreach (Property *prop, nsProp->value->properties) {
1613 if (!isAttachedPropertyName(prop->name))
1614 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1616 // Setup attached property data
1618 QDeclarativeType *type = 0;
1619 unit->imports().resolveType(ns, prop->name, &type, 0, 0, 0);
1621 if (!type || !type->attachedPropertiesType())
1622 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1625 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1627 Q_ASSERT(type->attachedPropertiesFunction());
1628 prop->index = type->index();
1629 prop->value->metatype = type->attachedPropertiesType();
1631 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1637 void QDeclarativeCompiler::genValueProperty(QDeclarativeParser::Property *prop,
1638 QDeclarativeParser::Object *obj)
1640 if (enginePrivate->isList(prop->type)) {
1641 genListProperty(prop, obj);
1643 genPropertyAssignment(prop, obj);
1647 void QDeclarativeCompiler::genListProperty(QDeclarativeParser::Property *prop,
1648 QDeclarativeParser::Object *obj)
1650 int listType = enginePrivate->listType(prop->type);
1652 QDeclarativeInstruction fetch;
1653 fetch.setType(QDeclarativeInstruction::FetchQList);
1654 fetch.fetchQmlList.property = prop->index;
1655 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1656 fetch.fetchQmlList.type = listType;
1657 output->addInstruction(fetch);
1659 for (int ii = 0; ii < prop->values.count(); ++ii) {
1660 QDeclarativeParser::Value *v = prop->values.at(ii);
1662 if (v->type == Value::CreatedObject) {
1664 genObject(v->object);
1665 if (listTypeIsInterface) {
1666 QDeclarativeInstruction assign;
1667 assign.setType(QDeclarativeInstruction::AssignObjectList);
1668 assign.assignObjectList.line = prop->location.start.line;
1669 output->addInstruction(assign);
1671 QDeclarativeInstruction store;
1672 store.setType(QDeclarativeInstruction::StoreObjectQList);
1673 output->addInstruction(store);
1676 } else if (v->type == Value::PropertyBinding) {
1678 genBindingAssignment(v, prop, obj);
1684 QDeclarativeInstruction pop;
1685 pop.setType(QDeclarativeInstruction::PopQList);
1686 output->addInstruction(pop);
1689 void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *prop,
1690 QDeclarativeParser::Object *obj,
1691 QDeclarativeParser::Property *valueTypeProperty)
1693 for (int ii = 0; ii < prop->values.count(); ++ii) {
1694 QDeclarativeParser::Value *v = prop->values.at(ii);
1696 Q_ASSERT(v->type == Value::CreatedObject ||
1697 v->type == Value::PropertyBinding ||
1698 v->type == Value::Literal);
1700 if (v->type == Value::CreatedObject) {
1702 genObject(v->object);
1704 if (QDeclarativeMetaType::isInterface(prop->type)) {
1706 QDeclarativeInstruction store;
1707 store.setType(QDeclarativeInstruction::StoreInterface);
1708 store.storeObject.line = v->object->location.start.line;
1709 store.storeObject.propertyIndex = prop->index;
1710 output->addInstruction(store);
1712 } else if (prop->type == -1) {
1714 QDeclarativeInstruction store;
1715 store.setType(QDeclarativeInstruction::StoreVariantObject);
1716 store.storeObject.line = v->object->location.start.line;
1717 store.storeObject.propertyIndex = prop->index;
1718 output->addInstruction(store);
1722 QDeclarativeInstruction store;
1723 store.setType(QDeclarativeInstruction::StoreObject);
1724 store.storeObject.line = v->object->location.start.line;
1725 store.storeObject.propertyIndex = prop->index;
1726 output->addInstruction(store);
1729 } else if (v->type == Value::PropertyBinding) {
1731 genBindingAssignment(v, prop, obj, valueTypeProperty);
1733 } else if (v->type == Value::Literal) {
1735 QMetaProperty mp = obj->metaObject()->property(prop->index);
1736 genLiteralAssignment(mp, v);
1742 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
1744 QDeclarativeParser::Value *v = prop->onValues.at(ii);
1746 Q_ASSERT(v->type == Value::ValueSource ||
1747 v->type == Value::ValueInterceptor);
1749 if (v->type == Value::ValueSource) {
1750 genObject(v->object);
1752 QDeclarativeInstruction store;
1753 store.setType(QDeclarativeInstruction::StoreValueSource);
1754 if (valueTypeProperty) {
1755 store.assignValueSource.property = genValueTypeData(prop, valueTypeProperty);
1756 store.assignValueSource.owner = 1;
1758 store.assignValueSource.property = genPropertyData(prop);
1759 store.assignValueSource.owner = 0;
1761 QDeclarativeType *valueType = toQmlType(v->object);
1762 store.assignValueSource.castValue = valueType->propertyValueSourceCast();
1763 output->addInstruction(store);
1765 } else if (v->type == Value::ValueInterceptor) {
1766 genObject(v->object);
1768 QDeclarativeInstruction store;
1769 store.setType(QDeclarativeInstruction::StoreValueInterceptor);
1770 if (valueTypeProperty) {
1771 store.assignValueInterceptor.property = genValueTypeData(prop, valueTypeProperty);
1772 store.assignValueInterceptor.owner = 1;
1774 store.assignValueInterceptor.property = genPropertyData(prop);
1775 store.assignValueInterceptor.owner = 0;
1777 QDeclarativeType *valueType = toQmlType(v->object);
1778 store.assignValueInterceptor.castValue = valueType->propertyValueInterceptorCast();
1779 output->addInstruction(store);
1785 bool QDeclarativeCompiler::buildIdProperty(QDeclarativeParser::Property *prop,
1786 QDeclarativeParser::Object *obj)
1789 prop->values.count() > 1 ||
1790 prop->values.at(0)->object)
1791 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
1793 QDeclarativeParser::Value *idValue = prop->values.at(0);
1794 QString val = idValue->primitive();
1796 COMPILE_CHECK(checkValidId(idValue, val));
1798 if (compileState.ids.contains(val))
1799 COMPILE_EXCEPTION(prop, tr("id is not unique"));
1801 prop->values.at(0)->type = Value::Id;
1809 void QDeclarativeCompiler::addId(const QString &id, QDeclarativeParser::Object *obj)
1811 Q_ASSERT(!compileState.ids.contains(id));
1812 Q_ASSERT(obj->id == id);
1813 obj->idIndex = compileState.ids.count();
1814 compileState.ids.insert(id, obj);
1815 compileState.idIndexes.insert(obj->idIndex, obj);
1818 void QDeclarativeCompiler::addBindingReference(const BindingReference &ref)
1820 Q_ASSERT(ref.value && !compileState.bindings.contains(ref.value));
1821 compileState.bindings.insert(ref.value, ref);
1824 void QDeclarativeCompiler::saveComponentState()
1826 Q_ASSERT(compileState.root);
1827 Q_ASSERT(!savedCompileStates.contains(compileState.root));
1829 savedCompileStates.insert(compileState.root, compileState);
1830 savedComponentStats.append(componentStat);
1833 QDeclarativeCompiler::ComponentCompileState
1834 QDeclarativeCompiler::componentState(QDeclarativeParser::Object *obj)
1836 Q_ASSERT(savedCompileStates.contains(obj));
1837 return savedCompileStates.value(obj);
1840 // Build attached property object. In this example,
1844 // GridView is an attached property object.
1845 bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeParser::Property *prop,
1846 QDeclarativeParser::Object *obj,
1847 const BindingContext &ctxt)
1849 Q_ASSERT(prop->value);
1850 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
1852 obj->addAttachedProperty(prop);
1854 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1860 // Build "grouped" properties. In this example:
1862 // font.pointSize: 12
1863 // font.family: "Helvetica"
1865 // font is a nested property. pointSize and family are not.
1866 bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeParser::Property *prop,
1867 QDeclarativeParser::Object *obj,
1868 const BindingContext &ctxt)
1870 Q_ASSERT(prop->type != 0);
1871 Q_ASSERT(prop->index != -1);
1873 if (QDeclarativeValueTypeFactory::isValueType(prop->type)) {
1874 if (prop->type >= 0 /* QVariant == -1 */ && enginePrivate->valueTypes[prop->type]) {
1876 if (prop->values.count()) {
1877 if (prop->values.at(0)->location < prop->value->location) {
1878 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
1880 COMPILE_EXCEPTION(prop->values.at(0), tr( "Property has already been assigned a value"));
1884 if (!obj->metaObject()->property(prop->index).isWritable()) {
1885 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
1889 if (prop->isAlias) {
1890 foreach (Property *vtProp, prop->value->properties)
1891 vtProp->isAlias = true;
1894 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
1895 prop->value, obj, ctxt.incr()));
1896 obj->addValueTypeProperty(prop);
1898 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1902 // Load the nested property's meta type
1903 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
1904 if (!prop->value->metatype)
1905 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1907 if (prop->values.count())
1908 COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign a value directly to a grouped property"));
1910 obj->addGroupedProperty(prop);
1912 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1918 bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
1919 QDeclarativeParser::Object *obj,
1920 QDeclarativeParser::Object *baseObj,
1921 const BindingContext &ctxt)
1923 if (obj->defaultProperty)
1924 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
1925 obj->metatype = type->metaObject();
1927 foreach (Property *prop, obj->properties) {
1928 int idx = type->metaObject()->indexOfProperty(prop->name.constData());
1930 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1931 QMetaProperty p = type->metaObject()->property(idx);
1932 if (!p.isScriptable())
1933 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1935 prop->type = p.userType();
1936 prop->isValueTypeSubProperty = true;
1939 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
1941 if (prop->values.count() > 1) {
1942 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
1943 } else if (prop->values.count()) {
1944 QDeclarativeParser::Value *value = prop->values.at(0);
1946 if (value->object) {
1947 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
1948 } else if (value->value.isScript()) {
1949 // ### Check for writability
1951 //optimization for <Type>.<EnumValue> enum assignments
1952 bool isEnumAssignment = false;
1953 COMPILE_CHECK(testQualifiedEnumAssignment(p, obj, value, &isEnumAssignment));
1954 if (isEnumAssignment) {
1955 value->type = Value::Literal;
1957 BindingReference reference;
1958 reference.expression = value->value;
1959 reference.property = prop;
1960 reference.value = value;
1961 reference.bindingContext = ctxt;
1962 reference.bindingContext.owner++;
1963 addBindingReference(reference);
1964 value->type = Value::PropertyBinding;
1967 COMPILE_CHECK(testLiteralAssignment(p, value));
1968 value->type = Value::Literal;
1972 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
1973 QDeclarativeParser::Value *v = prop->onValues.at(ii);
1974 Q_ASSERT(v->object);
1976 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
1979 obj->addValueProperty(prop);
1985 // Build assignments to QML lists. QML lists are properties of type
1986 // QDeclarativeListProperty<T>. List properties can accept a list of
1987 // objects, or a single binding.
1988 bool QDeclarativeCompiler::buildListProperty(QDeclarativeParser::Property *prop,
1989 QDeclarativeParser::Object *obj,
1990 const BindingContext &ctxt)
1992 Q_ASSERT(enginePrivate->isList(prop->type));
1996 obj->addValueProperty(prop);
1998 int listType = enginePrivate->listType(t);
1999 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
2001 bool assignedBinding = false;
2002 for (int ii = 0; ii < prop->values.count(); ++ii) {
2003 QDeclarativeParser::Value *v = prop->values.at(ii);
2005 v->type = Value::CreatedObject;
2006 COMPILE_CHECK(buildObject(v->object, ctxt));
2008 // We check object coercian here. We check interface assignment
2010 if (!listTypeIsInterface) {
2011 if (!canCoerce(listType, v->object)) {
2012 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2016 } else if (v->value.isScript()) {
2017 if (assignedBinding)
2018 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2020 assignedBinding = true;
2021 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2022 v->type = Value::PropertyBinding;
2024 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2031 // Compiles an assignment to a QDeclarativeScriptString property
2032 bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeParser::Property *prop,
2033 QDeclarativeParser::Object *obj,
2034 const BindingContext &ctxt)
2036 if (prop->values.count() > 1)
2037 COMPILE_EXCEPTION(prop->values.at(1), tr( "Cannot assign multiple values to a script property"));
2039 if (prop->values.at(0)->object)
2040 COMPILE_EXCEPTION(prop->values.at(0), tr( "Invalid property assignment: script expected"));
2042 obj->addScriptStringProperty(prop, ctxt.stack);
2047 // Compile regular property assignments of the form "property: <value>"
2048 bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeParser::Property *prop,
2049 QDeclarativeParser::Object *obj,
2050 const BindingContext &ctxt)
2052 obj->addValueProperty(prop);
2054 if (prop->values.count() > 1)
2055 COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign multiple values to a singular property") );
2057 for (int ii = 0; ii < prop->values.count(); ++ii) {
2058 QDeclarativeParser::Value *v = prop->values.at(ii);
2061 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2065 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2070 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
2071 QDeclarativeParser::Value *v = prop->onValues.at(ii);
2073 Q_ASSERT(v->object);
2074 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2080 // Compile assigning a single object instance to a regular property
2081 bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeParser::Property *prop,
2082 QDeclarativeParser::Object *obj,
2083 QDeclarativeParser::Value *v,
2084 const BindingContext &ctxt)
2086 Q_ASSERT(prop->index != -1);
2087 Q_ASSERT(v->object->type != -1);
2089 if (!obj->metaObject()->property(prop->index).isWritable())
2090 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2092 if (QDeclarativeMetaType::isInterface(prop->type)) {
2094 // Assigning an object to an interface ptr property
2095 COMPILE_CHECK(buildObject(v->object, ctxt));
2097 v->type = Value::CreatedObject;
2099 } else if (prop->type == -1) {
2101 // Assigning an object to a QVariant
2102 COMPILE_CHECK(buildObject(v->object, ctxt));
2104 v->type = Value::CreatedObject;
2106 // Normally buildObject() will set this up, but we need the static
2107 // meta object earlier to test for assignability. It doesn't matter
2108 // that there may still be outstanding synthesized meta object changes
2109 // on this type, as they are not relevant for assignability testing
2110 v->object->metatype = output->types.at(v->object->type).metaObject();
2111 Q_ASSERT(v->object->metaObject());
2113 // We want to raw metaObject here as the raw metaobject is the
2114 // actual property type before we applied any extensions that might
2115 // effect the properties on the type, but don't effect assignability
2116 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2118 // Will be true if the assgned type inherits propertyMetaObject
2119 bool isAssignable = false;
2120 // Determine isAssignable value
2121 if (propertyMetaObject) {
2122 const QMetaObject *c = v->object->metatype;
2124 isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject));
2125 c = c->superClass();
2130 // Simple assignment
2131 COMPILE_CHECK(buildObject(v->object, ctxt));
2133 v->type = Value::CreatedObject;
2134 } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) {
2135 // Automatic "Component" insertion
2136 QDeclarativeParser::Object *root = v->object;
2137 QDeclarativeParser::Object *component = new QDeclarativeParser::Object;
2138 component->type = componentTypeRef();
2139 component->typeName = "Qt/Component";
2140 component->metatype = &QDeclarativeComponent::staticMetaObject;
2141 component->location = root->location;
2142 QDeclarativeParser::Value *componentValue = new QDeclarativeParser::Value;
2143 componentValue->object = root;
2144 component->getDefaultProperty()->addValue(componentValue);
2145 v->object = component;
2146 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2148 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2155 // Compile assigning a single object instance to a regular property using the "on" syntax.
2159 // NumberAnimation on x { }
2161 bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeParser::Property *prop,
2162 QDeclarativeParser::Object *obj,
2163 QDeclarativeParser::Object *baseObj,
2164 QDeclarativeParser::Value *v,
2165 const BindingContext &ctxt)
2167 Q_ASSERT(prop->index != -1);
2168 Q_ASSERT(v->object->type != -1);
2170 if (!obj->metaObject()->property(prop->index).isWritable())
2171 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2174 // Normally buildObject() will set this up, but we need the static
2175 // meta object earlier to test for assignability. It doesn't matter
2176 // that there may still be outstanding synthesized meta object changes
2177 // on this type, as they are not relevant for assignability testing
2178 v->object->metatype = output->types.at(v->object->type).metaObject();
2179 Q_ASSERT(v->object->metaObject());
2181 // Will be true if the assigned type inherits QDeclarativePropertyValueSource
2182 bool isPropertyValue = false;
2183 // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor
2184 bool isPropertyInterceptor = false;
2185 if (QDeclarativeType *valueType = toQmlType(v->object)) {
2186 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2187 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2190 if (isPropertyValue || isPropertyInterceptor) {
2191 // Assign as a property value source
2192 COMPILE_CHECK(buildObject(v->object, ctxt));
2194 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2195 buildDynamicMeta(baseObj, ForceCreation);
2196 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2198 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(QString::fromUtf8(v->object->typeName)).arg(QString::fromUtf8(prop->name.constData())));
2204 // Compile assigning a literal or binding to a regular property
2205 bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeParser::Property *prop,
2206 QDeclarativeParser::Object *obj,
2207 QDeclarativeParser::Value *v,
2208 const BindingContext &ctxt)
2210 Q_ASSERT(prop->index != -1);
2212 if (v->value.isScript()) {
2214 //optimization for <Type>.<EnumValue> enum assignments
2215 bool isEnumAssignment = false;
2216 COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj, v, &isEnumAssignment));
2217 if (isEnumAssignment) {
2218 v->type = Value::Literal;
2222 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2224 v->type = Value::PropertyBinding;
2228 COMPILE_CHECK(testLiteralAssignment(obj->metaObject()->property(prop->index), v));
2230 v->type = Value::Literal;
2236 bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop,
2237 QDeclarativeParser::Object *obj,
2238 QDeclarativeParser::Value *v,
2241 *isAssignment = false;
2242 if (!prop.isEnumType())
2245 if (!prop.isWritable())
2246 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
2248 QString string = v->value.asString();
2249 if (!string.at(0).isUpper())
2252 QStringList parts = string.split(QLatin1Char('.'));
2253 if (parts.count() != 2)
2256 QString typeName = parts.at(0);
2257 QDeclarativeType *type = 0;
2258 unit->imports().resolveType(typeName.toUtf8(), &type, 0, 0, 0, 0);
2260 //handle enums on value types (where obj->typeName is empty)
2261 QByteArray objTypeName = obj->typeName;
2262 if (objTypeName.isEmpty()) {
2263 QDeclarativeType *objType = toQmlType(obj);
2265 objTypeName = objType->qmlTypeName();
2271 QString enumValue = parts.at(1);
2274 if (objTypeName == type->qmlTypeName()) {
2275 // When these two match, we can short cut the search
2276 if (prop.isFlagType()) {
2277 value = prop.enumerator().keysToValue(enumValue.toUtf8().constData());
2279 value = prop.enumerator().keyToValue(enumValue.toUtf8().constData());
2282 // Otherwise we have to search the whole type
2283 // This matches the logic in QV8TypeWrapper
2284 QByteArray enumName = enumValue.toUtf8();
2285 const QMetaObject *metaObject = type->baseMetaObject();
2286 for (int ii = metaObject->enumeratorCount() - 1; value == -1 && ii >= 0; --ii) {
2287 QMetaEnum e = metaObject->enumerator(ii);
2288 value = e.keyToValue(enumName.constData());
2295 v->type = Value::Literal;
2296 v->value = QDeclarativeParser::Variant((double)value);
2297 *isAssignment = true;
2302 struct StaticQtMetaObject : public QObject
2304 static const QMetaObject *get()
2305 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2308 // Similar logic to above, but not knowing target property.
2309 int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const
2311 int dot = script.indexOf('.');
2313 const QByteArray &scope = script.left(dot);
2314 QDeclarativeType *type = 0;
2315 unit->imports().resolveType(scope, &type, 0, 0, 0, 0);
2316 if (!type && scope != "Qt")
2318 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2319 const char *key = script.constData() + dot+1;
2320 int i = mo->enumeratorCount();
2322 int v = mo->enumerator(i).keyToValue(key);
2330 const QMetaObject *QDeclarativeCompiler::resolveType(const QByteArray& name) const
2332 QDeclarativeType *qmltype = 0;
2333 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2337 return qmltype->metaObject();
2340 // similar to logic of completeComponentBuild, but also sticks data
2341 // into primitives at the end
2342 int QDeclarativeCompiler::rewriteBinding(const QString& expression, const QByteArray& name)
2344 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2345 rewriteBinding.setName('$' + name.mid(name.lastIndexOf('.') + 1));
2347 QString rewrite = rewriteBinding(expression, 0, 0);
2349 return output->indexForString(rewrite);
2352 // Ensures that the dynamic meta specification on obj is valid
2353 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj)
2355 QSet<QByteArray> propNames;
2356 QSet<QByteArray> methodNames;
2357 bool seenDefaultProperty = false;
2360 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2361 const QDeclarativeParser::Object::DynamicProperty &prop =
2362 obj->dynamicProperties.at(ii);
2364 if (prop.isDefaultProperty) {
2365 if (seenDefaultProperty)
2366 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2367 seenDefaultProperty = true;
2370 if (propNames.contains(prop.name))
2371 COMPILE_EXCEPTION(&prop, tr("Duplicate property name"));
2373 QString propName = QString::fromUtf8(prop.name);
2374 if (propName.at(0).isUpper())
2375 COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
2377 if (enginePrivate->v8engine()->illegalNames().contains(propName))
2378 COMPILE_EXCEPTION(&prop, tr("Illegal property name"));
2380 propNames.insert(prop.name);
2383 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2384 QByteArray name = obj->dynamicSignals.at(ii).name;
2385 if (methodNames.contains(name))
2386 COMPILE_EXCEPTION(obj, tr("Duplicate signal name"));
2387 QString nameStr = QString::fromUtf8(name);
2388 if (nameStr.at(0).isUpper())
2389 COMPILE_EXCEPTION(obj, tr("Signal names cannot begin with an upper case letter"));
2390 if (enginePrivate->v8engine()->illegalNames().contains(nameStr))
2391 COMPILE_EXCEPTION(obj, tr("Illegal signal name"));
2392 methodNames.insert(name);
2394 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2395 QByteArray name = obj->dynamicSlots.at(ii).name;
2396 if (methodNames.contains(name))
2397 COMPILE_EXCEPTION(obj, tr("Duplicate method name"));
2398 QString nameStr = QString::fromUtf8(name);
2399 if (nameStr.at(0).isUpper())
2400 COMPILE_EXCEPTION(obj, tr("Method names cannot begin with an upper case letter"));
2401 if (enginePrivate->v8engine()->illegalNames().contains(nameStr))
2402 COMPILE_EXCEPTION(obj, tr("Illegal method name"));
2403 methodNames.insert(name);
2409 bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeParser::Object *obj)
2411 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2412 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2414 if (!p.defaultValue || p.type == Object::DynamicProperty::Alias)
2417 Property *property = 0;
2418 if (p.isDefaultProperty) {
2419 property = obj->getDefaultProperty();
2421 property = obj->getProperty(p.name);
2422 if (!property->values.isEmpty())
2423 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2426 if (property->value)
2427 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2429 for (int ii = 0; ii < p.defaultValue->values.count(); ++ii) {
2430 QDeclarativeParser::Value *v = p.defaultValue->values.at(ii);
2432 property->values.append(v);
2438 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2440 bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, DynamicMetaMode mode)
2443 Q_ASSERT(obj->metatype);
2445 if (mode != ForceCreation &&
2446 obj->dynamicProperties.isEmpty() &&
2447 obj->dynamicSignals.isEmpty() &&
2448 obj->dynamicSlots.isEmpty())
2451 QByteArray dynamicData(sizeof(QDeclarativeVMEMetaData), (char)0);
2453 QByteArray newClassName = obj->metatype->className();
2454 newClassName.append("_QML_");
2455 int idx = classIndexCounter()->fetchAndAddRelaxed(1);
2456 newClassName.append(QByteArray::number(idx));
2457 if (compileState.root == obj && !compileState.nested) {
2458 QString path = output->url.path();
2459 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2460 if (lastSlash > -1) {
2461 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2462 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2463 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(idx);
2467 QMetaObjectBuilder builder;
2468 builder.setClassName(newClassName);
2469 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
2471 bool hasAlias = false;
2472 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2473 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2475 int propIdx = obj->metaObject()->indexOfProperty(p.name.constData());
2476 if (-1 != propIdx) {
2477 QMetaProperty prop = obj->metaObject()->property(propIdx);
2479 COMPILE_EXCEPTION(&p, tr("Cannot override FINAL property"));
2482 if (p.isDefaultProperty &&
2483 (p.type != Object::DynamicProperty::Alias ||
2484 mode == ResolveAliases))
2485 builder.addClassInfo("DefaultProperty", p.name);
2488 int propertyType = 0;
2489 bool readonly = false;
2491 case Object::DynamicProperty::Alias:
2495 case Object::DynamicProperty::CustomList:
2496 case Object::DynamicProperty::Custom:
2498 QByteArray customTypeName;
2499 QDeclarativeType *qmltype = 0;
2501 if (!unit->imports().resolveType(p.customType, &qmltype, &url, 0, 0, 0))
2502 COMPILE_EXCEPTION(&p, tr("Invalid property type"));
2505 QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(url);
2507 Q_ASSERT(tdata->isComplete());
2509 QDeclarativeCompiledData *data = tdata->compiledData();
2510 customTypeName = data->root->className();
2514 customTypeName = qmltype->typeName();
2517 if (p.type == Object::DynamicProperty::Custom) {
2518 type = customTypeName + '*';
2519 propertyType = QMetaType::QObjectStar;
2522 type = "QDeclarativeListProperty<";
2523 type.append(customTypeName);
2525 propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
2529 case Object::DynamicProperty::Variant:
2533 case Object::DynamicProperty::Int:
2534 propertyType = QVariant::Int;
2537 case Object::DynamicProperty::Bool:
2538 propertyType = QVariant::Bool;
2541 case Object::DynamicProperty::Real:
2542 propertyType = QVariant::Double;
2545 case Object::DynamicProperty::String:
2546 propertyType = QVariant::String;
2549 case Object::DynamicProperty::Url:
2550 propertyType = QVariant::Url;
2553 case Object::DynamicProperty::Color:
2554 propertyType = QVariant::Color;
2557 case Object::DynamicProperty::Time:
2558 propertyType = QVariant::Time;
2561 case Object::DynamicProperty::Date:
2562 propertyType = QVariant::Date;
2565 case Object::DynamicProperty::DateTime:
2566 propertyType = QVariant::DateTime;
2571 ((QDeclarativeVMEMetaData *)dynamicData.data())->propertyCount++;
2572 QDeclarativeVMEMetaData::PropertyData propertyData = { propertyType };
2573 dynamicData.append((char *)&propertyData, sizeof(propertyData));
2575 builder.addSignal(p.name + "Changed()");
2576 QMetaPropertyBuilder propBuilder =
2577 builder.addProperty(p.name, type, builder.methodCount() - 1);
2578 propBuilder.setWritable(!readonly);
2581 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2582 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2584 if (p.type == Object::DynamicProperty::Alias) {
2585 if (mode == ResolveAliases) {
2586 ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++;
2587 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, p));
2589 // Need a fake signal so that the metaobject remains consistent across
2590 // the resolve and non-resolve alias runs
2591 builder.addSignal(p.name + "Changed()");
2596 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2597 const Object::DynamicSignal &s = obj->dynamicSignals.at(ii);
2598 QByteArray sig(s.name + '(');
2599 for (int jj = 0; jj < s.parameterTypes.count(); ++jj) {
2600 if (jj) sig.append(',');
2601 sig.append(s.parameterTypes.at(jj));
2604 QMetaMethodBuilder b = builder.addSignal(sig);
2605 b.setParameterNames(s.parameterNames);
2606 ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++;
2609 QStringList funcScripts;
2611 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2612 Object::DynamicSlot &s = obj->dynamicSlots[ii];
2613 QByteArray sig(s.name + '(');
2614 QString funcScript(QLatin1String("(function ") + s.name + QLatin1Char('('));
2616 for (int jj = 0; jj < s.parameterNames.count(); ++jj) {
2619 funcScript.append(QLatin1Char(','));
2621 funcScript.append(QLatin1String(s.parameterNames.at(jj)));
2622 sig.append("QVariant");
2625 funcScript.append(QLatin1Char(')'));
2626 funcScript.append(s.body);
2627 funcScript.append(QLatin1Char(')'));
2628 funcScripts << funcScript;
2630 QMetaMethodBuilder b = builder.addSlot(sig);
2631 b.setReturnType("QVariant");
2632 b.setParameterNames(s.parameterNames);
2634 ((QDeclarativeVMEMetaData *)dynamicData.data())->methodCount++;
2635 QDeclarativeVMEMetaData::MethodData methodData =
2636 { s.parameterNames.count(), 0, funcScript.length(), s.location.start.line };
2638 dynamicData.append((char *)&methodData, sizeof(methodData));
2641 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2642 const QString &funcScript = funcScripts.at(ii);
2643 QDeclarativeVMEMetaData::MethodData *data =
2644 ((QDeclarativeVMEMetaData *)dynamicData.data())->methodData() + ii;
2646 data->bodyOffset = dynamicData.size();
2648 dynamicData.append((const char *)funcScript.constData(),
2649 (funcScript.length() * sizeof(QChar)));
2652 obj->metadata = builder.toRelocatableData();
2653 builder.fromRelocatableData(&obj->extObject, obj->metatype, obj->metadata);
2655 if (mode == IgnoreAliases && hasAlias)
2656 compileState.aliasingObjects << obj;
2658 obj->synthdata = dynamicData;
2660 if (obj->synthCache) {
2661 obj->synthCache->release();
2662 obj->synthCache = 0;
2665 if (obj->type != -1) {
2666 QDeclarativePropertyCache *cache = output->types[obj->type].createPropertyCache(engine)->copy();
2667 cache->append(engine, &obj->extObject, QDeclarativePropertyCache::Data::NoFlags,
2668 QDeclarativePropertyCache::Data::IsVMEFunction,
2669 QDeclarativePropertyCache::Data::IsVMESignal);
2670 obj->synthCache = cache;
2676 bool QDeclarativeCompiler::checkValidId(QDeclarativeParser::Value *v, const QString &val)
2679 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
2681 if (val.at(0).isLetter() && !val.at(0).isLower())
2682 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
2684 QChar u(QLatin1Char('_'));
2685 for (int ii = 0; ii < val.count(); ++ii) {
2687 if (ii == 0 && !val.at(ii).isLetter() && val.at(ii) != u) {
2688 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
2689 } else if (ii != 0 && !val.at(ii).isLetterOrNumber() && val.at(ii) != u) {
2690 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
2695 if (enginePrivate->v8engine()->illegalNames().contains(val))
2696 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
2701 #include <qdeclarativejsparser_p.h>
2703 static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node)
2705 if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) {
2707 static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name->asString();
2708 return QStringList() << name;
2709 } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) {
2710 QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node);
2712 QStringList rv = astNodeToStringList(expr->base);
2715 rv.append(expr->name->asString());
2718 return QStringList();
2721 bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder,
2723 QDeclarativeParser::Object *obj,
2724 const Object::DynamicProperty &prop)
2726 if (!prop.defaultValue)
2727 COMPILE_EXCEPTION(obj, tr("No property alias location"));
2729 if (prop.defaultValue->values.count() != 1 ||
2730 prop.defaultValue->values.at(0)->object ||
2731 !prop.defaultValue->values.at(0)->value.isScript())
2732 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2734 QDeclarativeJS::AST::Node *node = prop.defaultValue->values.at(0)->value.asAST();
2736 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
2738 QStringList alias = astNodeToStringList(node);
2740 if (alias.count() < 1 || alias.count() > 3)
2741 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
2743 if (!compileState.ids.contains(alias.at(0)))
2744 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
2746 QDeclarativeParser::Object *idObject = compileState.ids[alias.at(0)];
2748 QByteArray typeName;
2752 bool writable = false;
2753 if (alias.count() == 2 || alias.count() == 3) {
2754 propIdx = indexOfProperty(idObject, alias.at(1).toUtf8());
2756 if (-1 == propIdx) {
2757 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2758 } else if (propIdx > 0xFFFF) {
2759 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
2762 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
2763 if (!aliasProperty.isScriptable())
2764 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2766 writable = aliasProperty.isWritable();
2768 if (alias.count() == 3) {
2769 QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
2771 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2773 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
2775 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
2776 if (valueTypeIndex == -1)
2777 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2778 Q_ASSERT(valueTypeIndex <= 0xFF);
2780 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
2781 propIdx |= (valueTypeIndex << 16);
2784 if (aliasProperty.isEnumType())
2785 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
2787 typeName = aliasProperty.typeName();
2789 Q_ASSERT(idObject->type != -1); // How else did it get an id?
2791 const QDeclarativeCompiledData::TypeReference &ref = output->types.at(idObject->type);
2793 typeName = ref.type->typeName();
2795 typeName = ref.component->root->className();
2800 if (typeName.endsWith('*'))
2801 flags |= QML_ALIAS_FLAG_PTR;
2803 data.append((const char *)&idObject->idIndex, sizeof(idObject->idIndex));
2804 data.append((const char *)&propIdx, sizeof(propIdx));
2805 data.append((const char *)&flags, sizeof(flags));
2807 builder.addSignal(prop.name + "Changed()");
2808 QMetaPropertyBuilder propBuilder =
2809 builder.addProperty(prop.name, typeName.constData(), builder.methodCount() - 1);
2810 propBuilder.setWritable(writable);
2814 bool QDeclarativeCompiler::buildBinding(QDeclarativeParser::Value *value,
2815 QDeclarativeParser::Property *prop,
2816 const BindingContext &ctxt)
2818 Q_ASSERT(prop->index != -1);
2819 Q_ASSERT(prop->parent);
2820 Q_ASSERT(prop->parent->metaObject());
2822 QMetaProperty mp = prop->parent->metaObject()->property(prop->index);
2823 if (!mp.isWritable() && !QDeclarativeMetaType::isList(prop->type))
2824 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2826 BindingReference reference;
2827 reference.expression = value->value;
2828 reference.property = prop;
2829 reference.value = value;
2830 reference.bindingContext = ctxt;
2831 addBindingReference(reference);
2836 void QDeclarativeCompiler::genBindingAssignment(QDeclarativeParser::Value *binding,
2837 QDeclarativeParser::Property *prop,
2838 QDeclarativeParser::Object *obj,
2839 QDeclarativeParser::Property *valueTypeProperty)
2842 Q_ASSERT(compileState.bindings.contains(binding));
2844 const BindingReference &ref = compileState.bindings.value(binding);
2845 if (ref.dataType == BindingReference::V4) {
2846 QDeclarativeInstruction store;
2847 store.setType(QDeclarativeInstruction::StoreV4Binding);
2848 store.assignBinding.value = ref.compiledIndex;
2849 store.assignBinding.context = ref.bindingContext.stack;
2850 store.assignBinding.owner = ref.bindingContext.owner;
2851 if (valueTypeProperty)
2852 store.assignBinding.property = (valueTypeProperty->index & 0xFFFF) |
2853 ((valueTypeProperty->type & 0xFF)) << 16 |
2854 ((prop->index & 0xFF) << 24);
2856 store.assignBinding.property = prop->index;
2857 store.assignBinding.line = binding->location.start.line;
2858 output->addInstruction(store);
2859 } else if (ref.dataType == BindingReference::V8) {
2860 QDeclarativeInstruction store;
2861 store.setType(QDeclarativeInstruction::StoreV8Binding);
2862 store.assignBinding.value = ref.compiledIndex;
2863 store.assignBinding.context = ref.bindingContext.stack;
2864 store.assignBinding.owner = ref.bindingContext.owner;
2865 store.assignBinding.line = binding->location.start.line;
2867 Q_ASSERT(ref.bindingContext.owner == 0 ||
2868 (ref.bindingContext.owner != 0 && valueTypeProperty));
2869 if (ref.bindingContext.owner) {
2870 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
2872 store.assignBinding.property = genPropertyData(prop);
2875 output->addInstruction(store);
2877 QDeclarativeInstruction store;
2879 store.setType(QDeclarativeInstruction::StoreBinding);
2881 store.setType(QDeclarativeInstruction::StoreBindingOnAlias);
2882 store.assignBinding.value = output->indexForString(ref.rewrittenExpression);
2883 store.assignBinding.context = ref.bindingContext.stack;
2884 store.assignBinding.owner = ref.bindingContext.owner;
2885 store.assignBinding.line = binding->location.start.line;
2887 Q_ASSERT(ref.bindingContext.owner == 0 ||
2888 (ref.bindingContext.owner != 0 && valueTypeProperty));
2889 if (ref.bindingContext.owner) {
2890 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
2892 store.assignBinding.property = genPropertyData(prop);
2894 output->addInstruction(store);
2898 int QDeclarativeCompiler::genContextCache()
2900 if (compileState.ids.count() == 0)
2903 QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache();
2905 for (QHash<QString, QDeclarativeParser::Object *>::ConstIterator iter = compileState.ids.begin();
2906 iter != compileState.ids.end();
2908 cache->add(iter.key(), (*iter)->idIndex);
2910 output->contextCaches.append(cache);
2911 return output->contextCaches.count() - 1;
2914 int QDeclarativeCompiler::genValueTypeData(QDeclarativeParser::Property *valueTypeProp,
2915 QDeclarativeParser::Property *prop)
2917 typedef QDeclarativePropertyPrivate QDPP;
2918 QByteArray data = QDPP::saveValueType(prop->parent->metaObject(), prop->index,
2919 enginePrivate->valueTypes[prop->type]->metaObject(),
2920 valueTypeProp->index, engine);
2922 return output->indexForByteArray(data);
2925 int QDeclarativeCompiler::genPropertyData(QDeclarativeParser::Property *prop)
2927 typedef QDeclarativePropertyPrivate QDPP;
2928 QByteArray data = QDPP::saveProperty(prop->parent->metaObject(), prop->index, engine);
2930 return output->indexForByteArray(data);
2933 bool QDeclarativeCompiler::completeComponentBuild()
2935 componentStat.ids = compileState.ids.count();
2937 for (int ii = 0; ii < compileState.aliasingObjects.count(); ++ii) {
2938 QDeclarativeParser::Object *aliasObject = compileState.aliasingObjects.at(ii);
2939 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
2942 QDeclarativeV4Compiler::Expression expr;
2943 expr.component = compileState.root;
2944 expr.ids = compileState.ids;
2945 expr.importCache = output->importCache;
2946 expr.imports = unit->imports();
2948 QDeclarativeV4Compiler bindingCompiler;
2950 QList<BindingReference*> sharedBindings;
2952 for (QHash<QDeclarativeParser::Value*,BindingReference>::Iterator iter = compileState.bindings.begin();
2953 iter != compileState.bindings.end(); ++iter) {
2955 BindingReference &binding = *iter;
2957 // ### We don't currently optimize for bindings on alias's - because
2958 // of the solution to QTBUG-13719
2959 if (!binding.property->isAlias) {
2960 expr.context = binding.bindingContext.object;
2961 expr.property = binding.property;
2962 expr.expression = binding.expression;
2964 int index = bindingCompiler.compile(expr, enginePrivate);
2966 binding.dataType = BindingReference::V4;
2967 binding.compiledIndex = index;
2968 componentStat.optimizedBindings.append(iter.key()->location);
2973 // Pre-rewrite the expression
2974 QString expression = binding.expression.asScript();
2976 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2977 rewriteBinding.setName('$'+binding.property->name);
2978 bool isSharable = false;
2979 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
2981 if (isSharable && !binding.property->isAlias /* See above re alias */ &&
2982 binding.property->type != qMetaTypeId<QDeclarativeBinding*>()) {
2983 binding.dataType = BindingReference::V8;
2984 sharedBindings.append(&iter.value());
2986 binding.dataType = BindingReference::QtScript;
2989 componentStat.scriptBindings.append(iter.key()->location);
2992 if (!sharedBindings.isEmpty()) {
2994 static bool lt(const BindingReference *lhs, const BindingReference *rhs)
2996 return lhs->value->location.start.line < rhs->value->location.start.line;
3000 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3002 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3003 int lineNumber = startLineNumber;
3005 QString functionArray(QLatin1String("["));
3006 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3007 BindingReference *reference = sharedBindings.at(ii);
3008 QDeclarativeParser::Value *value = reference->value;
3009 const QString &expression = reference->rewrittenExpression;
3011 if (ii != 0) functionArray += QLatin1String(",");
3013 while (lineNumber < value->location.start.line) {
3015 functionArray += QLatin1String("\n");
3018 functionArray += expression;
3019 reference->compiledIndex = ii;
3021 functionArray += QLatin1String("]");
3023 compileState.v8BindingProgram = functionArray;
3024 compileState.v8BindingProgramLine = startLineNumber;
3025 compileState.v8BindingProgramIndex = output->v8bindings.count();
3026 output->v8bindings.append(v8::Persistent<v8::Array>());
3029 if (bindingCompiler.isValid())
3030 compileState.compiledBindingData = bindingCompiler.program();
3032 saveComponentState();
3037 void QDeclarativeCompiler::dumpStats()
3039 qWarning().nospace() << "QML Document: " << output->url.toString();
3040 for (int ii = 0; ii < savedComponentStats.count(); ++ii) {
3041 const ComponentStat &stat = savedComponentStats.at(ii);
3042 qWarning().nospace() << " Component Line " << stat.lineNumber;
3043 qWarning().nospace() << " Total Objects: " << stat.objects;
3044 qWarning().nospace() << " IDs Used: " << stat.ids;
3045 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3049 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3050 if (0 == (ii % 10)) {
3051 if (ii) output.append("\n");
3056 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3058 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3059 output.append(") ");
3061 if (!output.isEmpty())
3062 qWarning().nospace() << output.constData();
3065 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3068 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3069 if (0 == (ii % 10)) {
3070 if (ii) output.append("\n");
3075 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3077 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3078 output.append(") ");
3080 if (!output.isEmpty())
3081 qWarning().nospace() << output.constData();
3087 Returns true if from can be assigned to a (QObject) property of type
3090 bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeParser::Object *from)
3092 const QMetaObject *toMo =
3093 enginePrivate->rawMetaObjectForType(to);
3094 const QMetaObject *fromMo = from->metaObject();
3097 if (QDeclarativePropertyPrivate::equal(fromMo, toMo))
3099 fromMo = fromMo->superClass();
3104 QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeParser::Object *from)
3107 const QMetaObject *mo = from->metatype;
3108 QDeclarativeType *type = 0;
3109 while (!type && mo) {
3110 type = QDeclarativeMetaType::qmlType(mo);
3111 mo = mo->superClass();
3116 QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeParser::Object *obj)
3118 const QMetaObject *mo = obj->metatype;
3120 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3122 return QStringList();
3124 QMetaClassInfo classInfo = mo->classInfo(idx);
3125 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3129 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3130 int QDeclarativeCompiler::indexOfSignal(QDeclarativeParser::Object *object, const QByteArray &name,
3131 bool *notInRevision)
3133 if (notInRevision) *notInRevision = false;
3135 if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) {
3137 QString strName(QString::fromUtf8(name));
3138 QDeclarativePropertyCache *cache =
3139 object->synthCache?object->synthCache:output->types.at(object->type).propertyCache();
3141 QDeclarativePropertyCache::Data *d = cache->property(strName);
3142 if (notInRevision) *notInRevision = false;
3144 while (d && !(d->isFunction()))
3145 d = cache->overrideData(d);
3147 if (d && !cache->isAllowedInRevision(d)) {
3148 if (notInRevision) *notInRevision = true;
3151 return d->coreIndex;
3154 if (name.endsWith("Changed")) {
3155 QByteArray propName = name.mid(0, name.length() - 7);
3157 int propIndex = indexOfProperty(object, propName, notInRevision);
3158 if (propIndex != -1) {
3159 d = cache->property(propIndex);
3160 return d->notifyIndex;
3166 return QDeclarativePropertyPrivate::findSignalByName(object->metaObject(), name).methodIndex();
3171 int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QByteArray &name,
3172 bool *notInRevision)
3174 if (notInRevision) *notInRevision = false;
3176 if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) {
3178 QString strName(QString::fromUtf8(name));
3179 QDeclarativePropertyCache *cache =
3180 object->synthCache?object->synthCache:output->types.at(object->type).propertyCache();
3182 QDeclarativePropertyCache::Data *d = cache->property(strName);
3183 // Find the first property
3184 while (d && d->isFunction())
3185 d = cache->overrideData(d);
3187 if (d && !cache->isAllowedInRevision(d)) {
3188 if (notInRevision) *notInRevision = true;
3191 return d?d->coreIndex:-1;
3194 const QMetaObject *mo = object->metaObject();
3195 return mo->indexOfProperty(name.constData());