1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "private/qdeclarativecompiler_p.h"
44 #include "private/qdeclarativeparser_p.h"
45 #include "private/qdeclarativescriptparser_p.h"
46 #include "qdeclarativepropertyvaluesource.h"
47 #include "qdeclarativecomponent.h"
48 #include "private/qmetaobjectbuilder_p.h"
49 #include "private/qdeclarativestringconverters_p.h"
50 #include "private/qdeclarativeengine_p.h"
51 #include "qdeclarativeengine.h"
52 #include "qdeclarativecontext.h"
53 #include "private/qdeclarativemetatype_p.h"
54 #include "private/qdeclarativecustomparser_p_p.h"
55 #include "private/qdeclarativecontext_p.h"
56 #include "private/qdeclarativecomponent_p.h"
57 #include "parser/qdeclarativejsast_p.h"
58 #include "private/qdeclarativevmemetaobject_p.h"
59 #include "private/qdeclarativeexpression_p.h"
60 #include "private/qdeclarativeproperty_p.h"
61 #include "private/qdeclarativerewrite_p.h"
62 #include "qdeclarativescriptstring.h"
63 #include "private/qdeclarativeglobal_p.h"
64 #include "private/qdeclarativescriptparser_p.h"
65 #include "private/qdeclarativebinding_p.h"
66 #include "private/qdeclarativev4compiler_p.h"
74 #include <QtCore/qdebug.h>
75 #include <QtCore/qdatetime.h>
79 DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP);
80 DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS);
82 using namespace QDeclarativeParser;
85 Instantiate a new QDeclarativeCompiler.
87 QDeclarativeCompiler::QDeclarativeCompiler()
88 : output(0), engine(0), unitRoot(0), unit(0)
93 Returns true if the last call to compile() caused errors.
97 bool QDeclarativeCompiler::isError() const
99 return !exceptions.isEmpty();
103 Return the list of errors from the last call to compile(), or an empty list
104 if there were no errors.
106 QList<QDeclarativeError> QDeclarativeCompiler::errors() const
112 Returns true if \a name refers to an attached property, false otherwise.
114 Attached property names are those that start with a capital letter.
116 bool QDeclarativeCompiler::isAttachedPropertyName(const QByteArray &name)
118 return !name.isEmpty() && name.at(0) >= 'A' && name.at(0) <= 'Z';
122 Returns true if \a name refers to a signal property, false otherwise.
124 Signal property names are those that start with "on", followed by a first
125 character which is either a capital letter or one or more underscores followed
126 by a capital letter, which is then followed by other allowed characters.
128 Note that although ECMA-262r3 supports dollarsigns and escaped unicode
129 character codes in property names, for simplicity and performance reasons
130 QML only supports letters, numbers and underscores.
132 bool QDeclarativeCompiler::isSignalPropertyName(const QByteArray &name)
134 if (name.length() < 3) return false;
135 if (!name.startsWith("on")) return false;
136 int ns = name.size();
137 for (int i = 2; i < ns; ++i) {
138 char curr = name.at(i);
139 if (curr == '_') continue;
140 if (curr >= 'A' && curr <= 'Z') return true;
143 return false; // consists solely of underscores - invalid.
147 \macro COMPILE_EXCEPTION
149 Inserts an error into the QDeclarativeCompiler error list, and returns false
152 \a token is used to source the error line and column, and \a desc is the
153 error itself. \a desc can be an expression that can be piped into QDebug.
158 COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(QString::fromUtf8(property->name)));
161 #define COMPILE_EXCEPTION(token, desc) \
163 QString exceptionDescription; \
164 QDeclarativeError error; \
165 error.setUrl(output->url); \
166 error.setLine((token)->location.start.line); \
167 error.setColumn((token)->location.start.column); \
168 error.setDescription(desc.trimmed()); \
169 exceptions << error; \
176 Returns false if \a is false, otherwise does nothing.
178 #define COMPILE_CHECK(a) \
180 if (!a) return false; \
184 Returns true if literal \a v can be assigned to property \a prop, otherwise
187 This test corresponds to action taken by genLiteralAssignment(). Any change
188 made here, must have a corresponding action in genLiteralAssigment().
190 bool QDeclarativeCompiler::testLiteralAssignment(const QMetaProperty &prop,
191 QDeclarativeParser::Value *v)
193 QString string = v->value.asString();
195 if (!prop.isWritable())
196 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
198 if (prop.isEnumType()) {
200 if (prop.isFlagType()) {
201 value = prop.enumerator().keysToValue(string.toUtf8().constData());
203 value = prop.enumerator().keyToValue(string.toUtf8().constData());
205 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration"));
208 int type = prop.userType();
212 case QVariant::String:
213 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
215 case QVariant::ByteArray:
216 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected"));
219 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected"));
223 bool ok = v->value.isNumber();
225 double n = v->value.asNumber();
226 if (double(uint(n)) != n)
229 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected"));
234 bool ok = v->value.isNumber();
236 double n = v->value.asNumber();
237 if (double(int(n)) != n)
240 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected"));
243 case QMetaType::Float:
244 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
246 case QVariant::Double:
247 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
249 case QVariant::Color:
252 QDeclarativeStringConverters::colorFromString(string, &ok);
253 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected"));
256 #ifndef QT_NO_DATESTRING
260 QDeclarativeStringConverters::dateFromString(string, &ok);
261 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected"));
267 QDeclarativeStringConverters::timeFromString(string, &ok);
268 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected"));
271 case QVariant::DateTime:
274 QDeclarativeStringConverters::dateTimeFromString(string, &ok);
275 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected"));
278 #endif // QT_NO_DATESTRING
279 case QVariant::Point:
280 case QVariant::PointF:
283 QPointF point = QDeclarativeStringConverters::pointFFromString(string, &ok);
284 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected"));
288 case QVariant::SizeF:
291 QSizeF size = QDeclarativeStringConverters::sizeFFromString(string, &ok);
292 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected"));
296 case QVariant::RectF:
299 QRectF rect = QDeclarativeStringConverters::rectFFromString(string, &ok);
300 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected"));
305 if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected"));
308 case QVariant::Vector3D:
311 QDeclarativeStringConverters::vector3DFromString(string, &ok);
312 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected"));
317 int t = prop.userType();
318 QDeclarativeMetaType::StringConverter converter =
319 QDeclarativeMetaType::customStringConverter(t);
321 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName(prop.type()))));
329 Generate a store instruction for assigning literal \a v to property \a prop.
331 Any literal assignment that is approved in testLiteralAssignment() must have
332 a corresponding action in this method.
334 void QDeclarativeCompiler::genLiteralAssignment(const QMetaProperty &prop,
335 QDeclarativeParser::Value *v)
337 QDeclarativeInstruction instr;
338 if (prop.isEnumType()) {
340 if (v->value.isNumber()) {
342 value = (int)v->value.asNumber();
345 if (prop.isFlagType()) {
346 value = prop.enumerator().keysToValue(v->value.asString().toUtf8().constData());
348 value = prop.enumerator().keyToValue(v->value.asString().toUtf8().constData());
351 instr.setType(QDeclarativeInstruction::StoreInteger);
352 instr.storeInteger.propertyIndex = prop.propertyIndex();
353 instr.storeInteger.value = value;
354 output->addInstruction(instr);
358 QString string = v->value.asString();
360 int type = prop.userType();
364 if (v->value.isNumber()) {
365 double n = v->value.asNumber();
366 if (double(int(n)) == n) {
367 instr.setType(QDeclarativeInstruction::StoreVariantInteger);
368 instr.storeInteger.propertyIndex = prop.propertyIndex();
369 instr.storeInteger.value = int(n);
371 instr.setType(QDeclarativeInstruction::StoreVariantDouble);
372 instr.storeDouble.propertyIndex = prop.propertyIndex();
373 instr.storeDouble.value = n;
375 } else if(v->value.isBoolean()) {
376 instr.setType(QDeclarativeInstruction::StoreVariantBool);
377 instr.storeBool.propertyIndex = prop.propertyIndex();
378 instr.storeBool.value = v->value.asBoolean();
380 instr.setType(QDeclarativeInstruction::StoreVariant);
381 instr.storeString.propertyIndex = prop.propertyIndex();
382 instr.storeString.value = output->indexForString(string);
386 case QVariant::String:
388 instr.setType(QDeclarativeInstruction::StoreString);
389 instr.storeString.propertyIndex = prop.propertyIndex();
390 instr.storeString.value = output->indexForString(string);
393 case QVariant::ByteArray:
395 instr.setType(QDeclarativeInstruction::StoreByteArray);
396 instr.storeByteArray.propertyIndex = prop.propertyIndex();
397 instr.storeByteArray.value = output->indexForByteArray(string.toLatin1());
402 instr.setType(QDeclarativeInstruction::StoreUrl);
403 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
404 instr.storeUrl.propertyIndex = prop.propertyIndex();
405 instr.storeUrl.value = output->indexForUrl(u);
410 instr.setType(QDeclarativeInstruction::StoreInteger);
411 instr.storeInteger.propertyIndex = prop.propertyIndex();
412 instr.storeInteger.value = uint(v->value.asNumber());
417 instr.setType(QDeclarativeInstruction::StoreInteger);
418 instr.storeInteger.propertyIndex = prop.propertyIndex();
419 instr.storeInteger.value = int(v->value.asNumber());
422 case QMetaType::Float:
424 instr.setType(QDeclarativeInstruction::StoreFloat);
425 instr.storeFloat.propertyIndex = prop.propertyIndex();
426 instr.storeFloat.value = float(v->value.asNumber());
429 case QVariant::Double:
431 instr.setType(QDeclarativeInstruction::StoreDouble);
432 instr.storeDouble.propertyIndex = prop.propertyIndex();
433 instr.storeDouble.value = v->value.asNumber();
436 case QVariant::Color:
438 QColor c = QDeclarativeStringConverters::colorFromString(string);
439 instr.setType(QDeclarativeInstruction::StoreColor);
440 instr.storeColor.propertyIndex = prop.propertyIndex();
441 instr.storeColor.value = c.rgba();
444 #ifndef QT_NO_DATESTRING
447 QDate d = QDeclarativeStringConverters::dateFromString(string);
448 instr.setType(QDeclarativeInstruction::StoreDate);
449 instr.storeDate.propertyIndex = prop.propertyIndex();
450 instr.storeDate.value = d.toJulianDay();
455 QTime time = QDeclarativeStringConverters::timeFromString(string);
456 instr.setType(QDeclarativeInstruction::StoreTime);
457 instr.storeTime.propertyIndex = prop.propertyIndex();
458 instr.storeTime.time = *(QDeclarativeInstruction::instr_storeTime::QTime *)&time;
461 case QVariant::DateTime:
463 QDateTime dateTime = QDeclarativeStringConverters::dateTimeFromString(string);
464 QTime time = dateTime.time();
465 instr.setType(QDeclarativeInstruction::StoreDateTime);
466 instr.storeDateTime.propertyIndex = prop.propertyIndex();
467 instr.storeDateTime.date = dateTime.date().toJulianDay();
468 instr.storeDateTime.time = *(QDeclarativeInstruction::instr_storeTime::QTime *)&time;
471 #endif // QT_NO_DATESTRING
472 case QVariant::Point:
475 QPoint point = QDeclarativeStringConverters::pointFFromString(string, &ok).toPoint();
476 instr.setType(QDeclarativeInstruction::StorePoint);
477 instr.storePoint.propertyIndex = prop.propertyIndex();
478 instr.storePoint.point.xp = point.x();
479 instr.storePoint.point.yp = point.y();
482 case QVariant::PointF:
485 QPointF point = QDeclarativeStringConverters::pointFFromString(string, &ok);
486 instr.setType(QDeclarativeInstruction::StorePointF);
487 instr.storePointF.propertyIndex = prop.propertyIndex();
488 instr.storePointF.point.xp = point.x();
489 instr.storePointF.point.yp = point.y();
495 QSize size = QDeclarativeStringConverters::sizeFFromString(string, &ok).toSize();
496 instr.setType(QDeclarativeInstruction::StoreSize);
497 instr.storeSize.propertyIndex = prop.propertyIndex();
498 instr.storeSize.size.wd = size.width();
499 instr.storeSize.size.ht = size.height();
502 case QVariant::SizeF:
505 QSizeF size = QDeclarativeStringConverters::sizeFFromString(string, &ok);
506 instr.setType(QDeclarativeInstruction::StoreSizeF);
507 instr.storeSizeF.propertyIndex = prop.propertyIndex();
508 instr.storeSizeF.size.wd = size.width();
509 instr.storeSizeF.size.ht = size.height();
515 QRect rect = QDeclarativeStringConverters::rectFFromString(string, &ok).toRect();
516 instr.setType(QDeclarativeInstruction::StoreRect);
517 instr.storeRect.propertyIndex = prop.propertyIndex();
518 instr.storeRect.rect.x1 = rect.left();
519 instr.storeRect.rect.y1 = rect.top();
520 instr.storeRect.rect.x2 = rect.right();
521 instr.storeRect.rect.y2 = rect.bottom();
524 case QVariant::RectF:
527 QRectF rect = QDeclarativeStringConverters::rectFFromString(string, &ok);
528 instr.setType(QDeclarativeInstruction::StoreRectF);
529 instr.storeRectF.propertyIndex = prop.propertyIndex();
530 instr.storeRectF.rect.xp = rect.left();
531 instr.storeRectF.rect.yp = rect.top();
532 instr.storeRectF.rect.w = rect.width();
533 instr.storeRectF.rect.h = rect.height();
538 bool b = v->value.asBoolean();
539 instr.setType(QDeclarativeInstruction::StoreBool);
540 instr.storeBool.propertyIndex = prop.propertyIndex();
541 instr.storeBool.value = b;
544 case QVariant::Vector3D:
547 QVector3D vector = QDeclarativeStringConverters::vector3DFromString(string, &ok);
548 instr.setType(QDeclarativeInstruction::StoreVector3D);
549 instr.storeVector3D.propertyIndex = prop.propertyIndex();
550 instr.storeVector3D.vector.xp = vector.x();
551 instr.storeVector3D.vector.yp = vector.y();
552 instr.storeVector3D.vector.zp = vector.z();
557 int t = prop.userType();
558 instr.setType(QDeclarativeInstruction::AssignCustomType);
559 instr.assignCustomType.propertyIndex = prop.propertyIndex();
560 instr.assignCustomType.primitive = output->indexForString(string);
561 instr.assignCustomType.type = t;
565 output->addInstruction(instr);
569 Resets data by clearing the lists that the QDeclarativeCompiler modifies.
571 void QDeclarativeCompiler::reset(QDeclarativeCompiledData *data)
574 data->primitives.clear();
576 data->bytecode.clear();
580 Compile \a unit, and store the output in \a out. \a engine is the QDeclarativeEngine
581 with which the QDeclarativeCompiledData will be associated.
583 Returns true on success, false on failure. On failure, the compile errors
584 are available from errors().
586 If the environment variant QML_COMPILER_DUMP is set
587 (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
588 on a successful compiler.
590 bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine,
591 QDeclarativeTypeData *unit,
592 QDeclarativeCompiledData *out)
602 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
603 QList<QDeclarativeScriptParser::TypeReference *> referencedTypes = unit->parser().referencedTypes();
605 for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
606 QDeclarativeCompiledData::TypeReference ref;
608 const QDeclarativeTypeData::TypeReference &tref = resolvedTypes.at(ii);
609 QDeclarativeScriptParser::TypeReference *parserRef = referencedTypes.at(ii);
612 ref.type = tref.type;
613 if (!ref.type->isCreatable()) {
614 QString err = ref.type->noCreationReason();
616 err = tr( "Element is not creatable.");
617 COMPILE_EXCEPTION(parserRef->refObjects.first(), err);
620 if (ref.type->containsRevisionedAttributes()) {
621 QDeclarativeError cacheError;
622 ref.typePropertyCache =
623 QDeclarativeEnginePrivate::get(engine)->cache(ref.type, resolvedTypes.at(ii).minorVersion, cacheError);
625 if (!ref.typePropertyCache) {
626 COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description());
628 ref.typePropertyCache->addref();
631 } else if (tref.typeData) {
632 ref.component = tref.typeData->compiledData();
634 ref.className = parserRef->name.toUtf8();
638 QDeclarativeParser::Object *root = unit->parser().tree();
641 this->engine = engine;
642 this->enginePrivate = QDeclarativeEnginePrivate::get(engine);
644 this->unitRoot = root;
649 out->dumpInstructions();
650 if (compilerStatDump())
652 Q_ASSERT(out->rootPropertyCache);
657 compileState = ComponentCompileState();
658 savedCompileStates.clear();
661 this->enginePrivate = 0;
668 void QDeclarativeCompiler::compileTree(QDeclarativeParser::Object *tree)
670 compileState.root = tree;
671 componentStat.lineNumber = tree->location.start.line;
673 // Build global import scripts
674 QStringList importedScriptIndexes;
676 foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
677 importedScriptIndexes.append(script.qualifier);
679 QDeclarativeInstruction import;
680 import.setType(QDeclarativeInstruction::StoreImportedScript);
681 import.storeScript.value = output->scripts.count();
683 QDeclarativeScriptData *scriptData = script.script->scriptData();
684 scriptData->addref();
685 output->scripts << scriptData;
686 output->addInstruction(import);
689 // We generate the importCache before we build the tree so that
690 // it can be used in the binding compiler. Given we "expect" the
691 // QML compilation to succeed, this isn't a waste.
692 output->importCache = new QDeclarativeTypeNameCache(engine);
693 for (int ii = 0; ii < importedScriptIndexes.count(); ++ii)
694 output->importCache->add(importedScriptIndexes.at(ii), ii);
695 unit->imports().populateCache(output->importCache, engine);
697 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
700 QDeclarativeInstruction init;
701 init.setType(QDeclarativeInstruction::Init);
702 init.init.bindingsSize = compileState.bindings.count();
703 init.init.parserStatusSize = compileState.parserStatusCount;
704 init.init.contextCache = genContextCache();
705 if (compileState.compiledBindingData.isEmpty())
706 init.init.compiledBinding = -1;
708 init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData);
709 output->addInstruction(init);
711 if (!compileState.v8BindingProgram.isEmpty()) {
712 QDeclarativeInstruction bindings;
713 bindings.setType(QDeclarativeInstruction::InitV8Bindings);
714 bindings.initV8Bindings.program = output->indexForString(compileState.v8BindingProgram);
715 bindings.initV8Bindings.programIndex = compileState.v8BindingProgramIndex;
716 bindings.initV8Bindings.line = compileState.v8BindingProgramLine;
717 output->addInstruction(bindings);
722 QDeclarativeInstruction def;
723 def.setType(QDeclarativeInstruction::SetDefault);
724 output->addInstruction(def);
726 QDeclarativeInstruction done;
727 done.setType(QDeclarativeInstruction::Done);
728 output->addInstruction(done);
730 Q_ASSERT(tree->metatype);
732 if (tree->metadata.isEmpty()) {
733 output->root = tree->metatype;
735 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
736 output->root = &output->rootData;
738 if (!tree->metadata.isEmpty())
739 enginePrivate->registerCompositeType(output);
742 static bool ValuePtrLessThan(const QDeclarativeParser::Value *t1, const QDeclarativeParser::Value *t2)
744 return t1->location.start.line < t2->location.start.line ||
745 (t1->location.start.line == t2->location.start.line &&
746 t1->location.start.column < t2->location.start.column);
749 bool QDeclarativeCompiler::buildObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
751 componentStat.objects++;
753 Q_ASSERT (obj->type != -1);
754 const QDeclarativeCompiledData::TypeReference &tr =
755 output->types.at(obj->type);
756 obj->metatype = tr.metaObject();
759 obj->url = tr.component->url;
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;
822 defaultProperty->listCommaPositions = obj->defaultProperty->listCommaPositions;
824 defaultProperty->values = obj->defaultProperty->values;
825 defaultProperty->values += explicitProperty->values;
826 foreach(QDeclarativeParser::Value *value, defaultProperty->values)
828 qSort(defaultProperty->values.begin(), defaultProperty->values.end(), ValuePtrLessThan);
831 defaultProperty = obj->defaultProperty;
832 defaultProperty->addref();
835 defaultProperty = obj->defaultProperty;
836 defaultProperty->addref();
840 QDeclarativeCustomParser *cp = 0;
842 cp = output->types.at(obj->type).type->customParser();
844 // Build all explicit properties specified
845 foreach(Property *prop, obj->properties) {
847 if (prop == skipProperty)
849 if (prop->name == "id")
852 bool canDefer = false;
853 if (isCustomParser) {
854 if (doesPropertyExist(prop, obj) &&
855 (!(cp->flags() & QDeclarativeCustomParser::AcceptsAttachedProperties) ||
856 !isAttachedPropertyName(prop->name))) {
857 int ids = compileState.ids.count();
858 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
859 canDefer = ids == compileState.ids.count();
861 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
864 if (isSignalPropertyName(prop->name)) {
865 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
867 int ids = compileState.ids.count();
868 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
869 canDefer = ids == compileState.ids.count();
873 if (canDefer && !deferredList.isEmpty() &&
874 deferredList.contains(QString::fromUtf8(prop->name)))
875 prop->isDeferred = true;
879 // Build the default property
880 if (defaultProperty) {
881 Property *prop = defaultProperty;
883 bool canDefer = false;
884 if (isCustomParser) {
885 if (doesPropertyExist(prop, obj)) {
886 int ids = compileState.ids.count();
887 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
888 canDefer = ids == compileState.ids.count();
890 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
893 int ids = compileState.ids.count();
894 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
895 canDefer = ids == compileState.ids.count();
898 if (canDefer && !deferredList.isEmpty() &&
899 deferredList.contains(QString::fromUtf8(prop->name)))
900 prop->isDeferred = true;
904 defaultProperty->release();
906 // Compile custom parser parts
907 if (isCustomParser && !customProps.isEmpty()) {
911 obj->custom = cp->compile(customProps);
914 foreach (QDeclarativeError err, cp->errors()) {
915 err.setUrl(output->url);
923 void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj)
925 QDeclarativeCompiledData::TypeReference &tr = output->types[obj->type];
926 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
932 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
933 !output->types.at(obj->type).type->isExtendedType() && obj != compileState.root) {
935 QDeclarativeInstruction create;
936 create.setType(QDeclarativeInstruction::CreateSimpleObject);
937 create.createSimple.create = output->types.at(obj->type).type->createFunction();
938 create.createSimple.typeSize = output->types.at(obj->type).type->createSize();
939 create.createSimple.type = obj->type;
940 create.createSimple.line = obj->location.start.line;
941 create.createSimple.column = obj->location.start.column;
942 output->addInstruction(create);
946 QDeclarativeInstruction create;
947 create.setType(QDeclarativeInstruction::CreateObject);
948 create.create.line = obj->location.start.line;
949 create.create.column = obj->location.start.column;
950 create.create.data = -1;
951 if (!obj->custom.isEmpty())
952 create.create.data = output->indexForByteArray(obj->custom);
953 create.create.type = obj->type;
954 if (!output->types.at(create.create.type).type &&
955 !obj->bindingBitmask.isEmpty()) {
956 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
957 create.create.bindingBits =
958 output->indexForByteArray(obj->bindingBitmask);
960 create.create.bindingBits = -1;
962 output->addInstruction(create);
966 // Setup the synthesized meta object if necessary
967 if (!obj->metadata.isEmpty()) {
968 QDeclarativeInstruction meta;
969 meta.setType(QDeclarativeInstruction::StoreMetaObject);
970 meta.storeMeta.data = output->indexForByteArray(obj->metadata);
971 meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata);
972 meta.storeMeta.propertyCache = output->propertyCaches.count();
974 QDeclarativePropertyCache *propertyCache = obj->synthCache;
975 Q_ASSERT(propertyCache);
976 propertyCache->addref();
978 // Add flag for alias properties
979 if (!obj->synthdata.isEmpty()) {
980 const QDeclarativeVMEMetaData *vmeMetaData =
981 reinterpret_cast<const QDeclarativeVMEMetaData *>(obj->synthdata.constData());
982 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
983 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
984 propertyCache->property(index)->flags |= QDeclarativePropertyCache::Data::IsAlias;
988 if (obj == unitRoot) {
989 propertyCache->addref();
990 output->rootPropertyCache = propertyCache;
993 output->propertyCaches << propertyCache;
994 output->addInstruction(meta);
995 } else if (obj == unitRoot) {
996 output->rootPropertyCache = tr.createPropertyCache(engine);
997 output->rootPropertyCache->addref();
1000 // Set the object id
1001 if (!obj->id.isEmpty()) {
1002 QDeclarativeInstruction id;
1003 id.setType(QDeclarativeInstruction::SetId);
1004 id.setId.value = output->indexForString(obj->id);
1005 id.setId.index = obj->idIndex;
1006 output->addInstruction(id);
1010 if (tr.type && obj->parserStatusCast != -1) {
1011 QDeclarativeInstruction begin;
1012 begin.setType(QDeclarativeInstruction::BeginObject);
1013 begin.begin.castValue = obj->parserStatusCast;
1014 output->addInstruction(begin);
1020 void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj)
1022 typedef QPair<Property *, int> PropPair;
1023 foreach(const PropPair &prop, obj->scriptStringProperties) {
1024 const QString &script = prop.first->values.at(0)->value.asScript();
1025 QDeclarativeInstruction ss;
1026 ss.setType(QDeclarativeInstruction::StoreScriptString);
1027 ss.storeScriptString.propertyIndex = prop.first->index;
1028 ss.storeScriptString.value = output->indexForString(script);
1029 ss.storeScriptString.scope = prop.second;
1030 ss.storeScriptString.bindingId = rewriteBinding(script, prop.first->name);
1031 ss.storeScriptString.line = prop.first->location.start.line;
1032 output->addInstruction(ss);
1035 bool seenDefer = false;
1036 foreach(Property *prop, obj->valueProperties) {
1037 if (prop->isDeferred) {
1042 genValueProperty(prop, obj);
1045 QDeclarativeInstruction defer;
1046 defer.setType(QDeclarativeInstruction::Defer);
1047 defer.defer.deferCount = 0;
1048 int deferIdx = output->addInstruction(defer);
1049 int nextInstructionIndex = output->nextInstructionIndex();
1051 QDeclarativeInstruction init;
1052 init.setType(QDeclarativeInstruction::Init);
1053 init.init.bindingsSize = compileState.bindings.count(); // XXX - bigger than necessary
1054 init.init.parserStatusSize = compileState.parserStatusCount; // XXX - bigger than necessary
1055 init.init.contextCache = -1;
1056 init.init.compiledBinding = -1;
1057 output->addInstruction(init);
1059 foreach(Property *prop, obj->valueProperties) {
1060 if (!prop->isDeferred)
1062 genValueProperty(prop, obj);
1065 QDeclarativeInstruction done;
1066 done.setType(QDeclarativeInstruction::Done);
1067 output->addInstruction(done);
1069 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1072 foreach(Property *prop, obj->signalProperties) {
1074 QDeclarativeParser::Value *v = prop->values.at(0);
1076 if (v->type == Value::SignalObject) {
1078 genObject(v->object);
1080 QDeclarativeInstruction assign;
1081 assign.setType(QDeclarativeInstruction::AssignSignalObject);
1082 assign.assignSignalObject.line = v->location.start.line;
1083 assign.assignSignalObject.signal =
1084 output->indexForByteArray(prop->name);
1085 output->addInstruction(assign);
1087 } else if (v->type == Value::SignalExpression) {
1089 BindingContext ctxt = compileState.signalExpressions.value(v);
1091 QDeclarativeInstruction store;
1092 store.setType(QDeclarativeInstruction::StoreSignal);
1093 store.storeSignal.signalIndex = prop->index;
1094 store.storeSignal.value =
1095 output->indexForString(v->value.asScript().trimmed());
1096 store.storeSignal.context = ctxt.stack;
1097 store.storeSignal.name = output->indexForByteArray(prop->name);
1098 store.storeSignal.line = v->location.start.line;
1099 output->addInstruction(store);
1105 foreach(Property *prop, obj->attachedProperties) {
1106 QDeclarativeInstruction fetch;
1107 fetch.setType(QDeclarativeInstruction::FetchAttached);
1108 fetch.fetchAttached.id = prop->index;
1109 fetch.fetchAttached.line = prop->location.start.line;
1110 output->addInstruction(fetch);
1112 genObjectBody(prop->value);
1114 QDeclarativeInstruction pop;
1115 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1116 output->addInstruction(pop);
1119 foreach(Property *prop, obj->groupedProperties) {
1120 QDeclarativeInstruction fetch;
1121 fetch.setType(QDeclarativeInstruction::FetchObject);
1122 fetch.fetch.property = prop->index;
1123 fetch.fetch.line = prop->location.start.line;
1124 output->addInstruction(fetch);
1126 if (!prop->value->metadata.isEmpty()) {
1127 QDeclarativeInstruction meta;
1128 meta.setType(QDeclarativeInstruction::StoreMetaObject);
1129 meta.storeMeta.data = output->indexForByteArray(prop->value->metadata);
1130 meta.storeMeta.aliasData = output->indexForByteArray(prop->value->synthdata);
1131 meta.storeMeta.propertyCache = -1;
1132 output->addInstruction(meta);
1135 genObjectBody(prop->value);
1137 QDeclarativeInstruction pop;
1138 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1139 output->addInstruction(pop);
1142 foreach(Property *prop, obj->valueTypeProperties) {
1144 genValueTypeProperty(obj, prop);
1147 foreach(Property *prop, obj->valueProperties) {
1148 if (prop->isDeferred)
1151 genValueProperty(prop, obj);
1154 foreach(Property *prop, obj->valueTypeProperties) {
1156 genValueTypeProperty(obj, prop);
1160 void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeParser::Object *obj,QDeclarativeParser::Property *prop)
1162 QDeclarativeInstruction fetch;
1163 fetch.setType(QDeclarativeInstruction::FetchValueType);
1164 fetch.fetchValue.property = prop->index;
1165 fetch.fetchValue.type = prop->type;
1166 fetch.fetchValue.bindingSkipList = 0;
1168 if (obj->type == -1 || output->types.at(obj->type).component) {
1169 // We only have to do this if this is a composite type. If it is a builtin
1170 // type it can't possibly already have bindings that need to be cleared.
1171 foreach(Property *vprop, prop->value->valueProperties) {
1172 if (!vprop->values.isEmpty()) {
1173 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1174 fetch.fetchValue.bindingSkipList |= (1 << vprop->index);
1179 output->addInstruction(fetch);
1181 foreach(Property *vprop, prop->value->valueProperties) {
1182 genPropertyAssignment(vprop, prop->value, prop);
1185 QDeclarativeInstruction pop;
1186 pop.setType(QDeclarativeInstruction::PopValueType);
1187 pop.fetchValue.property = prop->index;
1188 pop.fetchValue.type = prop->type;
1189 pop.fetchValue.bindingSkipList = 0;
1190 output->addInstruction(pop);
1193 void QDeclarativeCompiler::genComponent(QDeclarativeParser::Object *obj)
1195 QDeclarativeParser::Object *root = obj->defaultProperty->values.at(0)->object;
1198 QDeclarativeInstruction create;
1199 create.setType(QDeclarativeInstruction::CreateComponent);
1200 create.createComponent.line = root->location.start.line;
1201 create.createComponent.column = root->location.start.column;
1202 create.createComponent.endLine = root->location.end.line;
1203 int createInstruction = output->addInstruction(create);
1204 int nextInstructionIndex = output->nextInstructionIndex();
1206 ComponentCompileState oldCompileState = compileState;
1207 compileState = componentState(root);
1209 QDeclarativeInstruction init;
1210 init.setType(QDeclarativeInstruction::Init);
1211 init.init.bindingsSize = compileState.bindings.count();
1212 init.init.parserStatusSize = compileState.parserStatusCount;
1213 init.init.contextCache = genContextCache();
1214 if (compileState.compiledBindingData.isEmpty())
1215 init.init.compiledBinding = -1;
1217 init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData);
1218 output->addInstruction(init);
1220 if (!compileState.v8BindingProgram.isEmpty()) {
1221 QDeclarativeInstruction bindings;
1222 bindings.setType(QDeclarativeInstruction::InitV8Bindings);
1223 bindings.initV8Bindings.program = output->indexForString(compileState.v8BindingProgram);
1224 bindings.initV8Bindings.programIndex = compileState.v8BindingProgramIndex;
1225 bindings.initV8Bindings.line = compileState.v8BindingProgramLine;
1226 output->addInstruction(bindings);
1231 QDeclarativeInstruction def;
1232 def.setType(QDeclarativeInstruction::SetDefault);
1233 output->addInstruction(def);
1235 QDeclarativeInstruction done;
1236 done.setType(QDeclarativeInstruction::Done);
1237 output->addInstruction(done);
1239 output->instruction(createInstruction)->createComponent.count =
1240 output->nextInstructionIndex() - nextInstructionIndex;
1242 compileState = oldCompileState;
1244 if (!obj->id.isEmpty()) {
1245 QDeclarativeInstruction id;
1246 id.setType(QDeclarativeInstruction::SetId);
1247 id.setId.value = output->indexForString(obj->id);
1248 id.setId.index = obj->idIndex;
1249 output->addInstruction(id);
1252 if (obj == unitRoot) {
1253 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1254 output->rootPropertyCache->addref();
1258 bool QDeclarativeCompiler::buildComponent(QDeclarativeParser::Object *obj,
1259 const BindingContext &ctxt)
1261 // The special "Component" element can only have the id property and a
1262 // default property, that actually defines the component's tree
1264 // Find, check and set the "id" property (if any)
1265 Property *idProp = 0;
1266 if (obj->properties.count() > 1 ||
1267 (obj->properties.count() == 1 && obj->properties.begin().key() != "id"))
1268 COMPILE_EXCEPTION(*obj->properties.begin(), tr("Component elements may not contain properties other than id"));
1270 if (obj->properties.count())
1271 idProp = *obj->properties.begin();
1274 if (idProp->value || idProp->values.count() > 1 || idProp->values.at(0)->object)
1275 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1276 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1278 QString idVal = idProp->values.first()->primitive();
1280 if (compileState.ids.contains(idVal))
1281 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1287 // Check the Component tree is well formed
1288 if (obj->defaultProperty &&
1289 (obj->defaultProperty->value || obj->defaultProperty->values.count() > 1 ||
1290 (obj->defaultProperty->values.count() == 1 && !obj->defaultProperty->values.first()->object)))
1291 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1293 if (!obj->dynamicProperties.isEmpty())
1294 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1295 if (!obj->dynamicSignals.isEmpty())
1296 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1297 if (!obj->dynamicSlots.isEmpty())
1298 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1300 QDeclarativeParser::Object *root = 0;
1301 if (obj->defaultProperty && obj->defaultProperty->values.count())
1302 root = obj->defaultProperty->values.first()->object;
1305 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1307 // Build the component tree
1308 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1313 bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeParser::Object *obj,
1314 const BindingContext &ctxt)
1316 ComponentCompileState oldComponentCompileState = compileState;
1317 ComponentStat oldComponentStat = componentStat;
1319 compileState = ComponentCompileState();
1320 compileState.root = obj;
1321 compileState.nested = true;
1323 componentStat = ComponentStat();
1324 componentStat.lineNumber = obj->location.start.line;
1327 COMPILE_CHECK(buildObject(obj, ctxt));
1329 COMPILE_CHECK(completeComponentBuild());
1331 compileState = oldComponentCompileState;
1332 componentStat = oldComponentStat;
1338 // Build a sub-object. A sub-object is one that was not created directly by
1339 // QML - such as a grouped property object, or an attached object. Sub-object's
1340 // can't have an id, involve a custom parser, have attached properties etc.
1341 bool QDeclarativeCompiler::buildSubObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
1343 Q_ASSERT(obj->metatype);
1344 Q_ASSERT(!obj->defaultProperty);
1345 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1348 foreach(Property *prop, obj->properties) {
1349 if (isSignalPropertyName(prop->name)) {
1350 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1352 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1359 int QDeclarativeCompiler::componentTypeRef()
1361 QDeclarativeType *t = QDeclarativeMetaType::qmlType("QtQuick/Component",1,0);
1362 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1363 if (output->types.at(ii).type == t)
1366 QDeclarativeCompiledData::TypeReference ref;
1367 ref.className = "Component";
1369 output->types << ref;
1370 return output->types.count() - 1;
1373 bool QDeclarativeCompiler::buildSignal(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj,
1374 const BindingContext &ctxt)
1376 Q_ASSERT(obj->metaObject());
1378 QByteArray name = prop->name;
1379 Q_ASSERT(name.startsWith("on"));
1382 // Note that the property name could start with any alpha or '_' or '$' character,
1383 // so we need to do the lower-casing of the first alpha character.
1384 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1385 if (name[firstAlphaIndex] >= 'A' && name[firstAlphaIndex] <= 'Z') {
1386 name[firstAlphaIndex] = name[firstAlphaIndex] - 'A' + 'a';
1391 bool notInRevision = false;
1392 int sigIdx = indexOfSignal(obj, name, ¬InRevision);
1396 if (notInRevision && -1 == indexOfProperty(obj, prop->name, 0)) {
1397 Q_ASSERT(obj->type != -1);
1398 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1399 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1401 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));
1403 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)));
1407 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1409 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1413 if (prop->value || prop->values.count() != 1)
1414 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1416 prop->index = sigIdx;
1417 obj->addSignalProperty(prop);
1419 if (prop->values.at(0)->object) {
1420 COMPILE_CHECK(buildObject(prop->values.at(0)->object, ctxt));
1421 prop->values.at(0)->type = Value::SignalObject;
1423 prop->values.at(0)->type = Value::SignalExpression;
1425 if (!prop->values.at(0)->value.isScript())
1426 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1428 QString script = prop->values.at(0)->value.asScript().trimmed();
1429 if (script.isEmpty())
1430 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1432 compileState.signalExpressions.insert(prop->values.at(0), ctxt);
1441 Returns true if (value) property \a prop exists on obj, false otherwise.
1443 bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeParser::Property *prop,
1444 QDeclarativeParser::Object *obj)
1446 if(isAttachedPropertyName(prop->name) || prop->name == "id")
1449 const QMetaObject *mo = obj->metaObject();
1451 if (prop->isDefault) {
1452 QMetaProperty p = QDeclarativeMetaType::defaultProperty(mo);
1453 return p.name() != 0;
1455 int idx = indexOfProperty(obj, prop->name);
1456 return idx != -1 && mo->property(idx).isScriptable();
1463 bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop,
1464 QDeclarativeParser::Object *obj,
1465 const BindingContext &ctxt)
1467 if (prop->isEmpty())
1468 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1470 const QMetaObject *metaObject = obj->metaObject();
1471 Q_ASSERT(metaObject);
1473 if (isAttachedPropertyName(prop->name)) {
1474 // Setup attached property data
1476 if (ctxt.isSubContext()) {
1477 // Attached properties cannot be used on sub-objects. Sub-objects
1478 // always exist in a binding sub-context, which is what we test
1480 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1483 QDeclarativeType *type = 0;
1484 QDeclarativeImportedNamespace *typeNamespace = 0;
1485 unit->imports().resolveType(prop->name, &type, 0, 0, 0, &typeNamespace);
1487 if (typeNamespace) {
1488 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1491 } else if (!type || !type->attachedPropertiesType()) {
1492 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1496 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1498 Q_ASSERT(type->attachedPropertiesFunction());
1499 prop->index = type->attachedPropertiesId();
1500 prop->value->metatype = type->attachedPropertiesType();
1502 // Setup regular property data
1505 if (prop->isDefault) {
1506 p = QDeclarativeMetaType::defaultProperty(metaObject);
1509 prop->index = p.propertyIndex();
1510 prop->name = p.name();
1514 bool notInRevision = false;
1515 prop->index = indexOfProperty(obj, prop->name, ¬InRevision);
1516 if (prop->index == -1 && notInRevision) {
1517 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1518 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1520 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));
1522 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)));
1526 if (prop->index != -1) {
1527 p = metaObject->property(prop->index);
1530 if (!p.isScriptable()) {
1532 p = QMetaProperty();
1537 // We can't error here as the "id" property does not require a
1538 // successful index resolution
1540 prop->type = p.userType();
1542 // Check if this is an alias
1543 if (prop->index != -1 &&
1545 prop->parent->type != -1 &&
1546 output->types.at(prop->parent->type).component) {
1548 QDeclarativePropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1549 if (cache && cache->property(prop->index) &&
1550 cache->property(prop->index)->flags & QDeclarativePropertyCache::Data::IsAlias)
1551 prop->isAlias = true;
1554 if (prop->index != -1 && !prop->values.isEmpty())
1555 prop->parent->setBindingBit(prop->index);
1558 if (!prop->isDefault && prop->name == "id" && !ctxt.isSubContext()) {
1560 // The magic "id" behavior doesn't apply when "id" is resolved as a
1561 // default property or to sub-objects (which are always in binding
1563 COMPILE_CHECK(buildIdProperty(prop, obj));
1564 if (prop->type == QVariant::String &&
1565 prop->values.at(0)->value.isString())
1566 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1568 } else if (isAttachedPropertyName(prop->name)) {
1570 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1572 } else if (prop->index == -1) {
1574 if (prop->isDefault) {
1575 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1577 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1580 } else if (prop->value) {
1582 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1584 } else if (enginePrivate->isList(prop->type)) {
1586 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1588 } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) {
1590 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1594 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1601 bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
1602 QDeclarativeParser::Property *nsProp,
1603 QDeclarativeParser::Object *obj,
1604 const BindingContext &ctxt)
1607 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1609 foreach (Property *prop, nsProp->value->properties) {
1611 if (!isAttachedPropertyName(prop->name))
1612 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1614 // Setup attached property data
1616 QDeclarativeType *type = 0;
1617 unit->imports().resolveType(ns, prop->name, &type, 0, 0, 0);
1619 if (!type || !type->attachedPropertiesType())
1620 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1623 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1625 Q_ASSERT(type->attachedPropertiesFunction());
1626 prop->index = type->index();
1627 prop->value->metatype = type->attachedPropertiesType();
1629 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1635 void QDeclarativeCompiler::genValueProperty(QDeclarativeParser::Property *prop,
1636 QDeclarativeParser::Object *obj)
1638 if (enginePrivate->isList(prop->type)) {
1639 genListProperty(prop, obj);
1641 genPropertyAssignment(prop, obj);
1645 void QDeclarativeCompiler::genListProperty(QDeclarativeParser::Property *prop,
1646 QDeclarativeParser::Object *obj)
1648 int listType = enginePrivate->listType(prop->type);
1650 QDeclarativeInstruction fetch;
1651 fetch.setType(QDeclarativeInstruction::FetchQList);
1652 fetch.fetchQmlList.property = prop->index;
1653 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1654 fetch.fetchQmlList.type = listType;
1655 output->addInstruction(fetch);
1657 for (int ii = 0; ii < prop->values.count(); ++ii) {
1658 QDeclarativeParser::Value *v = prop->values.at(ii);
1660 if (v->type == Value::CreatedObject) {
1662 genObject(v->object);
1663 if (listTypeIsInterface) {
1664 QDeclarativeInstruction assign;
1665 assign.setType(QDeclarativeInstruction::AssignObjectList);
1666 assign.assignObjectList.line = prop->location.start.line;
1667 output->addInstruction(assign);
1669 QDeclarativeInstruction store;
1670 store.setType(QDeclarativeInstruction::StoreObjectQList);
1671 output->addInstruction(store);
1674 } else if (v->type == Value::PropertyBinding) {
1676 genBindingAssignment(v, prop, obj);
1682 QDeclarativeInstruction pop;
1683 pop.setType(QDeclarativeInstruction::PopQList);
1684 output->addInstruction(pop);
1687 void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *prop,
1688 QDeclarativeParser::Object *obj,
1689 QDeclarativeParser::Property *valueTypeProperty)
1691 for (int ii = 0; ii < prop->values.count(); ++ii) {
1692 QDeclarativeParser::Value *v = prop->values.at(ii);
1694 Q_ASSERT(v->type == Value::CreatedObject ||
1695 v->type == Value::PropertyBinding ||
1696 v->type == Value::Literal);
1698 if (v->type == Value::CreatedObject) {
1700 genObject(v->object);
1702 if (QDeclarativeMetaType::isInterface(prop->type)) {
1704 QDeclarativeInstruction store;
1705 store.setType(QDeclarativeInstruction::StoreInterface);
1706 store.storeObject.line = v->object->location.start.line;
1707 store.storeObject.propertyIndex = prop->index;
1708 output->addInstruction(store);
1710 } else if (prop->type == -1) {
1712 QDeclarativeInstruction store;
1713 store.setType(QDeclarativeInstruction::StoreVariantObject);
1714 store.storeObject.line = v->object->location.start.line;
1715 store.storeObject.propertyIndex = prop->index;
1716 output->addInstruction(store);
1720 QDeclarativeInstruction store;
1721 store.setType(QDeclarativeInstruction::StoreObject);
1722 store.storeObject.line = v->object->location.start.line;
1723 store.storeObject.propertyIndex = prop->index;
1724 output->addInstruction(store);
1727 } else if (v->type == Value::PropertyBinding) {
1729 genBindingAssignment(v, prop, obj, valueTypeProperty);
1731 } else if (v->type == Value::Literal) {
1733 QMetaProperty mp = obj->metaObject()->property(prop->index);
1734 genLiteralAssignment(mp, v);
1740 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
1742 QDeclarativeParser::Value *v = prop->onValues.at(ii);
1744 Q_ASSERT(v->type == Value::ValueSource ||
1745 v->type == Value::ValueInterceptor);
1747 if (v->type == Value::ValueSource) {
1748 genObject(v->object);
1750 QDeclarativeInstruction store;
1751 store.setType(QDeclarativeInstruction::StoreValueSource);
1752 if (valueTypeProperty) {
1753 store.assignValueSource.property = genValueTypeData(prop, valueTypeProperty);
1754 store.assignValueSource.owner = 1;
1756 store.assignValueSource.property = genPropertyData(prop);
1757 store.assignValueSource.owner = 0;
1759 QDeclarativeType *valueType = toQmlType(v->object);
1760 store.assignValueSource.castValue = valueType->propertyValueSourceCast();
1761 output->addInstruction(store);
1763 } else if (v->type == Value::ValueInterceptor) {
1764 genObject(v->object);
1766 QDeclarativeInstruction store;
1767 store.setType(QDeclarativeInstruction::StoreValueInterceptor);
1768 if (valueTypeProperty) {
1769 store.assignValueInterceptor.property = genValueTypeData(prop, valueTypeProperty);
1770 store.assignValueInterceptor.owner = 1;
1772 store.assignValueInterceptor.property = genPropertyData(prop);
1773 store.assignValueInterceptor.owner = 0;
1775 QDeclarativeType *valueType = toQmlType(v->object);
1776 store.assignValueInterceptor.castValue = valueType->propertyValueInterceptorCast();
1777 output->addInstruction(store);
1783 bool QDeclarativeCompiler::buildIdProperty(QDeclarativeParser::Property *prop,
1784 QDeclarativeParser::Object *obj)
1787 prop->values.count() > 1 ||
1788 prop->values.at(0)->object)
1789 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
1791 QDeclarativeParser::Value *idValue = prop->values.at(0);
1792 QString val = idValue->primitive();
1794 COMPILE_CHECK(checkValidId(idValue, val));
1796 if (compileState.ids.contains(val))
1797 COMPILE_EXCEPTION(prop, tr("id is not unique"));
1799 prop->values.at(0)->type = Value::Id;
1807 void QDeclarativeCompiler::addId(const QString &id, QDeclarativeParser::Object *obj)
1809 Q_ASSERT(!compileState.ids.contains(id));
1810 Q_ASSERT(obj->id == id);
1811 obj->idIndex = compileState.ids.count();
1812 compileState.ids.insert(id, obj);
1813 compileState.idIndexes.insert(obj->idIndex, obj);
1816 void QDeclarativeCompiler::addBindingReference(const BindingReference &ref)
1818 Q_ASSERT(ref.value && !compileState.bindings.contains(ref.value));
1819 compileState.bindings.insert(ref.value, ref);
1822 void QDeclarativeCompiler::saveComponentState()
1824 Q_ASSERT(compileState.root);
1825 Q_ASSERT(!savedCompileStates.contains(compileState.root));
1827 savedCompileStates.insert(compileState.root, compileState);
1828 savedComponentStats.append(componentStat);
1831 QDeclarativeCompiler::ComponentCompileState
1832 QDeclarativeCompiler::componentState(QDeclarativeParser::Object *obj)
1834 Q_ASSERT(savedCompileStates.contains(obj));
1835 return savedCompileStates.value(obj);
1838 // Build attached property object. In this example,
1842 // GridView is an attached property object.
1843 bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeParser::Property *prop,
1844 QDeclarativeParser::Object *obj,
1845 const BindingContext &ctxt)
1847 Q_ASSERT(prop->value);
1848 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
1850 obj->addAttachedProperty(prop);
1852 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1858 // Build "grouped" properties. In this example:
1860 // font.pointSize: 12
1861 // font.family: "Helvetica"
1863 // font is a nested property. pointSize and family are not.
1864 bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeParser::Property *prop,
1865 QDeclarativeParser::Object *obj,
1866 const BindingContext &ctxt)
1868 Q_ASSERT(prop->type != 0);
1869 Q_ASSERT(prop->index != -1);
1871 if (QDeclarativeValueTypeFactory::isValueType(prop->type)) {
1872 if (prop->type >= 0 /* QVariant == -1 */ && enginePrivate->valueTypes[prop->type]) {
1874 if (prop->values.count()) {
1875 if (prop->values.at(0)->location < prop->value->location) {
1876 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
1878 COMPILE_EXCEPTION(prop->values.at(0), tr( "Property has already been assigned a value"));
1882 if (!obj->metaObject()->property(prop->index).isWritable()) {
1883 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
1887 if (prop->isAlias) {
1888 foreach (Property *vtProp, prop->value->properties)
1889 vtProp->isAlias = true;
1892 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
1893 prop->value, obj, ctxt.incr()));
1894 obj->addValueTypeProperty(prop);
1896 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1900 // Load the nested property's meta type
1901 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
1902 if (!prop->value->metatype)
1903 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1905 if (prop->values.count())
1906 COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign a value directly to a grouped property"));
1908 obj->addGroupedProperty(prop);
1910 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1916 bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
1917 QDeclarativeParser::Object *obj,
1918 QDeclarativeParser::Object *baseObj,
1919 const BindingContext &ctxt)
1921 if (obj->defaultProperty)
1922 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
1923 obj->metatype = type->metaObject();
1925 foreach (Property *prop, obj->properties) {
1926 int idx = type->metaObject()->indexOfProperty(prop->name.constData());
1928 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1929 QMetaProperty p = type->metaObject()->property(idx);
1930 if (!p.isScriptable())
1931 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1933 prop->type = p.userType();
1934 prop->isValueTypeSubProperty = true;
1937 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
1939 if (prop->values.count() > 1) {
1940 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
1941 } else if (prop->values.count()) {
1942 QDeclarativeParser::Value *value = prop->values.at(0);
1944 if (value->object) {
1945 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
1946 } else if (value->value.isScript()) {
1947 // ### Check for writability
1949 //optimization for <Type>.<EnumValue> enum assignments
1950 bool isEnumAssignment = false;
1951 COMPILE_CHECK(testQualifiedEnumAssignment(p, obj, value, &isEnumAssignment));
1952 if (isEnumAssignment) {
1953 value->type = Value::Literal;
1955 BindingReference reference;
1956 reference.expression = value->value;
1957 reference.property = prop;
1958 reference.value = value;
1959 reference.bindingContext = ctxt;
1960 reference.bindingContext.owner++;
1961 addBindingReference(reference);
1962 value->type = Value::PropertyBinding;
1965 COMPILE_CHECK(testLiteralAssignment(p, value));
1966 value->type = Value::Literal;
1970 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
1971 QDeclarativeParser::Value *v = prop->onValues.at(ii);
1972 Q_ASSERT(v->object);
1974 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
1977 obj->addValueProperty(prop);
1983 // Build assignments to QML lists. QML lists are properties of type
1984 // QDeclarativeListProperty<T>. List properties can accept a list of
1985 // objects, or a single binding.
1986 bool QDeclarativeCompiler::buildListProperty(QDeclarativeParser::Property *prop,
1987 QDeclarativeParser::Object *obj,
1988 const BindingContext &ctxt)
1990 Q_ASSERT(enginePrivate->isList(prop->type));
1994 obj->addValueProperty(prop);
1996 int listType = enginePrivate->listType(t);
1997 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1999 bool assignedBinding = false;
2000 for (int ii = 0; ii < prop->values.count(); ++ii) {
2001 QDeclarativeParser::Value *v = prop->values.at(ii);
2003 v->type = Value::CreatedObject;
2004 COMPILE_CHECK(buildObject(v->object, ctxt));
2006 // We check object coercian here. We check interface assignment
2008 if (!listTypeIsInterface) {
2009 if (!canCoerce(listType, v->object)) {
2010 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2014 } else if (v->value.isScript()) {
2015 if (assignedBinding)
2016 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2018 assignedBinding = true;
2019 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2020 v->type = Value::PropertyBinding;
2022 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2029 // Compiles an assignment to a QDeclarativeScriptString property
2030 bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeParser::Property *prop,
2031 QDeclarativeParser::Object *obj,
2032 const BindingContext &ctxt)
2034 if (prop->values.count() > 1)
2035 COMPILE_EXCEPTION(prop->values.at(1), tr( "Cannot assign multiple values to a script property"));
2037 if (prop->values.at(0)->object)
2038 COMPILE_EXCEPTION(prop->values.at(0), tr( "Invalid property assignment: script expected"));
2040 obj->addScriptStringProperty(prop, ctxt.stack);
2045 // Compile regular property assignments of the form "property: <value>"
2046 bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeParser::Property *prop,
2047 QDeclarativeParser::Object *obj,
2048 const BindingContext &ctxt)
2050 obj->addValueProperty(prop);
2052 if (prop->values.count() > 1)
2053 COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign multiple values to a singular property") );
2055 for (int ii = 0; ii < prop->values.count(); ++ii) {
2056 QDeclarativeParser::Value *v = prop->values.at(ii);
2059 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2063 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2068 for (int ii = 0; ii < prop->onValues.count(); ++ii) {
2069 QDeclarativeParser::Value *v = prop->onValues.at(ii);
2071 Q_ASSERT(v->object);
2072 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2078 // Compile assigning a single object instance to a regular property
2079 bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeParser::Property *prop,
2080 QDeclarativeParser::Object *obj,
2081 QDeclarativeParser::Value *v,
2082 const BindingContext &ctxt)
2084 Q_ASSERT(prop->index != -1);
2085 Q_ASSERT(v->object->type != -1);
2087 if (!obj->metaObject()->property(prop->index).isWritable())
2088 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2090 if (QDeclarativeMetaType::isInterface(prop->type)) {
2092 // Assigning an object to an interface ptr property
2093 COMPILE_CHECK(buildObject(v->object, ctxt));
2095 v->type = Value::CreatedObject;
2097 } else if (prop->type == -1) {
2099 // Assigning an object to a QVariant
2100 COMPILE_CHECK(buildObject(v->object, ctxt));
2102 v->type = Value::CreatedObject;
2104 // Normally buildObject() will set this up, but we need the static
2105 // meta object earlier to test for assignability. It doesn't matter
2106 // that there may still be outstanding synthesized meta object changes
2107 // on this type, as they are not relevant for assignability testing
2108 v->object->metatype = output->types.at(v->object->type).metaObject();
2109 Q_ASSERT(v->object->metaObject());
2111 // We want to raw metaObject here as the raw metaobject is the
2112 // actual property type before we applied any extensions that might
2113 // effect the properties on the type, but don't effect assignability
2114 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2116 // Will be true if the assgned type inherits propertyMetaObject
2117 bool isAssignable = false;
2118 // Determine isAssignable value
2119 if (propertyMetaObject) {
2120 const QMetaObject *c = v->object->metatype;
2122 isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject));
2123 c = c->superClass();
2128 // Simple assignment
2129 COMPILE_CHECK(buildObject(v->object, ctxt));
2131 v->type = Value::CreatedObject;
2132 } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) {
2133 // Automatic "Component" insertion
2134 QDeclarativeParser::Object *root = v->object;
2135 QDeclarativeParser::Object *component = new QDeclarativeParser::Object;
2136 component->type = componentTypeRef();
2137 component->typeName = "Qt/Component";
2138 component->metatype = &QDeclarativeComponent::staticMetaObject;
2139 component->location = root->location;
2140 QDeclarativeParser::Value *componentValue = new QDeclarativeParser::Value;
2141 componentValue->object = root;
2142 component->getDefaultProperty()->addValue(componentValue);
2143 v->object = component;
2144 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2146 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2153 // Compile assigning a single object instance to a regular property using the "on" syntax.
2157 // NumberAnimation on x { }
2159 bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeParser::Property *prop,
2160 QDeclarativeParser::Object *obj,
2161 QDeclarativeParser::Object *baseObj,
2162 QDeclarativeParser::Value *v,
2163 const BindingContext &ctxt)
2165 Q_ASSERT(prop->index != -1);
2166 Q_ASSERT(v->object->type != -1);
2168 if (!obj->metaObject()->property(prop->index).isWritable())
2169 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2172 // Normally buildObject() will set this up, but we need the static
2173 // meta object earlier to test for assignability. It doesn't matter
2174 // that there may still be outstanding synthesized meta object changes
2175 // on this type, as they are not relevant for assignability testing
2176 v->object->metatype = output->types.at(v->object->type).metaObject();
2177 Q_ASSERT(v->object->metaObject());
2179 // Will be true if the assigned type inherits QDeclarativePropertyValueSource
2180 bool isPropertyValue = false;
2181 // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor
2182 bool isPropertyInterceptor = false;
2183 if (QDeclarativeType *valueType = toQmlType(v->object)) {
2184 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2185 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2188 if (isPropertyValue || isPropertyInterceptor) {
2189 // Assign as a property value source
2190 COMPILE_CHECK(buildObject(v->object, ctxt));
2192 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2193 buildDynamicMeta(baseObj, ForceCreation);
2194 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2196 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(QString::fromUtf8(v->object->typeName)).arg(QString::fromUtf8(prop->name.constData())));
2202 // Compile assigning a literal or binding to a regular property
2203 bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeParser::Property *prop,
2204 QDeclarativeParser::Object *obj,
2205 QDeclarativeParser::Value *v,
2206 const BindingContext &ctxt)
2208 Q_ASSERT(prop->index != -1);
2210 if (v->value.isScript()) {
2212 //optimization for <Type>.<EnumValue> enum assignments
2213 bool isEnumAssignment = false;
2214 COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj, v, &isEnumAssignment));
2215 if (isEnumAssignment) {
2216 v->type = Value::Literal;
2220 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2222 v->type = Value::PropertyBinding;
2226 COMPILE_CHECK(testLiteralAssignment(obj->metaObject()->property(prop->index), v));
2228 v->type = Value::Literal;
2234 bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop,
2235 QDeclarativeParser::Object *obj,
2236 QDeclarativeParser::Value *v,
2239 *isAssignment = false;
2240 if (!prop.isEnumType())
2243 if (!prop.isWritable())
2244 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
2246 QString string = v->value.asString();
2247 if (!string.at(0).isUpper())
2250 QStringList parts = string.split(QLatin1Char('.'));
2251 if (parts.count() != 2)
2254 QString typeName = parts.at(0);
2255 QDeclarativeType *type = 0;
2256 unit->imports().resolveType(typeName.toUtf8(), &type, 0, 0, 0, 0);
2258 //handle enums on value types (where obj->typeName is empty)
2259 QByteArray objTypeName = obj->typeName;
2260 if (objTypeName.isEmpty()) {
2261 QDeclarativeType *objType = toQmlType(obj);
2263 objTypeName = objType->qmlTypeName();
2269 QString enumValue = parts.at(1);
2272 if (objTypeName == type->qmlTypeName()) {
2273 // When these two match, we can short cut the search
2274 if (prop.isFlagType()) {
2275 value = prop.enumerator().keysToValue(enumValue.toUtf8().constData());
2277 value = prop.enumerator().keyToValue(enumValue.toUtf8().constData());
2280 // Otherwise we have to search the whole type
2281 // This matches the logic in QV8TypeWrapper
2282 QByteArray enumName = enumValue.toUtf8();
2283 const QMetaObject *metaObject = type->baseMetaObject();
2284 for (int ii = metaObject->enumeratorCount() - 1; value == -1 && ii >= 0; --ii) {
2285 QMetaEnum e = metaObject->enumerator(ii);
2286 value = e.keyToValue(enumName.constData());
2293 v->type = Value::Literal;
2294 v->value = QDeclarativeParser::Variant((double)value);
2295 *isAssignment = true;
2300 // Similar logic to above, but not knowing target property.
2301 int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const
2303 int dot = script.indexOf('.');
2305 QDeclarativeType *type = 0;
2306 unit->imports().resolveType(script.left(dot), &type, 0, 0, 0, 0);
2309 const QMetaObject *mo = type->metaObject();
2310 const char *key = script.constData() + dot+1;
2311 int i = mo->enumeratorCount();
2313 int v = mo->enumerator(i).keyToValue(key);
2321 const QMetaObject *QDeclarativeCompiler::resolveType(const QByteArray& name) const
2323 QDeclarativeType *qmltype = 0;
2324 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2328 return qmltype->metaObject();
2331 // similar to logic of completeComponentBuild, but also sticks data
2332 // into primitives at the end
2333 int QDeclarativeCompiler::rewriteBinding(const QString& expression, const QByteArray& name)
2335 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2336 rewriteBinding.setName('$' + name.mid(name.lastIndexOf('.') + 1));
2338 QString rewrite = rewriteBinding(expression, 0, 0);
2340 return output->indexForString(rewrite);
2343 // Ensures that the dynamic meta specification on obj is valid
2344 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj)
2346 QSet<QByteArray> propNames;
2347 QSet<QByteArray> methodNames;
2348 bool seenDefaultProperty = false;
2351 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2352 const QDeclarativeParser::Object::DynamicProperty &prop =
2353 obj->dynamicProperties.at(ii);
2355 if (prop.isDefaultProperty) {
2356 if (seenDefaultProperty)
2357 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2358 seenDefaultProperty = true;
2361 if (propNames.contains(prop.name))
2362 COMPILE_EXCEPTION(&prop, tr("Duplicate property name"));
2364 QString propName = QString::fromUtf8(prop.name);
2365 if (propName.at(0).isUpper())
2366 COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
2368 if (enginePrivate->v8engine.illegalNames().contains(propName))
2369 COMPILE_EXCEPTION(&prop, tr("Illegal property name"));
2371 propNames.insert(prop.name);
2374 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2375 QByteArray name = obj->dynamicSignals.at(ii).name;
2376 if (methodNames.contains(name))
2377 COMPILE_EXCEPTION(obj, tr("Duplicate signal name"));
2378 QString nameStr = QString::fromUtf8(name);
2379 if (nameStr.at(0).isUpper())
2380 COMPILE_EXCEPTION(obj, tr("Signal names cannot begin with an upper case letter"));
2381 if (enginePrivate->v8engine.illegalNames().contains(nameStr))
2382 COMPILE_EXCEPTION(obj, tr("Illegal signal name"));
2383 methodNames.insert(name);
2385 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2386 QByteArray name = obj->dynamicSlots.at(ii).name;
2387 if (methodNames.contains(name))
2388 COMPILE_EXCEPTION(obj, tr("Duplicate method name"));
2389 QString nameStr = QString::fromUtf8(name);
2390 if (nameStr.at(0).isUpper())
2391 COMPILE_EXCEPTION(obj, tr("Method names cannot begin with an upper case letter"));
2392 if (enginePrivate->v8engine.illegalNames().contains(nameStr))
2393 COMPILE_EXCEPTION(obj, tr("Illegal method name"));
2394 methodNames.insert(name);
2400 bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeParser::Object *obj)
2402 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2403 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2405 if (!p.defaultValue || p.type == Object::DynamicProperty::Alias)
2408 Property *property = 0;
2409 if (p.isDefaultProperty) {
2410 property = obj->getDefaultProperty();
2412 property = obj->getProperty(p.name);
2413 if (!property->values.isEmpty())
2414 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2417 if (property->value)
2418 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2420 for (int ii = 0; ii < p.defaultValue->values.count(); ++ii) {
2421 QDeclarativeParser::Value *v = p.defaultValue->values.at(ii);
2423 property->values.append(v);
2429 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2431 bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, DynamicMetaMode mode)
2434 Q_ASSERT(obj->metatype);
2436 if (mode != ForceCreation &&
2437 obj->dynamicProperties.isEmpty() &&
2438 obj->dynamicSignals.isEmpty() &&
2439 obj->dynamicSlots.isEmpty())
2442 QByteArray dynamicData(sizeof(QDeclarativeVMEMetaData), (char)0);
2444 QByteArray newClassName = obj->metatype->className();
2445 newClassName.append("_QML_");
2446 int idx = classIndexCounter()->fetchAndAddRelaxed(1);
2447 newClassName.append(QByteArray::number(idx));
2448 if (compileState.root == obj && !compileState.nested) {
2449 QString path = output->url.path();
2450 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2451 if (lastSlash > -1) {
2452 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2453 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2454 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(idx);
2458 QMetaObjectBuilder builder;
2459 builder.setClassName(newClassName);
2460 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
2462 bool hasAlias = false;
2463 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2464 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2466 int propIdx = obj->metaObject()->indexOfProperty(p.name.constData());
2467 if (-1 != propIdx) {
2468 QMetaProperty prop = obj->metaObject()->property(propIdx);
2470 COMPILE_EXCEPTION(&p, tr("Cannot override FINAL property"));
2473 if (p.isDefaultProperty &&
2474 (p.type != Object::DynamicProperty::Alias ||
2475 mode == ResolveAliases))
2476 builder.addClassInfo("DefaultProperty", p.name);
2479 int propertyType = 0;
2480 bool readonly = false;
2482 case Object::DynamicProperty::Alias:
2486 case Object::DynamicProperty::CustomList:
2487 case Object::DynamicProperty::Custom:
2489 QByteArray customTypeName;
2490 QDeclarativeType *qmltype = 0;
2492 if (!unit->imports().resolveType(p.customType, &qmltype, &url, 0, 0, 0))
2493 COMPILE_EXCEPTION(&p, tr("Invalid property type"));
2496 QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(url);
2498 Q_ASSERT(tdata->isComplete());
2500 QDeclarativeCompiledData *data = tdata->compiledData();
2501 customTypeName = data->root->className();
2505 customTypeName = qmltype->typeName();
2508 if (p.type == Object::DynamicProperty::Custom) {
2509 type = customTypeName + '*';
2510 propertyType = QMetaType::QObjectStar;
2513 type = "QDeclarativeListProperty<";
2514 type.append(customTypeName);
2516 propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
2520 case Object::DynamicProperty::Variant:
2524 case Object::DynamicProperty::Int:
2525 propertyType = QVariant::Int;
2528 case Object::DynamicProperty::Bool:
2529 propertyType = QVariant::Bool;
2532 case Object::DynamicProperty::Real:
2533 propertyType = QVariant::Double;
2536 case Object::DynamicProperty::String:
2537 propertyType = QVariant::String;
2540 case Object::DynamicProperty::Url:
2541 propertyType = QVariant::Url;
2544 case Object::DynamicProperty::Color:
2545 propertyType = QVariant::Color;
2548 case Object::DynamicProperty::Time:
2549 propertyType = QVariant::Time;
2552 case Object::DynamicProperty::Date:
2553 propertyType = QVariant::Date;
2556 case Object::DynamicProperty::DateTime:
2557 propertyType = QVariant::DateTime;
2562 ((QDeclarativeVMEMetaData *)dynamicData.data())->propertyCount++;
2563 QDeclarativeVMEMetaData::PropertyData propertyData = { propertyType };
2564 dynamicData.append((char *)&propertyData, sizeof(propertyData));
2566 builder.addSignal(p.name + "Changed()");
2567 QMetaPropertyBuilder propBuilder =
2568 builder.addProperty(p.name, type, builder.methodCount() - 1);
2569 propBuilder.setWritable(!readonly);
2572 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2573 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2575 if (p.type == Object::DynamicProperty::Alias) {
2576 if (mode == ResolveAliases) {
2577 ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++;
2578 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, p));
2580 // Need a fake signal so that the metaobject remains consistent across
2581 // the resolve and non-resolve alias runs
2582 builder.addSignal(p.name + "Changed()");
2587 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2588 const Object::DynamicSignal &s = obj->dynamicSignals.at(ii);
2589 QByteArray sig(s.name + '(');
2590 for (int jj = 0; jj < s.parameterTypes.count(); ++jj) {
2591 if (jj) sig.append(',');
2592 sig.append(s.parameterTypes.at(jj));
2595 QMetaMethodBuilder b = builder.addSignal(sig);
2596 b.setParameterNames(s.parameterNames);
2597 ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++;
2600 QStringList funcScripts;
2602 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2603 Object::DynamicSlot &s = obj->dynamicSlots[ii];
2604 QByteArray sig(s.name + '(');
2605 QString funcScript(QLatin1String("(function ") + s.name + QLatin1Char('('));
2607 for (int jj = 0; jj < s.parameterNames.count(); ++jj) {
2610 funcScript.append(QLatin1Char(','));
2612 funcScript.append(QLatin1String(s.parameterNames.at(jj)));
2613 sig.append("QVariant");
2616 funcScript.append(QLatin1Char(')'));
2617 funcScript.append(s.body);
2618 funcScript.append(QLatin1Char(')'));
2619 funcScripts << funcScript;
2621 QMetaMethodBuilder b = builder.addSlot(sig);
2622 b.setReturnType("QVariant");
2623 b.setParameterNames(s.parameterNames);
2625 ((QDeclarativeVMEMetaData *)dynamicData.data())->methodCount++;
2626 QDeclarativeVMEMetaData::MethodData methodData =
2627 { s.parameterNames.count(), 0, funcScript.length(), s.location.start.line };
2629 dynamicData.append((char *)&methodData, sizeof(methodData));
2632 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2633 const QString &funcScript = funcScripts.at(ii);
2634 QDeclarativeVMEMetaData::MethodData *data =
2635 ((QDeclarativeVMEMetaData *)dynamicData.data())->methodData() + ii;
2637 data->bodyOffset = dynamicData.size();
2639 dynamicData.append((const char *)funcScript.constData(),
2640 (funcScript.length() * sizeof(QChar)));
2643 obj->metadata = builder.toRelocatableData();
2644 builder.fromRelocatableData(&obj->extObject, obj->metatype, obj->metadata);
2646 if (mode == IgnoreAliases && hasAlias)
2647 compileState.aliasingObjects << obj;
2649 obj->synthdata = dynamicData;
2651 if (obj->synthCache) {
2652 obj->synthCache->release();
2653 obj->synthCache = 0;
2656 if (obj->type != -1) {
2657 QDeclarativePropertyCache *cache = output->types[obj->type].createPropertyCache(engine)->copy();
2658 cache->append(engine, &obj->extObject, QDeclarativePropertyCache::Data::NoFlags,
2659 QDeclarativePropertyCache::Data::IsVMEFunction,
2660 QDeclarativePropertyCache::Data::IsVMESignal);
2661 obj->synthCache = cache;
2667 bool QDeclarativeCompiler::checkValidId(QDeclarativeParser::Value *v, const QString &val)
2670 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
2672 if (val.at(0).isLetter() && !val.at(0).isLower())
2673 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
2675 QChar u(QLatin1Char('_'));
2676 for (int ii = 0; ii < val.count(); ++ii) {
2678 if (ii == 0 && !val.at(ii).isLetter() && val.at(ii) != u) {
2679 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
2680 } else if (ii != 0 && !val.at(ii).isLetterOrNumber() && val.at(ii) != u) {
2681 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
2686 if (enginePrivate->v8engine.illegalNames().contains(val))
2687 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
2692 #include <qdeclarativejsparser_p.h>
2694 static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node)
2696 if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) {
2698 static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name->asString();
2699 return QStringList() << name;
2700 } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) {
2701 QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node);
2703 QStringList rv = astNodeToStringList(expr->base);
2706 rv.append(expr->name->asString());
2709 return QStringList();
2712 bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder,
2714 QDeclarativeParser::Object *obj,
2715 const Object::DynamicProperty &prop)
2717 if (!prop.defaultValue)
2718 COMPILE_EXCEPTION(obj, tr("No property alias location"));
2720 if (prop.defaultValue->values.count() != 1 ||
2721 prop.defaultValue->values.at(0)->object ||
2722 !prop.defaultValue->values.at(0)->value.isScript())
2723 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2725 QDeclarativeJS::AST::Node *node = prop.defaultValue->values.at(0)->value.asAST();
2727 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
2729 QStringList alias = astNodeToStringList(node);
2731 if (alias.count() < 1 || alias.count() > 3)
2732 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
2734 if (!compileState.ids.contains(alias.at(0)))
2735 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
2737 QDeclarativeParser::Object *idObject = compileState.ids[alias.at(0)];
2739 QByteArray typeName;
2743 bool writable = false;
2744 if (alias.count() == 2 || alias.count() == 3) {
2745 propIdx = indexOfProperty(idObject, alias.at(1).toUtf8());
2747 if (-1 == propIdx) {
2748 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2749 } else if (propIdx > 0xFFFF) {
2750 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
2753 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
2754 if (!aliasProperty.isScriptable())
2755 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2757 writable = aliasProperty.isWritable();
2759 if (alias.count() == 3) {
2760 QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
2762 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2764 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
2766 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
2767 if (valueTypeIndex == -1)
2768 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2769 Q_ASSERT(valueTypeIndex <= 0xFF);
2771 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
2772 propIdx |= (valueTypeIndex << 16);
2775 if (aliasProperty.isEnumType())
2776 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
2778 typeName = aliasProperty.typeName();
2780 typeName = idObject->metaObject()->className();
2782 //use the base type since it has been registered with metatype system
2783 int index = typeName.indexOf("_QML_");
2785 typeName = typeName.left(index);
2787 index = typeName.indexOf("_QMLTYPE_");
2788 const QMetaObject *mo = idObject->metaObject();
2789 while (index != -1 && mo) {
2790 typeName = mo->superClass()->className();
2791 index = typeName.indexOf("_QMLTYPE_");
2792 mo = mo->superClass();
2799 if (typeName.endsWith('*'))
2800 flags |= QML_ALIAS_FLAG_PTR;
2802 data.append((const char *)&idObject->idIndex, sizeof(idObject->idIndex));
2803 data.append((const char *)&propIdx, sizeof(propIdx));
2804 data.append((const char *)&flags, sizeof(flags));
2806 builder.addSignal(prop.name + "Changed()");
2807 QMetaPropertyBuilder propBuilder =
2808 builder.addProperty(prop.name, typeName.constData(), builder.methodCount() - 1);
2809 propBuilder.setWritable(writable);
2813 bool QDeclarativeCompiler::buildBinding(QDeclarativeParser::Value *value,
2814 QDeclarativeParser::Property *prop,
2815 const BindingContext &ctxt)
2817 Q_ASSERT(prop->index != -1);
2818 Q_ASSERT(prop->parent);
2819 Q_ASSERT(prop->parent->metaObject());
2821 QMetaProperty mp = prop->parent->metaObject()->property(prop->index);
2822 if (!mp.isWritable() && !QDeclarativeMetaType::isList(prop->type))
2823 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2825 BindingReference reference;
2826 reference.expression = value->value;
2827 reference.property = prop;
2828 reference.value = value;
2829 reference.bindingContext = ctxt;
2830 addBindingReference(reference);
2835 void QDeclarativeCompiler::genBindingAssignment(QDeclarativeParser::Value *binding,
2836 QDeclarativeParser::Property *prop,
2837 QDeclarativeParser::Object *obj,
2838 QDeclarativeParser::Property *valueTypeProperty)
2841 Q_ASSERT(compileState.bindings.contains(binding));
2843 const BindingReference &ref = compileState.bindings.value(binding);
2844 if (ref.dataType == BindingReference::V4) {
2845 QDeclarativeInstruction store;
2846 store.setType(QDeclarativeInstruction::StoreV4Binding);
2847 store.assignBinding.value = ref.compiledIndex;
2848 store.assignBinding.context = ref.bindingContext.stack;
2849 store.assignBinding.owner = ref.bindingContext.owner;
2850 if (valueTypeProperty)
2851 store.assignBinding.property = (valueTypeProperty->index & 0xFFFF) |
2852 ((valueTypeProperty->type & 0xFF)) << 16 |
2853 ((prop->index & 0xFF) << 24);
2855 store.assignBinding.property = prop->index;
2856 store.assignBinding.line = binding->location.start.line;
2857 output->addInstruction(store);
2858 } else if (ref.dataType == BindingReference::V8) {
2859 QDeclarativeInstruction store;
2860 store.setType(QDeclarativeInstruction::StoreV8Binding);
2861 store.assignBinding.value = ref.compiledIndex;
2862 store.assignBinding.context = ref.bindingContext.stack;
2863 store.assignBinding.owner = ref.bindingContext.owner;
2864 store.assignBinding.line = binding->location.start.line;
2866 Q_ASSERT(ref.bindingContext.owner == 0 ||
2867 (ref.bindingContext.owner != 0 && valueTypeProperty));
2868 if (ref.bindingContext.owner) {
2869 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
2871 store.assignBinding.property = genPropertyData(prop);
2874 output->addInstruction(store);
2876 QDeclarativeInstruction store;
2878 store.setType(QDeclarativeInstruction::StoreBinding);
2880 store.setType(QDeclarativeInstruction::StoreBindingOnAlias);
2881 store.assignBinding.value = output->indexForString(ref.rewrittenExpression);
2882 store.assignBinding.context = ref.bindingContext.stack;
2883 store.assignBinding.owner = ref.bindingContext.owner;
2884 store.assignBinding.line = binding->location.start.line;
2886 Q_ASSERT(ref.bindingContext.owner == 0 ||
2887 (ref.bindingContext.owner != 0 && valueTypeProperty));
2888 if (ref.bindingContext.owner) {
2889 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
2891 store.assignBinding.property = genPropertyData(prop);
2893 output->addInstruction(store);
2897 int QDeclarativeCompiler::genContextCache()
2899 if (compileState.ids.count() == 0)
2902 QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache();
2904 for (QHash<QString, QDeclarativeParser::Object *>::ConstIterator iter = compileState.ids.begin();
2905 iter != compileState.ids.end();
2907 cache->add(iter.key(), (*iter)->idIndex);
2909 output->contextCaches.append(cache);
2910 return output->contextCaches.count() - 1;
2913 int QDeclarativeCompiler::genValueTypeData(QDeclarativeParser::Property *valueTypeProp,
2914 QDeclarativeParser::Property *prop)
2917 QDeclarativePropertyPrivate::saveValueType(prop->parent->metaObject(), prop->index,
2918 enginePrivate->valueTypes[prop->type]->metaObject(),
2919 valueTypeProp->index);
2920 // valueTypeProp->index, valueTypeProp->type);
2922 return output->indexForByteArray(data);
2925 int QDeclarativeCompiler::genPropertyData(QDeclarativeParser::Property *prop)
2927 return output->indexForByteArray(QDeclarativePropertyPrivate::saveProperty(prop->parent->metaObject(), prop->index));
2930 bool QDeclarativeCompiler::completeComponentBuild()
2932 componentStat.ids = compileState.ids.count();
2934 for (int ii = 0; ii < compileState.aliasingObjects.count(); ++ii) {
2935 QDeclarativeParser::Object *aliasObject = compileState.aliasingObjects.at(ii);
2936 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
2939 QDeclarativeV4Compiler::Expression expr;
2940 expr.component = compileState.root;
2941 expr.ids = compileState.ids;
2942 expr.importCache = output->importCache;
2943 expr.imports = unit->imports();
2945 QDeclarativeV4Compiler bindingCompiler;
2947 QList<BindingReference*> sharedBindings;
2949 for (QHash<QDeclarativeParser::Value*,BindingReference>::Iterator iter = compileState.bindings.begin();
2950 iter != compileState.bindings.end(); ++iter) {
2952 BindingReference &binding = *iter;
2954 // ### We don't currently optimize for bindings on alias's - because
2955 // of the solution to QTBUG-13719
2956 if (!binding.property->isAlias) {
2957 expr.context = binding.bindingContext.object;
2958 expr.property = binding.property;
2959 expr.expression = binding.expression;
2961 int index = bindingCompiler.compile(expr, enginePrivate);
2963 binding.dataType = BindingReference::V4;
2964 binding.compiledIndex = index;
2965 componentStat.optimizedBindings.append(iter.key()->location);
2970 // Pre-rewrite the expression
2971 QString expression = binding.expression.asScript();
2973 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2974 rewriteBinding.setName('$'+binding.property->name);
2975 bool isSharable = false;
2976 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
2978 if (isSharable && !binding.property->isAlias /* See above re alias */ &&
2979 binding.property->type != qMetaTypeId<QDeclarativeBinding*>()) {
2980 binding.dataType = BindingReference::V8;
2981 sharedBindings.append(&iter.value());
2983 binding.dataType = BindingReference::QtScript;
2986 componentStat.scriptBindings.append(iter.key()->location);
2989 if (!sharedBindings.isEmpty()) {
2991 static bool lt(const BindingReference *lhs, const BindingReference *rhs)
2993 return lhs->value->location.start.line < rhs->value->location.start.line;
2997 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
2999 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3000 int lineNumber = startLineNumber;
3002 QString functionArray(QLatin1String("["));
3003 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3004 BindingReference *reference = sharedBindings.at(ii);
3005 QDeclarativeParser::Value *value = reference->value;
3006 const QString &expression = reference->rewrittenExpression;
3008 if (ii != 0) functionArray += QLatin1String(",");
3010 while (lineNumber < value->location.start.line) {
3012 functionArray += QLatin1String("\n");
3015 functionArray += expression;
3016 reference->compiledIndex = ii;
3018 functionArray += QLatin1String("]");
3020 compileState.v8BindingProgram = functionArray;
3021 compileState.v8BindingProgramLine = startLineNumber;
3022 compileState.v8BindingProgramIndex = output->v8bindings.count();
3023 output->v8bindings.append(v8::Persistent<v8::Array>());
3026 if (bindingCompiler.isValid())
3027 compileState.compiledBindingData = bindingCompiler.program();
3029 saveComponentState();
3034 void QDeclarativeCompiler::dumpStats()
3036 qWarning().nospace() << "QML Document: " << output->url.toString();
3037 for (int ii = 0; ii < savedComponentStats.count(); ++ii) {
3038 const ComponentStat &stat = savedComponentStats.at(ii);
3039 qWarning().nospace() << " Component Line " << stat.lineNumber;
3040 qWarning().nospace() << " Total Objects: " << stat.objects;
3041 qWarning().nospace() << " IDs Used: " << stat.ids;
3042 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3046 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3047 if (0 == (ii % 10)) {
3048 if (ii) output.append("\n");
3053 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3055 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3056 output.append(") ");
3058 if (!output.isEmpty())
3059 qWarning().nospace() << output.constData();
3062 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3065 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3066 if (0 == (ii % 10)) {
3067 if (ii) output.append("\n");
3072 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3074 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3075 output.append(") ");
3077 if (!output.isEmpty())
3078 qWarning().nospace() << output.constData();
3084 Returns true if from can be assigned to a (QObject) property of type
3087 bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeParser::Object *from)
3089 const QMetaObject *toMo =
3090 enginePrivate->rawMetaObjectForType(to);
3091 const QMetaObject *fromMo = from->metaObject();
3094 if (QDeclarativePropertyPrivate::equal(fromMo, toMo))
3096 fromMo = fromMo->superClass();
3101 QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeParser::Object *from)
3104 const QMetaObject *mo = from->metatype;
3105 QDeclarativeType *type = 0;
3106 while (!type && mo) {
3107 type = QDeclarativeMetaType::qmlType(mo);
3108 mo = mo->superClass();
3113 QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeParser::Object *obj)
3115 const QMetaObject *mo = obj->metatype;
3117 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3119 return QStringList();
3121 QMetaClassInfo classInfo = mo->classInfo(idx);
3122 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3126 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3127 int QDeclarativeCompiler::indexOfSignal(QDeclarativeParser::Object *object, const QByteArray &name,
3128 bool *notInRevision)
3130 if (notInRevision) *notInRevision = false;
3132 if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) {
3134 QString strName(QString::fromUtf8(name));
3135 QDeclarativePropertyCache *cache =
3136 object->synthCache?object->synthCache:output->types.at(object->type).propertyCache();
3138 QDeclarativePropertyCache::Data *d = cache->property(strName);
3139 if (notInRevision) *notInRevision = false;
3141 while (d && !(d->flags & QDeclarativePropertyCache::Data::IsFunction))
3142 d = cache->overrideData(d);
3144 if (d && !cache->isAllowedInRevision(d)) {
3145 if (notInRevision) *notInRevision = true;
3148 return d->coreIndex;
3151 if (name.endsWith("Changed")) {
3152 QByteArray propName = name.mid(0, name.length() - 7);
3154 int propIndex = indexOfProperty(object, propName, notInRevision);
3155 if (propIndex != -1) {
3156 d = cache->property(propIndex);
3157 return d->notifyIndex;
3163 return QDeclarativePropertyPrivate::findSignalByName(object->metaObject(), name).methodIndex();
3168 int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QByteArray &name,
3169 bool *notInRevision)
3171 if (notInRevision) *notInRevision = false;
3173 if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) {
3175 QString strName(QString::fromUtf8(name));
3176 QDeclarativePropertyCache *cache =
3177 object->synthCache?object->synthCache:output->types.at(object->type).propertyCache();
3179 QDeclarativePropertyCache::Data *d = cache->property(strName);
3180 // Find the first property
3181 while (d && d->flags & QDeclarativePropertyCache::Data::IsFunction)
3182 d = cache->overrideData(d);
3184 if (d && !cache->isAllowedInRevision(d)) {
3185 if (notInRevision) *notInRevision = true;
3188 return d?d->coreIndex:-1;
3191 const QMetaObject *mo = object->metaObject();
3192 return mo->indexOfProperty(name.constData());