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;
83 using namespace QDeclarativeCompilerTypes;
85 static QString id_string(QLatin1String("id"));
86 static QString on_string(QLatin1String("on"));
87 static QString Changed_string(QLatin1String("Changed"));
88 static QString Component_string(QLatin1String("Component"));
91 Instantiate a new QDeclarativeCompiler.
93 QDeclarativeCompiler::QDeclarativeCompiler(QDeclarativePool *pool)
94 : pool(pool), output(0), engine(0), unitRoot(0), unit(0), componentStats(0)
96 if (compilerStatDump())
97 componentStats = pool->New<ComponentStats>();
101 Returns true if the last call to compile() caused errors.
105 bool QDeclarativeCompiler::isError() const
107 return !exceptions.isEmpty();
111 Return the list of errors from the last call to compile(), or an empty list
112 if there were no errors.
114 QList<QDeclarativeError> QDeclarativeCompiler::errors() const
120 Returns true if \a name refers to an attached property, false otherwise.
122 Attached property names are those that start with a capital letter.
124 bool QDeclarativeCompiler::isAttachedPropertyName(const QString &name)
126 return isAttachedPropertyName(QStringRef(&name));
129 bool QDeclarativeCompiler::isAttachedPropertyName(const QStringRef &name)
131 return !name.isEmpty() && name.at(0) >= 'A' && name.at(0) <= 'Z';
135 Returns true if \a name refers to a signal property, false otherwise.
137 Signal property names are those that start with "on", followed by a first
138 character which is either a capital letter or one or more underscores followed
139 by a capital letter, which is then followed by other allowed characters.
141 Note that although ECMA-262r3 supports dollarsigns and escaped unicode
142 character codes in property names, for simplicity and performance reasons
143 QML only supports letters, numbers and underscores.
145 bool QDeclarativeCompiler::isSignalPropertyName(const QString &name)
147 return isSignalPropertyName(QStringRef(&name));
150 bool QDeclarativeCompiler::isSignalPropertyName(const QStringRef &name)
152 if (name.length() < 3) return false;
153 if (!name.startsWith(on_string)) return false;
154 int ns = name.size();
155 for (int i = 2; i < ns; ++i) {
156 QChar curr = name.at(i);
157 if (curr == QLatin1Char('_')) continue;
158 if (curr >= QLatin1Char('A') && curr <= QLatin1Char('Z')) return true;
161 return false; // consists solely of underscores - invalid.
165 \macro COMPILE_EXCEPTION
167 Inserts an error into the QDeclarativeCompiler error list, and returns false
170 \a token is used to source the error line and column, and \a desc is the
171 error itself. \a desc can be an expression that can be piped into QDebug.
176 COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(property->name));
179 #define COMPILE_EXCEPTION(token, desc) \
181 QString exceptionDescription; \
182 QDeclarativeError error; \
183 error.setUrl(output->url); \
184 error.setLine((token)->location.start.line); \
185 error.setColumn((token)->location.start.column); \
186 error.setDescription(desc.trimmed()); \
187 exceptions << error; \
194 Returns false if \a is false, otherwise does nothing.
196 #define COMPILE_CHECK(a) \
198 if (!a) return false; \
202 Returns true if literal \a v can be assigned to property \a prop, otherwise
205 This test corresponds to action taken by genLiteralAssignment(). Any change
206 made here, must have a corresponding action in genLiteralAssigment().
208 bool QDeclarativeCompiler::testLiteralAssignment(QDeclarativeParser::Property *prop,
209 QDeclarativeParser::Value *v)
211 const QDeclarativeParser::Variant &value = v->value;
213 if (!prop->core.isWritable())
214 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
216 if (prop->core.isEnum()) {
217 QMetaProperty p = prop->parent->metaObject()->property(prop->index);
219 if (p.isFlagType()) {
220 enumValue = p.enumerator().keysToValue(value.asString().toUtf8().constData());
222 enumValue = p.enumerator().keyToValue(value.asString().toUtf8().constData());
225 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration"));
227 v->value = QDeclarativeParser::Variant((double)enumValue);
231 int type = prop->type;
234 case QMetaType::QVariant:
236 case QVariant::String:
237 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
239 case QVariant::ByteArray:
240 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected"));
243 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected"));
247 bool ok = v->value.isNumber();
249 double n = v->value.asNumber();
250 if (double(uint(n)) != n)
253 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected"));
258 bool ok = v->value.isNumber();
260 double n = v->value.asNumber();
261 if (double(int(n)) != n)
264 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected"));
267 case QMetaType::Float:
268 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
270 case QVariant::Double:
271 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
273 case QVariant::Color:
276 QDeclarativeStringConverters::colorFromString(value.asString(), &ok);
277 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected"));
280 #ifndef QT_NO_DATESTRING
284 QDeclarativeStringConverters::dateFromString(value.asString(), &ok);
285 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected"));
291 QDeclarativeStringConverters::timeFromString(value.asString(), &ok);
292 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected"));
295 case QVariant::DateTime:
298 QDeclarativeStringConverters::dateTimeFromString(value.asString(), &ok);
299 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected"));
302 #endif // QT_NO_DATESTRING
303 case QVariant::Point:
304 case QVariant::PointF:
307 QPointF point = QDeclarativeStringConverters::pointFFromString(value.asString(), &ok);
308 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected"));
312 case QVariant::SizeF:
315 QSizeF size = QDeclarativeStringConverters::sizeFFromString(value.asString(), &ok);
316 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected"));
320 case QVariant::RectF:
323 QRectF rect = QDeclarativeStringConverters::rectFFromString(value.asString(), &ok);
324 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected"));
329 if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected"));
332 case QVariant::Vector3D:
335 QDeclarativeStringConverters::vector3DFromString(value.asString(), &ok);
336 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected"));
339 case QVariant::Vector4D:
342 QDeclarativeStringConverters::vector4DFromString(string, &ok);
343 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 4D vector expected"));
348 QDeclarativeMetaType::StringConverter converter = QDeclarativeMetaType::customStringConverter(type);
350 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName((QVariant::Type)type))));
358 Generate a store instruction for assigning literal \a v to property \a prop.
360 Any literal assignment that is approved in testLiteralAssignment() must have
361 a corresponding action in this method.
363 void QDeclarativeCompiler::genLiteralAssignment(QDeclarativeParser::Property *prop,
364 QDeclarativeParser::Value *v)
366 QDeclarativeInstruction instr;
368 if (prop->core.isEnum()) {
369 Q_ASSERT(v->value.isNumber());
371 int value = (int)v->value.asNumber();
373 instr.setType(QDeclarativeInstruction::StoreInteger);
374 instr.storeInteger.propertyIndex = prop->index;
375 instr.storeInteger.value = value;
376 output->addInstruction(instr);
380 int type = prop->type;
382 case QMetaType::QVariant:
384 if (v->value.isNumber()) {
385 double n = v->value.asNumber();
386 if (double(int(n)) == n) {
387 instr.setType(QDeclarativeInstruction::StoreVariantInteger);
388 instr.storeInteger.propertyIndex = prop->index;
389 instr.storeInteger.value = int(n);
391 instr.setType(QDeclarativeInstruction::StoreVariantDouble);
392 instr.storeDouble.propertyIndex = prop->index;
393 instr.storeDouble.value = n;
395 } else if(v->value.isBoolean()) {
396 instr.setType(QDeclarativeInstruction::StoreVariantBool);
397 instr.storeBool.propertyIndex = prop->index;
398 instr.storeBool.value = v->value.asBoolean();
400 instr.setType(QDeclarativeInstruction::StoreVariant);
401 instr.storeString.propertyIndex = prop->index;
402 instr.storeString.value = output->indexForString(v->value.asString());
406 case QVariant::String:
408 instr.setType(QDeclarativeInstruction::StoreString);
409 instr.storeString.propertyIndex = prop->index;
410 instr.storeString.value = output->indexForString(v->value.asString());
413 case QVariant::ByteArray:
415 instr.setType(QDeclarativeInstruction::StoreByteArray);
416 instr.storeByteArray.propertyIndex = prop->index;
417 instr.storeByteArray.value = output->indexForByteArray(v->value.asString().toLatin1());
422 instr.setType(QDeclarativeInstruction::StoreUrl);
423 QString string = v->value.asString();
424 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
425 instr.storeUrl.propertyIndex = prop->index;
426 instr.storeUrl.value = output->indexForUrl(u);
431 instr.setType(QDeclarativeInstruction::StoreInteger);
432 instr.storeInteger.propertyIndex = prop->index;
433 instr.storeInteger.value = uint(v->value.asNumber());
438 instr.setType(QDeclarativeInstruction::StoreInteger);
439 instr.storeInteger.propertyIndex = prop->index;
440 instr.storeInteger.value = int(v->value.asNumber());
443 case QMetaType::Float:
445 instr.setType(QDeclarativeInstruction::StoreFloat);
446 instr.storeFloat.propertyIndex = prop->index;
447 instr.storeFloat.value = float(v->value.asNumber());
450 case QVariant::Double:
452 instr.setType(QDeclarativeInstruction::StoreDouble);
453 instr.storeDouble.propertyIndex = prop->index;
454 instr.storeDouble.value = v->value.asNumber();
457 case QVariant::Color:
459 QColor c = QDeclarativeStringConverters::colorFromString(v->value.asString());
460 instr.setType(QDeclarativeInstruction::StoreColor);
461 instr.storeColor.propertyIndex = prop->index;
462 instr.storeColor.value = c.rgba();
465 #ifndef QT_NO_DATESTRING
468 QDate d = QDeclarativeStringConverters::dateFromString(v->value.asString());
469 instr.setType(QDeclarativeInstruction::StoreDate);
470 instr.storeDate.propertyIndex = prop->index;
471 instr.storeDate.value = d.toJulianDay();
476 QTime time = QDeclarativeStringConverters::timeFromString(v->value.asString());
477 instr.setType(QDeclarativeInstruction::StoreTime);
478 instr.storeTime.propertyIndex = prop->index;
479 Q_ASSERT(sizeof(instr.storeTime.time) == sizeof(QTime));
480 ::memcpy(&instr.storeTime.time, &time, sizeof(QTime)); }
483 case QVariant::DateTime:
485 QDateTime dateTime = QDeclarativeStringConverters::dateTimeFromString(v->value.asString());
486 QTime time = dateTime.time();
487 instr.setType(QDeclarativeInstruction::StoreDateTime);
488 instr.storeDateTime.propertyIndex = prop->index;
489 instr.storeDateTime.date = dateTime.date().toJulianDay();
490 Q_ASSERT(sizeof(instr.storeDateTime.time) == sizeof(QTime));
491 ::memcpy(&instr.storeDateTime.time, &time, sizeof(QTime));
494 #endif // QT_NO_DATESTRING
495 case QVariant::Point:
498 QPoint point = QDeclarativeStringConverters::pointFFromString(v->value.asString(), &ok).toPoint();
499 instr.setType(QDeclarativeInstruction::StorePoint);
500 instr.storePoint.propertyIndex = prop->index;
501 instr.storePoint.point.xp = point.x();
502 instr.storePoint.point.yp = point.y();
505 case QVariant::PointF:
508 QPointF point = QDeclarativeStringConverters::pointFFromString(v->value.asString(), &ok);
509 instr.setType(QDeclarativeInstruction::StorePointF);
510 instr.storePointF.propertyIndex = prop->index;
511 instr.storePointF.point.xp = point.x();
512 instr.storePointF.point.yp = point.y();
518 QSize size = QDeclarativeStringConverters::sizeFFromString(v->value.asString(), &ok).toSize();
519 instr.setType(QDeclarativeInstruction::StoreSize);
520 instr.storeSize.propertyIndex = prop->index;
521 instr.storeSize.size.wd = size.width();
522 instr.storeSize.size.ht = size.height();
525 case QVariant::SizeF:
528 QSizeF size = QDeclarativeStringConverters::sizeFFromString(v->value.asString(), &ok);
529 instr.setType(QDeclarativeInstruction::StoreSizeF);
530 instr.storeSizeF.propertyIndex = prop->index;
531 instr.storeSizeF.size.wd = size.width();
532 instr.storeSizeF.size.ht = size.height();
538 QRect rect = QDeclarativeStringConverters::rectFFromString(v->value.asString(), &ok).toRect();
539 instr.setType(QDeclarativeInstruction::StoreRect);
540 instr.storeRect.propertyIndex = prop->index;
541 instr.storeRect.rect.x1 = rect.left();
542 instr.storeRect.rect.y1 = rect.top();
543 instr.storeRect.rect.x2 = rect.right();
544 instr.storeRect.rect.y2 = rect.bottom();
547 case QVariant::RectF:
550 QRectF rect = QDeclarativeStringConverters::rectFFromString(v->value.asString(), &ok);
551 instr.setType(QDeclarativeInstruction::StoreRectF);
552 instr.storeRectF.propertyIndex = prop->index;
553 instr.storeRectF.rect.xp = rect.left();
554 instr.storeRectF.rect.yp = rect.top();
555 instr.storeRectF.rect.w = rect.width();
556 instr.storeRectF.rect.h = rect.height();
561 bool b = v->value.asBoolean();
562 instr.setType(QDeclarativeInstruction::StoreBool);
563 instr.storeBool.propertyIndex = prop->index;
564 instr.storeBool.value = b;
567 case QVariant::Vector3D:
570 QVector3D vector = QDeclarativeStringConverters::vector3DFromString(v->value.asString(), &ok);
571 instr.setType(QDeclarativeInstruction::StoreVector3D);
572 instr.storeVector3D.propertyIndex = prop->index;
573 instr.storeVector3D.vector.xp = vector.x();
574 instr.storeVector3D.vector.yp = vector.y();
575 instr.storeVector3D.vector.zp = vector.z();
578 case QVariant::Vector4D:
581 QVector4D vector = QDeclarativeStringConverters::vector4DFromString(string, &ok);
582 instr.setType(QDeclarativeInstruction::StoreVector4D);
583 instr.storeVector4D.propertyIndex = prop.propertyIndex();
584 instr.storeVector4D.vector.xp = vector.x();
585 instr.storeVector4D.vector.yp = vector.y();
586 instr.storeVector4D.vector.zp = vector.z();
587 instr.storeVector4D.vector.wp = vector.w();
592 instr.setType(QDeclarativeInstruction::AssignCustomType);
593 instr.assignCustomType.propertyIndex = prop->index;
594 instr.assignCustomType.primitive = output->indexForString(v->value.asString());
595 instr.assignCustomType.type = type;
599 output->addInstruction(instr);
603 Resets data by clearing the lists that the QDeclarativeCompiler modifies.
605 void QDeclarativeCompiler::reset(QDeclarativeCompiledData *data)
608 data->primitives.clear();
610 data->bytecode.resize(0);
614 Compile \a unit, and store the output in \a out. \a engine is the QDeclarativeEngine
615 with which the QDeclarativeCompiledData will be associated.
617 Returns true on success, false on failure. On failure, the compile errors
618 are available from errors().
620 If the environment variant QML_COMPILER_DUMP is set
621 (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
622 on a successful compiler.
624 bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine,
625 QDeclarativeTypeData *unit,
626 QDeclarativeCompiledData *out)
636 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
637 QList<QDeclarativeScriptParser::TypeReference *> referencedTypes = unit->parser().referencedTypes();
639 for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
640 QDeclarativeCompiledData::TypeReference ref;
642 const QDeclarativeTypeData::TypeReference &tref = resolvedTypes.at(ii);
643 QDeclarativeScriptParser::TypeReference *parserRef = referencedTypes.at(ii);
646 ref.type = tref.type;
647 if (!ref.type->isCreatable()) {
648 QString err = ref.type->noCreationReason();
650 err = tr( "Element is not creatable.");
651 COMPILE_EXCEPTION(parserRef->refObjects.first(), err);
654 if (ref.type->containsRevisionedAttributes()) {
655 QDeclarativeError cacheError;
656 ref.typePropertyCache =
657 QDeclarativeEnginePrivate::get(engine)->cache(ref.type, resolvedTypes.at(ii).minorVersion, cacheError);
659 if (!ref.typePropertyCache) {
660 COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description());
662 ref.typePropertyCache->addref();
665 } else if (tref.typeData) {
666 ref.component = tref.typeData->compiledData();
668 ref.className = parserRef->name;
672 QDeclarativeParser::Object *root = unit->parser().tree();
675 this->engine = engine;
676 this->enginePrivate = QDeclarativeEnginePrivate::get(engine);
678 this->unitRoot = root;
683 out->dumpInstructions();
686 Q_ASSERT(out->rootPropertyCache);
694 this->enginePrivate = 0;
701 void QDeclarativeCompiler::compileTree(QDeclarativeParser::Object *tree)
703 compileState = pool->New<ComponentCompileState>();
705 compileState->root = tree;
707 componentStats->componentStat.lineNumber = tree->location.start.line;
709 // Build global import scripts
710 QStringList importedScriptIndexes;
712 foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
713 importedScriptIndexes.append(script.qualifier);
715 QDeclarativeInstruction import;
716 import.setType(QDeclarativeInstruction::StoreImportedScript);
717 import.storeScript.value = output->scripts.count();
719 QDeclarativeScriptData *scriptData = script.script->scriptData();
720 scriptData->addref();
721 output->scripts << scriptData;
722 output->addInstruction(import);
725 // We generate the importCache before we build the tree so that
726 // it can be used in the binding compiler. Given we "expect" the
727 // QML compilation to succeed, this isn't a waste.
728 output->importCache = new QDeclarativeTypeNameCache(engine);
729 for (int ii = 0; ii < importedScriptIndexes.count(); ++ii)
730 output->importCache->add(importedScriptIndexes.at(ii), ii);
731 unit->imports().populateCache(output->importCache, engine);
733 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
736 QDeclarativeInstruction init;
737 init.setType(QDeclarativeInstruction::Init);
738 init.init.bindingsSize = compileState->bindings.count();
739 init.init.parserStatusSize = compileState->parserStatusCount;
740 init.init.contextCache = genContextCache();
741 if (compileState->compiledBindingData.isEmpty())
742 init.init.compiledBinding = -1;
744 init.init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
745 output->addInstruction(init);
747 if (!compileState->v8BindingProgram.isEmpty()) {
748 QDeclarativeInstruction bindings;
749 bindings.setType(QDeclarativeInstruction::InitV8Bindings);
750 bindings.initV8Bindings.program = output->indexForString(compileState->v8BindingProgram);
751 bindings.initV8Bindings.programIndex = compileState->v8BindingProgramIndex;
752 bindings.initV8Bindings.line = compileState->v8BindingProgramLine;
753 output->addInstruction(bindings);
758 QDeclarativeInstruction def;
759 def.setType(QDeclarativeInstruction::SetDefault);
760 output->addInstruction(def);
762 QDeclarativeInstruction done;
763 done.setType(QDeclarativeInstruction::Done);
764 output->addInstruction(done);
766 Q_ASSERT(tree->metatype);
768 if (tree->metadata.isEmpty()) {
769 output->root = tree->metatype;
771 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
772 output->root = &output->rootData;
774 if (!tree->metadata.isEmpty())
775 enginePrivate->registerCompositeType(output);
778 static bool QStringList_contains(const QStringList &list, const QStringRef &string)
780 for (int ii = 0; ii < list.count(); ++ii)
781 if (list.at(ii) == string)
787 bool QDeclarativeCompiler::buildObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
790 componentStats->componentStat.objects++;
792 Q_ASSERT (obj->type != -1);
793 const QDeclarativeCompiledData::TypeReference &tr =
794 output->types.at(obj->type);
795 obj->metatype = tr.metaObject();
798 obj->typeName = tr.type->qmlTypeName();
800 // This object is a "Component" element
801 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
802 COMPILE_CHECK(buildComponent(obj, ctxt));
806 // Object instantiations reset the binding context
807 BindingContext objCtxt(obj);
809 // Create the synthesized meta object, ignoring aliases
810 COMPILE_CHECK(checkDynamicMeta(obj));
811 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
812 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
814 // Find the native type and check for the QDeclarativeParserStatus interface
815 QDeclarativeType *type = toQmlType(obj);
817 obj->parserStatusCast = type->parserStatusCast();
818 if (obj->parserStatusCast != -1)
819 compileState->parserStatusCount++;
821 // Check if this is a custom parser type. Custom parser types allow
822 // assignments to non-existent properties. These assignments are then
823 // compiled by the type.
824 bool isCustomParser = output->types.at(obj->type).type &&
825 output->types.at(obj->type).type->customParser() != 0;
826 QList<QDeclarativeCustomParserProperty> customProps;
828 // Fetch the list of deferred properties
829 QStringList deferredList = deferredProperties(obj);
831 // Must do id property first. This is to ensure that the id given to any
832 // id reference created matches the order in which the objects are
834 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
835 if (prop->name() == id_string) {
836 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
842 Property *defaultProperty = 0;
843 Property *skipProperty = 0;
844 if (obj->defaultProperty) {
845 defaultProperty = obj->defaultProperty;
847 const QMetaObject *metaObject = obj->metaObject();
848 Q_ASSERT(metaObject);
849 QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
851 Property *explicitProperty = obj->getProperty(QString::fromUtf8(p.name()), false);
852 if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) {
854 skipProperty = explicitProperty; // We merge the values into defaultProperty
856 // Find the correct insertion point
857 Value *insertPos = 0;
859 for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) {
860 if (!(v->location.start < explicitProperty->values.first()->location.start))
865 defaultProperty->values.insertAfter(insertPos, explicitProperty->values);
871 QDeclarativeCustomParser *cp = 0;
873 cp = output->types.at(obj->type).type->customParser();
875 // Build all explicit properties specified
876 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
878 if (prop == skipProperty)
880 if (prop->name() == id_string)
883 bool canDefer = false;
884 if (isCustomParser) {
885 if (doesPropertyExist(prop, obj) &&
886 (!(cp->flags() & QDeclarativeCustomParser::AcceptsAttachedProperties) ||
887 !isAttachedPropertyName(prop->name()))) {
888 int ids = compileState->ids.count();
889 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
890 canDefer = ids == compileState->ids.count();
891 } else if (isSignalPropertyName(prop->name()) &&
892 (cp->flags() & QDeclarativeCustomParser::AcceptsSignalHandlers)) {
893 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
895 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
898 if (isSignalPropertyName(prop->name())) {
899 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
901 int ids = compileState->ids.count();
902 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
903 canDefer = ids == compileState->ids.count();
907 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
908 prop->isDeferred = true;
912 // Build the default property
913 if (defaultProperty) {
914 Property *prop = defaultProperty;
916 bool canDefer = false;
917 if (isCustomParser) {
918 if (doesPropertyExist(prop, obj)) {
919 int ids = compileState->ids.count();
920 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
921 canDefer = ids == compileState->ids.count();
923 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
926 int ids = compileState->ids.count();
927 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
928 canDefer = ids == compileState->ids.count();
931 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
932 prop->isDeferred = true;
935 // Compile custom parser parts
936 if (isCustomParser && !customProps.isEmpty()) {
940 obj->custom = cp->compile(customProps);
943 foreach (QDeclarativeError err, cp->errors()) {
944 err.setUrl(output->url);
952 void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj)
954 QDeclarativeCompiledData::TypeReference &tr = output->types[obj->type];
955 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
961 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
962 !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) {
964 QDeclarativeInstruction create;
965 create.setType(QDeclarativeInstruction::CreateSimpleObject);
966 create.createSimple.create = output->types.at(obj->type).type->createFunction();
967 create.createSimple.typeSize = output->types.at(obj->type).type->createSize();
968 create.createSimple.type = obj->type;
969 create.createSimple.line = obj->location.start.line;
970 create.createSimple.column = obj->location.start.column;
971 output->addInstruction(create);
975 QDeclarativeInstruction create;
976 create.setType(QDeclarativeInstruction::CreateObject);
977 create.create.line = obj->location.start.line;
978 create.create.column = obj->location.start.column;
979 create.create.data = -1;
980 if (!obj->custom.isEmpty())
981 create.create.data = output->indexForByteArray(obj->custom);
982 create.create.type = obj->type;
983 if (!output->types.at(create.create.type).type &&
984 !obj->bindingBitmask.isEmpty()) {
985 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
986 create.create.bindingBits =
987 output->indexForByteArray(obj->bindingBitmask);
989 create.create.bindingBits = -1;
991 output->addInstruction(create);
995 // Setup the synthesized meta object if necessary
996 if (!obj->metadata.isEmpty()) {
997 QDeclarativeInstruction meta;
998 meta.setType(QDeclarativeInstruction::StoreMetaObject);
999 meta.storeMeta.data = output->indexForByteArray(obj->metadata);
1000 meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata);
1001 meta.storeMeta.propertyCache = output->propertyCaches.count();
1003 QDeclarativePropertyCache *propertyCache = obj->synthCache;
1004 Q_ASSERT(propertyCache);
1005 propertyCache->addref();
1007 // Add flag for alias properties
1008 if (!obj->synthdata.isEmpty()) {
1009 const QDeclarativeVMEMetaData *vmeMetaData =
1010 reinterpret_cast<const QDeclarativeVMEMetaData *>(obj->synthdata.constData());
1011 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
1012 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
1013 QDeclarativePropertyCache::Data *data = propertyCache->property(index);
1014 data->setFlags(data->getFlags() | QDeclarativePropertyCache::Data::IsAlias);
1018 if (obj == unitRoot) {
1019 propertyCache->addref();
1020 output->rootPropertyCache = propertyCache;
1023 output->propertyCaches << propertyCache;
1024 output->addInstruction(meta);
1025 } else if (obj == unitRoot) {
1026 output->rootPropertyCache = tr.createPropertyCache(engine);
1027 output->rootPropertyCache->addref();
1030 // Set the object id
1031 if (!obj->id.isEmpty()) {
1032 QDeclarativeInstruction id;
1033 id.setType(QDeclarativeInstruction::SetId);
1034 id.setId.value = output->indexForString(obj->id);
1035 id.setId.index = obj->idIndex;
1036 output->addInstruction(id);
1040 if (tr.type && obj->parserStatusCast != -1) {
1041 QDeclarativeInstruction begin;
1042 begin.setType(QDeclarativeInstruction::BeginObject);
1043 begin.begin.castValue = obj->parserStatusCast;
1044 output->addInstruction(begin);
1050 void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj)
1052 for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1053 Q_ASSERT(prop->scriptStringScope != -1);
1054 const QString &script = prop->values.first()->value.asScript();
1055 QDeclarativeInstruction ss;
1056 ss.setType(QDeclarativeInstruction::StoreScriptString);
1057 ss.storeScriptString.propertyIndex = prop->index;
1058 ss.storeScriptString.value = output->indexForString(script);
1059 ss.storeScriptString.scope = prop->scriptStringScope;
1060 // ss.storeScriptString.bindingId = rewriteBinding(script, prop->name());
1061 ss.storeScriptString.bindingId = rewriteBinding(script, QString()); // XXX
1062 ss.storeScriptString.line = prop->location.start.line;
1063 output->addInstruction(ss);
1066 bool seenDefer = false;
1067 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1068 if (prop->isDeferred) {
1073 genValueProperty(prop, obj);
1076 QDeclarativeInstruction defer;
1077 defer.setType(QDeclarativeInstruction::Defer);
1078 defer.defer.deferCount = 0;
1079 int deferIdx = output->addInstruction(defer);
1080 int nextInstructionIndex = output->nextInstructionIndex();
1082 QDeclarativeInstruction init;
1083 init.setType(QDeclarativeInstruction::Init);
1084 init.init.bindingsSize = compileState->bindings.count(); // XXX - bigger than necessary
1085 init.init.parserStatusSize = compileState->parserStatusCount; // XXX - bigger than necessary
1086 init.init.contextCache = -1;
1087 init.init.compiledBinding = -1;
1088 output->addInstruction(init);
1090 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1091 if (!prop->isDeferred)
1093 genValueProperty(prop, obj);
1096 QDeclarativeInstruction done;
1097 done.setType(QDeclarativeInstruction::Done);
1098 output->addInstruction(done);
1100 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1103 for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1105 QDeclarativeParser::Value *v = prop->values.first();
1107 if (v->type == Value::SignalObject) {
1109 genObject(v->object);
1111 QDeclarativeInstruction assign;
1112 assign.setType(QDeclarativeInstruction::AssignSignalObject);
1113 assign.assignSignalObject.line = v->location.start.line;
1114 assign.assignSignalObject.signal = output->indexForString(prop->name().toString());
1115 output->addInstruction(assign);
1117 } else if (v->type == Value::SignalExpression) {
1119 QDeclarativeInstruction store;
1120 store.setType(QDeclarativeInstruction::StoreSignal);
1121 store.storeSignal.signalIndex = prop->index;
1122 store.storeSignal.value =
1123 output->indexForString(v->value.asScript().trimmed());
1124 store.storeSignal.context = v->signalExpressionContextStack;
1125 store.storeSignal.name = output->indexForByteArray(prop->name().toUtf8());
1126 store.storeSignal.line = v->location.start.line;
1127 output->addInstruction(store);
1133 for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1134 QDeclarativeInstruction fetch;
1135 fetch.setType(QDeclarativeInstruction::FetchAttached);
1136 fetch.fetchAttached.id = prop->index;
1137 fetch.fetchAttached.line = prop->location.start.line;
1138 output->addInstruction(fetch);
1140 genObjectBody(prop->value);
1142 QDeclarativeInstruction pop;
1143 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1144 output->addInstruction(pop);
1147 for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1148 QDeclarativeInstruction fetch;
1149 fetch.setType(QDeclarativeInstruction::FetchObject);
1150 fetch.fetch.property = prop->index;
1151 fetch.fetch.line = prop->location.start.line;
1152 output->addInstruction(fetch);
1154 if (!prop->value->metadata.isEmpty()) {
1155 QDeclarativeInstruction meta;
1156 meta.setType(QDeclarativeInstruction::StoreMetaObject);
1157 meta.storeMeta.data = output->indexForByteArray(prop->value->metadata);
1158 meta.storeMeta.aliasData = output->indexForByteArray(prop->value->synthdata);
1159 meta.storeMeta.propertyCache = -1;
1160 output->addInstruction(meta);
1163 genObjectBody(prop->value);
1165 QDeclarativeInstruction pop;
1166 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1167 output->addInstruction(pop);
1170 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1172 genValueTypeProperty(obj, prop);
1175 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1176 if (prop->isDeferred)
1179 genValueProperty(prop, obj);
1182 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1184 genValueTypeProperty(obj, prop);
1188 void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeParser::Object *obj,QDeclarativeParser::Property *prop)
1190 QDeclarativeInstruction fetch;
1191 fetch.setType(QDeclarativeInstruction::FetchValueType);
1192 fetch.fetchValue.property = prop->index;
1193 fetch.fetchValue.type = prop->type;
1194 fetch.fetchValue.bindingSkipList = 0;
1196 if (obj->type == -1 || output->types.at(obj->type).component) {
1197 // We only have to do this if this is a composite type. If it is a builtin
1198 // type it can't possibly already have bindings that need to be cleared.
1199 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1200 if (!vprop->values.isEmpty()) {
1201 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1202 fetch.fetchValue.bindingSkipList |= (1 << vprop->index);
1207 output->addInstruction(fetch);
1209 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1210 genPropertyAssignment(vprop, prop->value, prop);
1213 QDeclarativeInstruction pop;
1214 pop.setType(QDeclarativeInstruction::PopValueType);
1215 pop.fetchValue.property = prop->index;
1216 pop.fetchValue.type = prop->type;
1217 pop.fetchValue.bindingSkipList = 0;
1218 output->addInstruction(pop);
1221 void QDeclarativeCompiler::genComponent(QDeclarativeParser::Object *obj)
1223 QDeclarativeParser::Object *root = obj->defaultProperty->values.first()->object;
1226 QDeclarativeInstruction create;
1227 create.setType(QDeclarativeInstruction::CreateComponent);
1228 create.createComponent.line = root->location.start.line;
1229 create.createComponent.column = root->location.start.column;
1230 create.createComponent.endLine = root->location.end.line;
1231 int createInstruction = output->addInstruction(create);
1232 int nextInstructionIndex = output->nextInstructionIndex();
1234 ComponentCompileState *oldCompileState = compileState;
1235 compileState = componentState(root);
1237 QDeclarativeInstruction init;
1238 init.setType(QDeclarativeInstruction::Init);
1239 init.init.bindingsSize = compileState->bindings.count();
1240 init.init.parserStatusSize = compileState->parserStatusCount;
1241 init.init.contextCache = genContextCache();
1242 if (compileState->compiledBindingData.isEmpty())
1243 init.init.compiledBinding = -1;
1245 init.init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
1246 output->addInstruction(init);
1248 if (!compileState->v8BindingProgram.isEmpty()) {
1249 QDeclarativeInstruction bindings;
1250 bindings.setType(QDeclarativeInstruction::InitV8Bindings);
1251 bindings.initV8Bindings.program = output->indexForString(compileState->v8BindingProgram);
1252 bindings.initV8Bindings.programIndex = compileState->v8BindingProgramIndex;
1253 bindings.initV8Bindings.line = compileState->v8BindingProgramLine;
1254 output->addInstruction(bindings);
1259 QDeclarativeInstruction def;
1260 def.setType(QDeclarativeInstruction::SetDefault);
1261 output->addInstruction(def);
1263 QDeclarativeInstruction done;
1264 done.setType(QDeclarativeInstruction::Done);
1265 output->addInstruction(done);
1267 output->instruction(createInstruction)->createComponent.count =
1268 output->nextInstructionIndex() - nextInstructionIndex;
1270 compileState = oldCompileState;
1272 if (!obj->id.isEmpty()) {
1273 QDeclarativeInstruction id;
1274 id.setType(QDeclarativeInstruction::SetId);
1275 id.setId.value = output->indexForString(obj->id);
1276 id.setId.index = obj->idIndex;
1277 output->addInstruction(id);
1280 if (obj == unitRoot) {
1281 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1282 output->rootPropertyCache->addref();
1286 bool QDeclarativeCompiler::buildComponent(QDeclarativeParser::Object *obj,
1287 const BindingContext &ctxt)
1289 // The special "Component" element can only have the id property and a
1290 // default property, that actually defines the component's tree
1292 // Find, check and set the "id" property (if any)
1293 Property *idProp = 0;
1294 if (obj->properties.isMany() ||
1295 (obj->properties.isOne() && obj->properties.first()->name() != id_string))
1296 COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
1298 if (!obj->properties.isEmpty())
1299 idProp = obj->properties.first();
1302 if (idProp->value || idProp->values.isMany() || idProp->values.first()->object)
1303 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1304 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1306 QString idVal = idProp->values.first()->primitive();
1308 if (compileState->ids.value(idVal))
1309 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1315 // Check the Component tree is well formed
1316 if (obj->defaultProperty &&
1317 (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
1318 (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
1319 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1321 if (!obj->dynamicProperties.isEmpty())
1322 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1323 if (!obj->dynamicSignals.isEmpty())
1324 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1325 if (!obj->dynamicSlots.isEmpty())
1326 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1328 QDeclarativeParser::Object *root = 0;
1329 if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
1330 root = obj->defaultProperty->values.first()->object;
1333 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1335 // Build the component tree
1336 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1341 bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeParser::Object *obj,
1342 const BindingContext &ctxt)
1344 ComponentCompileState *oldComponentCompileState = compileState;
1345 compileState = pool->New<ComponentCompileState>();
1346 compileState->root = obj;
1347 compileState->nested = true;
1349 if (componentStats) {
1350 ComponentStat oldComponentStat = componentStats->componentStat;
1352 componentStats->componentStat = ComponentStat();
1353 componentStats->componentStat.lineNumber = obj->location.start.line;
1356 COMPILE_CHECK(buildObject(obj, ctxt));
1358 COMPILE_CHECK(completeComponentBuild());
1360 componentStats->componentStat = oldComponentStat;
1363 COMPILE_CHECK(buildObject(obj, ctxt));
1365 COMPILE_CHECK(completeComponentBuild());
1368 compileState = oldComponentCompileState;
1374 // Build a sub-object. A sub-object is one that was not created directly by
1375 // QML - such as a grouped property object, or an attached object. Sub-object's
1376 // can't have an id, involve a custom parser, have attached properties etc.
1377 bool QDeclarativeCompiler::buildSubObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
1379 Q_ASSERT(obj->metatype);
1380 Q_ASSERT(!obj->defaultProperty);
1381 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1384 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1385 if (isSignalPropertyName(prop->name())) {
1386 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1388 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1395 int QDeclarativeCompiler::componentTypeRef()
1397 QDeclarativeType *t = QDeclarativeMetaType::qmlType("QtQuick/Component",2,0);
1398 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1399 if (output->types.at(ii).type == t)
1402 QDeclarativeCompiledData::TypeReference ref;
1403 ref.className = Component_string;
1405 output->types << ref;
1406 return output->types.count() - 1;
1409 bool QDeclarativeCompiler::buildSignal(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj,
1410 const BindingContext &ctxt)
1412 Q_ASSERT(obj->metaObject());
1414 QStringRef propName = prop->name();
1415 Q_ASSERT(propName.startsWith(on_string));
1416 QString name = propName.string()->mid(propName.position() + 2, propName.length() - 2);
1418 // Note that the property name could start with any alpha or '_' or '$' character,
1419 // so we need to do the lower-casing of the first alpha character.
1420 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1421 if (name.at(firstAlphaIndex) >= QLatin1Char('A') && name.at(firstAlphaIndex) <= QLatin1Char('Z')) {
1422 name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1427 bool notInRevision = false;
1429 QDeclarativePropertyCache::Data *sig = signal(obj, QStringRef(&name), ¬InRevision);
1433 if (notInRevision && 0 == property(obj, propName, 0)) {
1434 Q_ASSERT(obj->type != -1);
1435 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1436 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1438 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(elementName(obj)).arg(prop->name().toString()).arg(QString::fromUtf8(type.type->module())).arg(type.majorVersion).arg(type.minorVersion));
1440 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1444 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1446 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1450 if (prop->value || !prop->values.isOne())
1451 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1453 prop->index = sig->coreIndex;
1456 obj->addSignalProperty(prop);
1458 if (prop->values.first()->object) {
1459 COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1460 prop->values.first()->type = Value::SignalObject;
1462 prop->values.first()->type = Value::SignalExpression;
1464 if (!prop->values.first()->value.isScript())
1465 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1467 QString script = prop->values.first()->value.asScript().trimmed();
1468 if (script.isEmpty())
1469 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1471 prop->values.first()->signalExpressionContextStack = ctxt.stack;
1480 Returns true if (value) property \a prop exists on obj, false otherwise.
1482 bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeParser::Property *prop,
1483 QDeclarativeParser::Object *obj)
1485 if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1488 if (prop->isDefault) {
1489 const QMetaObject *mo = obj->metaObject();
1490 QMetaProperty p = QDeclarativeMetaType::defaultProperty(mo);
1491 return p.name() != 0;
1493 return property(obj, prop->name()) != 0;
1497 bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop,
1498 QDeclarativeParser::Object *obj,
1499 const BindingContext &ctxt)
1501 if (prop->isEmpty())
1502 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1504 const QMetaObject *metaObject = obj->metaObject();
1505 Q_ASSERT(metaObject);
1507 if (isAttachedPropertyName(prop->name())) {
1508 // Setup attached property data
1510 if (ctxt.isSubContext()) {
1511 // Attached properties cannot be used on sub-objects. Sub-objects
1512 // always exist in a binding sub-context, which is what we test
1514 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1517 QDeclarativeType *type = 0;
1518 QDeclarativeImportedNamespace *typeNamespace = 0;
1519 unit->imports().resolveType(prop->name().toUtf8(), &type, 0, 0, 0, &typeNamespace);
1521 if (typeNamespace) {
1522 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1525 } else if (!type || !type->attachedPropertiesType()) {
1526 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1530 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1532 Q_ASSERT(type->attachedPropertiesFunction());
1533 prop->index = type->attachedPropertiesId();
1534 prop->value->metatype = type->attachedPropertiesType();
1536 // Setup regular property data
1538 if (prop->isDefault) {
1539 QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
1542 prop->setName(QString::fromLatin1(p.name()));
1544 QDeclarativePropertyCache::Data *d = property(obj, p.propertyIndex());
1545 prop->index = d->coreIndex;
1550 bool notInRevision = false;
1551 QDeclarativePropertyCache::Data *d = property(obj, prop->name(), ¬InRevision);
1553 if (d == 0 && notInRevision) {
1554 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1555 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1557 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(elementName(obj)).arg(prop->name().toString()).arg(QString::fromUtf8(type.type->module())).arg(type.majorVersion).arg(type.minorVersion));
1559 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1562 prop->index = d->coreIndex;
1567 // We can't error here as the "id" property does not require a
1568 // successful index resolution
1569 if (prop->index != -1)
1570 prop->type = prop->core.propType;
1572 // Check if this is an alias
1573 if (prop->index != -1 &&
1575 prop->parent->type != -1 &&
1576 output->types.at(prop->parent->type).component) {
1578 QDeclarativePropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1579 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1580 prop->isAlias = true;
1583 if (prop->index != -1 && !prop->values.isEmpty())
1584 prop->parent->setBindingBit(prop->index);
1587 if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1589 // The magic "id" behavior doesn't apply when "id" is resolved as a
1590 // default property or to sub-objects (which are always in binding
1592 COMPILE_CHECK(buildIdProperty(prop, obj));
1593 if (prop->type == QVariant::String &&
1594 prop->values.first()->value.isString())
1595 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1597 } else if (isAttachedPropertyName(prop->name())) {
1599 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1601 } else if (prop->index == -1) {
1603 if (prop->isDefault) {
1604 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1606 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1609 } else if (prop->value) {
1611 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1613 } else if (enginePrivate->isList(prop->type)) {
1615 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1617 } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) {
1619 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1623 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1630 bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
1631 QDeclarativeParser::Property *nsProp,
1632 QDeclarativeParser::Object *obj,
1633 const BindingContext &ctxt)
1636 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1638 for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1640 if (!isAttachedPropertyName(prop->name()))
1641 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1643 // Setup attached property data
1645 QDeclarativeType *type = 0;
1646 unit->imports().resolveType(ns, prop->name().toUtf8(), &type, 0, 0, 0);
1648 if (!type || !type->attachedPropertiesType())
1649 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1652 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1654 Q_ASSERT(type->attachedPropertiesFunction());
1655 prop->index = type->index();
1656 prop->value->metatype = type->attachedPropertiesType();
1658 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1664 void QDeclarativeCompiler::genValueProperty(QDeclarativeParser::Property *prop,
1665 QDeclarativeParser::Object *obj)
1667 if (enginePrivate->isList(prop->type)) {
1668 genListProperty(prop, obj);
1670 genPropertyAssignment(prop, obj);
1674 void QDeclarativeCompiler::genListProperty(QDeclarativeParser::Property *prop,
1675 QDeclarativeParser::Object *obj)
1677 int listType = enginePrivate->listType(prop->type);
1679 QDeclarativeInstruction fetch;
1680 fetch.setType(QDeclarativeInstruction::FetchQList);
1681 fetch.fetchQmlList.property = prop->index;
1682 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1683 fetch.fetchQmlList.type = listType;
1684 output->addInstruction(fetch);
1686 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1688 if (v->type == Value::CreatedObject) {
1690 genObject(v->object);
1691 if (listTypeIsInterface) {
1692 QDeclarativeInstruction assign;
1693 assign.setType(QDeclarativeInstruction::AssignObjectList);
1694 assign.assignObjectList.line = prop->location.start.line;
1695 output->addInstruction(assign);
1697 QDeclarativeInstruction store;
1698 store.setType(QDeclarativeInstruction::StoreObjectQList);
1699 output->addInstruction(store);
1702 } else if (v->type == Value::PropertyBinding) {
1704 genBindingAssignment(v, prop, obj);
1710 QDeclarativeInstruction pop;
1711 pop.setType(QDeclarativeInstruction::PopQList);
1712 output->addInstruction(pop);
1715 void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *prop,
1716 QDeclarativeParser::Object *obj,
1717 QDeclarativeParser::Property *valueTypeProperty)
1719 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1721 Q_ASSERT(v->type == Value::CreatedObject ||
1722 v->type == Value::PropertyBinding ||
1723 v->type == Value::Literal);
1725 if (v->type == Value::CreatedObject) {
1727 genObject(v->object);
1729 if (QDeclarativeMetaType::isInterface(prop->type)) {
1731 QDeclarativeInstruction store;
1732 store.setType(QDeclarativeInstruction::StoreInterface);
1733 store.storeObject.line = v->object->location.start.line;
1734 store.storeObject.propertyIndex = prop->index;
1735 output->addInstruction(store);
1737 } else if (prop->type == QMetaType::QVariant) {
1739 QDeclarativeInstruction store;
1740 store.setType(QDeclarativeInstruction::StoreVariantObject);
1741 store.storeObject.line = v->object->location.start.line;
1742 store.storeObject.propertyIndex = prop->index;
1743 output->addInstruction(store);
1747 QDeclarativeInstruction store;
1748 store.setType(QDeclarativeInstruction::StoreObject);
1749 store.storeObject.line = v->object->location.start.line;
1750 store.storeObject.propertyIndex = prop->index;
1751 output->addInstruction(store);
1754 } else if (v->type == Value::PropertyBinding) {
1756 genBindingAssignment(v, prop, obj, valueTypeProperty);
1758 } else if (v->type == Value::Literal) {
1760 genLiteralAssignment(prop, v);
1766 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
1768 Q_ASSERT(v->type == Value::ValueSource ||
1769 v->type == Value::ValueInterceptor);
1771 if (v->type == Value::ValueSource) {
1772 genObject(v->object);
1774 QDeclarativeInstruction store;
1775 store.setType(QDeclarativeInstruction::StoreValueSource);
1776 if (valueTypeProperty) {
1777 store.assignValueSource.property = genValueTypeData(prop, valueTypeProperty);
1778 store.assignValueSource.owner = 1;
1780 store.assignValueSource.property = genPropertyData(prop);
1781 store.assignValueSource.owner = 0;
1783 QDeclarativeType *valueType = toQmlType(v->object);
1784 store.assignValueSource.castValue = valueType->propertyValueSourceCast();
1785 output->addInstruction(store);
1787 } else if (v->type == Value::ValueInterceptor) {
1788 genObject(v->object);
1790 QDeclarativeInstruction store;
1791 store.setType(QDeclarativeInstruction::StoreValueInterceptor);
1792 if (valueTypeProperty) {
1793 store.assignValueInterceptor.property = genValueTypeData(prop, valueTypeProperty);
1794 store.assignValueInterceptor.owner = 1;
1796 store.assignValueInterceptor.property = genPropertyData(prop);
1797 store.assignValueInterceptor.owner = 0;
1799 QDeclarativeType *valueType = toQmlType(v->object);
1800 store.assignValueInterceptor.castValue = valueType->propertyValueInterceptorCast();
1801 output->addInstruction(store);
1807 bool QDeclarativeCompiler::buildIdProperty(QDeclarativeParser::Property *prop,
1808 QDeclarativeParser::Object *obj)
1811 prop->values.isMany() ||
1812 prop->values.first()->object)
1813 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
1815 QDeclarativeParser::Value *idValue = prop->values.first();
1816 QString val = idValue->primitive();
1818 COMPILE_CHECK(checkValidId(idValue, val));
1820 if (compileState->ids.value(val))
1821 COMPILE_EXCEPTION(prop, tr("id is not unique"));
1823 prop->values.first()->type = Value::Id;
1831 void QDeclarativeCompiler::addId(const QString &id, QDeclarativeParser::Object *obj)
1833 Q_ASSERT(!compileState->ids.value(id));
1834 Q_ASSERT(obj->id == id);
1835 obj->idIndex = compileState->ids.count();
1836 compileState->ids.append(obj);
1839 void QDeclarativeCompiler::addBindingReference(BindingReference *ref)
1841 Q_ASSERT(ref->value && !ref->value->bindingReference);
1842 ref->value->bindingReference = ref;
1843 compileState->bindings.prepend(ref);
1846 void QDeclarativeCompiler::saveComponentState()
1848 Q_ASSERT(compileState->root);
1849 Q_ASSERT(compileState->root->componentCompileState == 0);
1851 compileState->root->componentCompileState = compileState;
1854 componentStats->savedComponentStats.append(componentStats->componentStat);
1857 QDeclarativeCompilerTypes::ComponentCompileState *
1858 QDeclarativeCompiler::componentState(QDeclarativeParser::Object *obj)
1860 Q_ASSERT(obj->componentCompileState);
1861 return obj->componentCompileState;
1864 // Build attached property object. In this example,
1868 // GridView is an attached property object.
1869 bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeParser::Property *prop,
1870 QDeclarativeParser::Object *obj,
1871 const BindingContext &ctxt)
1873 Q_ASSERT(prop->value);
1874 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
1876 obj->addAttachedProperty(prop);
1878 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1884 // Build "grouped" properties. In this example:
1886 // font.pointSize: 12
1887 // font.family: "Helvetica"
1889 // font is a nested property. pointSize and family are not.
1890 bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeParser::Property *prop,
1891 QDeclarativeParser::Object *obj,
1892 const BindingContext &ctxt)
1894 Q_ASSERT(prop->type != 0);
1895 Q_ASSERT(prop->index != -1);
1897 if (QDeclarativeValueTypeFactory::isValueType(prop->type)) {
1898 if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
1900 if (!prop->values.isEmpty()) {
1901 if (prop->values.first()->location < prop->value->location) {
1902 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
1904 COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
1908 if (!obj->metaObject()->property(prop->index).isWritable()) {
1909 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
1913 if (prop->isAlias) {
1914 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
1915 vtProp->isAlias = true;
1919 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
1920 prop->value, obj, ctxt.incr()));
1921 obj->addValueTypeProperty(prop);
1923 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1927 // Load the nested property's meta type
1928 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
1929 if (!prop->value->metatype)
1930 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1932 if (!prop->values.isEmpty())
1933 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
1935 obj->addGroupedProperty(prop);
1937 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1943 bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
1944 QDeclarativeParser::Object *obj,
1945 QDeclarativeParser::Object *baseObj,
1946 const BindingContext &ctxt)
1948 if (obj->defaultProperty)
1949 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
1950 obj->metatype = type->metaObject();
1952 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1954 QDeclarativePropertyCache::Data *d = property(obj, prop->name());
1956 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1958 prop->index = d->coreIndex;
1959 prop->type = d->propType;
1961 prop->isValueTypeSubProperty = true;
1964 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
1966 if (prop->values.isMany()) {
1967 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
1968 } else if (!prop->values.isEmpty()) {
1969 QDeclarativeParser::Value *value = prop->values.first();
1971 if (value->object) {
1972 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
1973 } else if (value->value.isScript()) {
1974 // ### Check for writability
1976 //optimization for <Type>.<EnumValue> enum assignments
1977 bool isEnumAssignment = false;
1979 if (prop->core.isEnum())
1980 COMPILE_CHECK(testQualifiedEnumAssignment(obj->metatype->property(prop->index), obj,
1981 value, &isEnumAssignment));
1983 if (isEnumAssignment) {
1984 value->type = Value::Literal;
1986 BindingReference *reference = pool->New<BindingReference>();
1987 reference->expression = value->value;
1988 reference->property = prop;
1989 reference->value = value;
1990 reference->bindingContext = ctxt;
1991 reference->bindingContext.owner++;
1992 addBindingReference(reference);
1993 value->type = Value::PropertyBinding;
1996 COMPILE_CHECK(testLiteralAssignment(prop, value));
1997 value->type = Value::Literal;
2001 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2002 Q_ASSERT(v->object);
2004 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
2007 obj->addValueProperty(prop);
2013 // Build assignments to QML lists. QML lists are properties of type
2014 // QDeclarativeListProperty<T>. List properties can accept a list of
2015 // objects, or a single binding.
2016 bool QDeclarativeCompiler::buildListProperty(QDeclarativeParser::Property *prop,
2017 QDeclarativeParser::Object *obj,
2018 const BindingContext &ctxt)
2020 Q_ASSERT(enginePrivate->isList(prop->type));
2024 obj->addValueProperty(prop);
2026 int listType = enginePrivate->listType(t);
2027 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
2029 bool assignedBinding = false;
2030 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2032 v->type = Value::CreatedObject;
2033 COMPILE_CHECK(buildObject(v->object, ctxt));
2035 // We check object coercian here. We check interface assignment
2037 if (!listTypeIsInterface) {
2038 if (!canCoerce(listType, v->object)) {
2039 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2043 } else if (v->value.isScript()) {
2044 if (assignedBinding)
2045 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2047 assignedBinding = true;
2048 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2049 v->type = Value::PropertyBinding;
2051 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2058 // Compiles an assignment to a QDeclarativeScriptString property
2059 bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeParser::Property *prop,
2060 QDeclarativeParser::Object *obj,
2061 const BindingContext &ctxt)
2063 if (prop->values.isMany())
2064 COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2066 if (prop->values.first()->object)
2067 COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2069 prop->scriptStringScope = ctxt.stack;
2070 obj->addScriptStringProperty(prop);
2075 // Compile regular property assignments of the form "property: <value>"
2076 bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeParser::Property *prop,
2077 QDeclarativeParser::Object *obj,
2078 const BindingContext &ctxt)
2080 obj->addValueProperty(prop);
2082 if (prop->values.isMany())
2083 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2085 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2088 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2092 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2097 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2098 Q_ASSERT(v->object);
2099 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2105 // Compile assigning a single object instance to a regular property
2106 bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeParser::Property *prop,
2107 QDeclarativeParser::Object *obj,
2108 QDeclarativeParser::Value *v,
2109 const BindingContext &ctxt)
2111 Q_ASSERT(prop->index != -1);
2112 Q_ASSERT(v->object->type != -1);
2114 if (!obj->metaObject()->property(prop->index).isWritable())
2115 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2117 if (QDeclarativeMetaType::isInterface(prop->type)) {
2119 // Assigning an object to an interface ptr property
2120 COMPILE_CHECK(buildObject(v->object, ctxt));
2122 v->type = Value::CreatedObject;
2124 } else if (prop->type == QMetaType::QVariant) {
2126 // Assigning an object to a QVariant
2127 COMPILE_CHECK(buildObject(v->object, ctxt));
2129 v->type = Value::CreatedObject;
2131 // Normally buildObject() will set this up, but we need the static
2132 // meta object earlier to test for assignability. It doesn't matter
2133 // that there may still be outstanding synthesized meta object changes
2134 // on this type, as they are not relevant for assignability testing
2135 v->object->metatype = output->types.at(v->object->type).metaObject();
2136 Q_ASSERT(v->object->metaObject());
2138 // We want to raw metaObject here as the raw metaobject is the
2139 // actual property type before we applied any extensions that might
2140 // effect the properties on the type, but don't effect assignability
2141 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2143 // Will be true if the assgned type inherits propertyMetaObject
2144 bool isAssignable = false;
2145 // Determine isAssignable value
2146 if (propertyMetaObject) {
2147 const QMetaObject *c = v->object->metatype;
2149 isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject));
2150 c = c->superClass();
2155 // Simple assignment
2156 COMPILE_CHECK(buildObject(v->object, ctxt));
2158 v->type = Value::CreatedObject;
2159 } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) {
2160 // Automatic "Component" insertion
2161 QDeclarativeParser::Object *root = v->object;
2162 QDeclarativeParser::Object *component = pool->New<Object>();
2163 component->type = componentTypeRef();
2164 component->typeName = "Qt/Component";
2165 component->metatype = &QDeclarativeComponent::staticMetaObject;
2166 component->location = root->location;
2167 QDeclarativeParser::Value *componentValue = pool->New<Value>();
2168 componentValue->object = root;
2169 component->getDefaultProperty()->addValue(componentValue);
2170 v->object = component;
2171 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2173 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2180 // Compile assigning a single object instance to a regular property using the "on" syntax.
2184 // NumberAnimation on x { }
2186 bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeParser::Property *prop,
2187 QDeclarativeParser::Object *obj,
2188 QDeclarativeParser::Object *baseObj,
2189 QDeclarativeParser::Value *v,
2190 const BindingContext &ctxt)
2192 Q_ASSERT(prop->index != -1);
2193 Q_ASSERT(v->object->type != -1);
2195 if (!obj->metaObject()->property(prop->index).isWritable())
2196 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2199 // Normally buildObject() will set this up, but we need the static
2200 // meta object earlier to test for assignability. It doesn't matter
2201 // that there may still be outstanding synthesized meta object changes
2202 // on this type, as they are not relevant for assignability testing
2203 v->object->metatype = output->types.at(v->object->type).metaObject();
2204 Q_ASSERT(v->object->metaObject());
2206 // Will be true if the assigned type inherits QDeclarativePropertyValueSource
2207 bool isPropertyValue = false;
2208 // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor
2209 bool isPropertyInterceptor = false;
2210 if (QDeclarativeType *valueType = toQmlType(v->object)) {
2211 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2212 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2215 if (isPropertyValue || isPropertyInterceptor) {
2216 // Assign as a property value source
2217 COMPILE_CHECK(buildObject(v->object, ctxt));
2219 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2220 buildDynamicMeta(baseObj, ForceCreation);
2221 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2223 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(QString::fromUtf8(v->object->typeName)).arg(prop->name().toString()));
2229 // Compile assigning a literal or binding to a regular property
2230 bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeParser::Property *prop,
2231 QDeclarativeParser::Object *obj,
2232 QDeclarativeParser::Value *v,
2233 const BindingContext &ctxt)
2235 Q_ASSERT(prop->index != -1);
2237 if (v->value.isScript()) {
2239 //optimization for <Type>.<EnumValue> enum assignments
2240 if (prop->core.isEnum()) {
2241 bool isEnumAssignment = false;
2242 COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj,
2243 v, &isEnumAssignment));
2244 if (isEnumAssignment) {
2245 v->type = Value::Literal;
2250 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2252 v->type = Value::PropertyBinding;
2256 COMPILE_CHECK(testLiteralAssignment(prop, v));
2258 v->type = Value::Literal;
2264 bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop,
2265 QDeclarativeParser::Object *obj,
2266 QDeclarativeParser::Value *v,
2269 *isAssignment = false;
2270 if (!prop.isEnumType())
2273 if (!prop.isWritable())
2274 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
2276 QString string = v->value.asString();
2277 if (!string.at(0).isUpper())
2280 QStringList parts = string.split(QLatin1Char('.'));
2281 if (parts.count() != 2)
2284 QString typeName = parts.at(0);
2285 QDeclarativeType *type = 0;
2286 unit->imports().resolveType(typeName.toUtf8(), &type, 0, 0, 0, 0);
2288 //handle enums on value types (where obj->typeName is empty)
2289 QByteArray objTypeName = obj->typeName;
2290 if (objTypeName.isEmpty()) {
2291 QDeclarativeType *objType = toQmlType(obj);
2293 objTypeName = objType->qmlTypeName();
2299 QString enumValue = parts.at(1);
2302 if (objTypeName == type->qmlTypeName()) {
2303 // When these two match, we can short cut the search
2304 if (prop.isFlagType()) {
2305 value = prop.enumerator().keysToValue(enumValue.toUtf8().constData());
2307 value = prop.enumerator().keyToValue(enumValue.toUtf8().constData());
2310 // Otherwise we have to search the whole type
2311 // This matches the logic in QV8TypeWrapper
2312 QByteArray enumName = enumValue.toUtf8();
2313 const QMetaObject *metaObject = type->baseMetaObject();
2314 for (int ii = metaObject->enumeratorCount() - 1; value == -1 && ii >= 0; --ii) {
2315 QMetaEnum e = metaObject->enumerator(ii);
2316 value = e.keyToValue(enumName.constData());
2323 v->type = Value::Literal;
2324 v->value = QDeclarativeParser::Variant((double)value);
2325 *isAssignment = true;
2330 struct StaticQtMetaObject : public QObject
2332 static const QMetaObject *get()
2333 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2336 // Similar logic to above, but not knowing target property.
2337 int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const
2339 int dot = script.indexOf('.');
2341 const QByteArray &scope = script.left(dot);
2342 QDeclarativeType *type = 0;
2343 unit->imports().resolveType(scope, &type, 0, 0, 0, 0);
2344 if (!type && scope != "Qt")
2346 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2347 const char *key = script.constData() + dot+1;
2348 int i = mo->enumeratorCount();
2350 int v = mo->enumerator(i).keyToValue(key);
2358 const QMetaObject *QDeclarativeCompiler::resolveType(const QByteArray& name) const
2360 QDeclarativeType *qmltype = 0;
2361 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2365 return qmltype->metaObject();
2368 // similar to logic of completeComponentBuild, but also sticks data
2369 // into primitives at the end
2370 int QDeclarativeCompiler::rewriteBinding(const QString& expression, const QString& name)
2372 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2373 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf('.') + 1));
2375 QString rewrite = rewriteBinding(expression, 0, 0);
2377 return output->indexForString(rewrite);
2380 // Ensures that the dynamic meta specification on obj is valid
2381 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj)
2383 QSet<QByteArray> propNames;
2384 QSet<QByteArray> methodNames;
2385 bool seenDefaultProperty = false;
2388 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2389 const QDeclarativeParser::Object::DynamicProperty &prop =
2390 obj->dynamicProperties.at(ii);
2392 if (prop.isDefaultProperty) {
2393 if (seenDefaultProperty)
2394 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2395 seenDefaultProperty = true;
2398 if (propNames.contains(prop.name))
2399 COMPILE_EXCEPTION(&prop, tr("Duplicate property name"));
2401 QString propName = QString::fromUtf8(prop.name);
2402 if (propName.at(0).isUpper())
2403 COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
2405 if (enginePrivate->v8engine()->illegalNames().contains(propName))
2406 COMPILE_EXCEPTION(&prop, tr("Illegal property name"));
2408 propNames.insert(prop.name);
2411 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2412 const QDeclarativeParser::Object::DynamicSignal &currSig = obj->dynamicSignals.at(ii);
2413 QByteArray name = currSig.name;
2414 if (methodNames.contains(name))
2415 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2416 QString nameStr = QString::fromUtf8(name);
2417 if (nameStr.at(0).isUpper())
2418 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2419 if (enginePrivate->v8engine()->illegalNames().contains(nameStr))
2420 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2421 methodNames.insert(name);
2423 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2424 const QDeclarativeParser::Object::DynamicSlot &currSlot = obj->dynamicSlots.at(ii);
2425 QByteArray name = currSlot.name;
2426 if (methodNames.contains(name))
2427 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2428 QString nameStr = QString::fromUtf8(name);
2429 if (nameStr.at(0).isUpper())
2430 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2431 if (enginePrivate->v8engine()->illegalNames().contains(nameStr))
2432 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2433 methodNames.insert(name);
2439 bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeParser::Object *obj)
2441 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2442 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2444 if (!p.defaultValue || p.type == Object::DynamicProperty::Alias)
2447 Property *property = 0;
2448 if (p.isDefaultProperty) {
2449 property = obj->getDefaultProperty();
2451 property = obj->getProperty(p.name);
2452 if (!property->values.isEmpty())
2453 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2456 if (property->value)
2457 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2459 property->values.append(p.defaultValue->values);
2464 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2466 bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, DynamicMetaMode mode)
2469 Q_ASSERT(obj->metatype);
2471 if (mode != ForceCreation &&
2472 obj->dynamicProperties.isEmpty() &&
2473 obj->dynamicSignals.isEmpty() &&
2474 obj->dynamicSlots.isEmpty())
2477 QByteArray dynamicData(sizeof(QDeclarativeVMEMetaData), (char)0);
2479 QByteArray newClassName = obj->metatype->className();
2480 newClassName.append("_QML_");
2481 int idx = classIndexCounter()->fetchAndAddRelaxed(1);
2482 newClassName.append(QByteArray::number(idx));
2483 if (compileState->root == obj && !compileState->nested) {
2484 QString path = output->url.path();
2485 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2486 if (lastSlash > -1) {
2487 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2488 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2489 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(idx);
2493 QMetaObjectBuilder builder;
2494 builder.setClassName(newClassName);
2495 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
2497 bool hasAlias = false;
2498 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2499 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2501 int propIdx = obj->metaObject()->indexOfProperty(p.name.constData());
2502 if (-1 != propIdx) {
2503 QMetaProperty prop = obj->metaObject()->property(propIdx);
2505 COMPILE_EXCEPTION(&p, tr("Cannot override FINAL property"));
2508 if (p.isDefaultProperty &&
2509 (p.type != Object::DynamicProperty::Alias ||
2510 mode == ResolveAliases))
2511 builder.addClassInfo("DefaultProperty", p.name);
2514 int propertyType = 0;
2515 bool readonly = false;
2517 case Object::DynamicProperty::Alias:
2521 case Object::DynamicProperty::CustomList:
2522 case Object::DynamicProperty::Custom:
2524 QByteArray customTypeName;
2525 QDeclarativeType *qmltype = 0;
2527 if (!unit->imports().resolveType(p.customType, &qmltype, &url, 0, 0, 0))
2528 COMPILE_EXCEPTION(&p, tr("Invalid property type"));
2531 QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(QUrl(url));
2533 Q_ASSERT(tdata->isComplete());
2535 QDeclarativeCompiledData *data = tdata->compiledData();
2536 customTypeName = data->root->className();
2540 customTypeName = qmltype->typeName();
2543 if (p.type == Object::DynamicProperty::Custom) {
2544 type = customTypeName + '*';
2545 propertyType = QMetaType::QObjectStar;
2548 type = "QDeclarativeListProperty<";
2549 type.append(customTypeName);
2551 propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
2555 case Object::DynamicProperty::Variant:
2559 case Object::DynamicProperty::Int:
2560 propertyType = QVariant::Int;
2563 case Object::DynamicProperty::Bool:
2564 propertyType = QVariant::Bool;
2567 case Object::DynamicProperty::Real:
2568 propertyType = QVariant::Double;
2571 case Object::DynamicProperty::String:
2572 propertyType = QVariant::String;
2575 case Object::DynamicProperty::Url:
2576 propertyType = QVariant::Url;
2579 case Object::DynamicProperty::Color:
2580 propertyType = QVariant::Color;
2583 case Object::DynamicProperty::Time:
2584 propertyType = QVariant::Time;
2587 case Object::DynamicProperty::Date:
2588 propertyType = QVariant::Date;
2591 case Object::DynamicProperty::DateTime:
2592 propertyType = QVariant::DateTime;
2597 ((QDeclarativeVMEMetaData *)dynamicData.data())->propertyCount++;
2598 QDeclarativeVMEMetaData::PropertyData propertyData = { propertyType };
2599 dynamicData.append((char *)&propertyData, sizeof(propertyData));
2601 builder.addSignal(p.name + "Changed()");
2602 QMetaPropertyBuilder propBuilder =
2603 builder.addProperty(p.name, type, builder.methodCount() - 1);
2604 propBuilder.setWritable(!readonly);
2607 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2608 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2610 if (p.type == Object::DynamicProperty::Alias) {
2611 if (mode == ResolveAliases) {
2612 ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++;
2613 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, p));
2615 // Need a fake signal so that the metaobject remains consistent across
2616 // the resolve and non-resolve alias runs
2617 builder.addSignal(p.name + "Changed()");
2622 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2623 const Object::DynamicSignal &s = obj->dynamicSignals.at(ii);
2624 QByteArray sig(s.name + '(');
2625 for (int jj = 0; jj < s.parameterTypes.count(); ++jj) {
2626 if (jj) sig.append(',');
2627 sig.append(s.parameterTypes.at(jj));
2630 QMetaMethodBuilder b = builder.addSignal(sig);
2631 b.setParameterNames(s.parameterNames);
2632 ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++;
2635 QStringList funcScripts;
2637 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2638 Object::DynamicSlot &s = obj->dynamicSlots[ii];
2639 QByteArray sig(s.name + '(');
2640 QString funcScript(QLatin1String("(function ") + s.name + QLatin1Char('('));
2642 for (int jj = 0; jj < s.parameterNames.count(); ++jj) {
2645 funcScript.append(QLatin1Char(','));
2647 funcScript.append(QLatin1String(s.parameterNames.at(jj)));
2648 sig.append("QVariant");
2651 funcScript.append(QLatin1Char(')'));
2652 funcScript.append(s.body);
2653 funcScript.append(QLatin1Char(')'));
2654 funcScripts << funcScript;
2656 QMetaMethodBuilder b = builder.addSlot(sig);
2657 b.setReturnType("QVariant");
2658 b.setParameterNames(s.parameterNames);
2660 ((QDeclarativeVMEMetaData *)dynamicData.data())->methodCount++;
2661 QDeclarativeVMEMetaData::MethodData methodData =
2662 { s.parameterNames.count(), 0, funcScript.length(), s.location.start.line };
2664 dynamicData.append((char *)&methodData, sizeof(methodData));
2667 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2668 const QString &funcScript = funcScripts.at(ii);
2669 QDeclarativeVMEMetaData::MethodData *data =
2670 ((QDeclarativeVMEMetaData *)dynamicData.data())->methodData() + ii;
2672 data->bodyOffset = dynamicData.size();
2674 dynamicData.append((const char *)funcScript.constData(),
2675 (funcScript.length() * sizeof(QChar)));
2678 obj->metadata = builder.toRelocatableData();
2679 builder.fromRelocatableData(&obj->extObject, obj->metatype, obj->metadata);
2681 if (mode == IgnoreAliases && hasAlias)
2682 compileState->aliasingObjects.append(obj);
2684 obj->synthdata = dynamicData;
2686 if (obj->synthCache) {
2687 obj->synthCache->release();
2688 obj->synthCache = 0;
2691 if (obj->type != -1) {
2692 QDeclarativePropertyCache *cache = output->types[obj->type].createPropertyCache(engine)->copy();
2693 cache->append(engine, &obj->extObject, QDeclarativePropertyCache::Data::NoFlags,
2694 QDeclarativePropertyCache::Data::IsVMEFunction,
2695 QDeclarativePropertyCache::Data::IsVMESignal);
2696 obj->synthCache = cache;
2702 bool QDeclarativeCompiler::checkValidId(QDeclarativeParser::Value *v, const QString &val)
2705 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
2707 if (val.at(0).isLetter() && !val.at(0).isLower())
2708 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
2710 QChar u(QLatin1Char('_'));
2711 for (int ii = 0; ii < val.count(); ++ii) {
2713 if (ii == 0 && !val.at(ii).isLetter() && val.at(ii) != u) {
2714 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
2715 } else if (ii != 0 && !val.at(ii).isLetterOrNumber() && val.at(ii) != u) {
2716 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
2721 if (enginePrivate->v8engine()->illegalNames().contains(val))
2722 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
2727 #include <qdeclarativejsparser_p.h>
2729 static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node)
2731 if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) {
2733 static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name.toString();
2734 return QStringList() << name;
2735 } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) {
2736 QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node);
2738 QStringList rv = astNodeToStringList(expr->base);
2741 rv.append(expr->name.toString());
2744 return QStringList();
2747 bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder,
2749 QDeclarativeParser::Object *obj,
2750 const Object::DynamicProperty &prop)
2752 if (!prop.defaultValue)
2753 COMPILE_EXCEPTION(obj, tr("No property alias location"));
2755 if (!prop.defaultValue->values.isOne() ||
2756 prop.defaultValue->values.first()->object ||
2757 !prop.defaultValue->values.first()->value.isScript())
2758 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2760 QDeclarativeJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST();
2762 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
2764 QStringList alias = astNodeToStringList(node);
2766 if (alias.count() < 1 || alias.count() > 3)
2767 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
2769 QDeclarativeParser::Object *idObject = compileState->ids.value(alias.at(0));
2771 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
2773 QByteArray typeName;
2777 bool writable = false;
2778 bool resettable = false;
2779 if (alias.count() == 2 || alias.count() == 3) {
2780 propIdx = indexOfProperty(idObject, alias.at(1));
2782 if (-1 == propIdx) {
2783 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2784 } else if (propIdx > 0xFFFF) {
2785 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
2788 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
2789 if (!aliasProperty.isScriptable())
2790 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2792 writable = aliasProperty.isWritable();
2793 resettable = aliasProperty.isResettable();
2795 if (alias.count() == 3) {
2796 QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
2798 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2800 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
2802 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
2803 if (valueTypeIndex == -1)
2804 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2805 Q_ASSERT(valueTypeIndex <= 0xFF);
2807 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
2808 propIdx |= (valueTypeIndex << 16);
2811 if (aliasProperty.isEnumType())
2812 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
2814 typeName = aliasProperty.typeName();
2816 Q_ASSERT(idObject->type != -1); // How else did it get an id?
2818 const QDeclarativeCompiledData::TypeReference &ref = output->types.at(idObject->type);
2820 typeName = ref.type->typeName();
2822 typeName = ref.component->root->className();
2827 if (typeName.endsWith('*'))
2828 flags |= QML_ALIAS_FLAG_PTR;
2830 data.append((const char *)&idObject->idIndex, sizeof(idObject->idIndex));
2831 data.append((const char *)&propIdx, sizeof(propIdx));
2832 data.append((const char *)&flags, sizeof(flags));
2834 builder.addSignal(prop.name + "Changed()");
2835 QMetaPropertyBuilder propBuilder =
2836 builder.addProperty(prop.name, typeName.constData(), builder.methodCount() - 1);
2837 propBuilder.setWritable(writable);
2838 propBuilder.setResettable(resettable);
2842 bool QDeclarativeCompiler::buildBinding(QDeclarativeParser::Value *value,
2843 QDeclarativeParser::Property *prop,
2844 const BindingContext &ctxt)
2846 Q_ASSERT(prop->index != -1);
2847 Q_ASSERT(prop->parent);
2848 Q_ASSERT(prop->parent->metaObject());
2850 QMetaProperty mp = prop->parent->metaObject()->property(prop->index);
2851 if (!mp.isWritable() && !QDeclarativeMetaType::isList(prop->type))
2852 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2854 BindingReference *reference = pool->New<BindingReference>();
2855 reference->expression = value->value;
2856 reference->property = prop;
2857 reference->value = value;
2858 reference->bindingContext = ctxt;
2859 addBindingReference(reference);
2864 void QDeclarativeCompiler::genBindingAssignment(QDeclarativeParser::Value *binding,
2865 QDeclarativeParser::Property *prop,
2866 QDeclarativeParser::Object *obj,
2867 QDeclarativeParser::Property *valueTypeProperty)
2870 Q_ASSERT(binding->bindingReference);
2872 const BindingReference &ref = *binding->bindingReference;
2873 if (ref.dataType == BindingReference::V4) {
2874 QDeclarativeInstruction store;
2875 store.setType(QDeclarativeInstruction::StoreV4Binding);
2876 store.assignBinding.value = ref.compiledIndex;
2877 store.assignBinding.context = ref.bindingContext.stack;
2878 store.assignBinding.owner = ref.bindingContext.owner;
2879 if (valueTypeProperty)
2880 store.assignBinding.property = (valueTypeProperty->index & 0xFFFF) |
2881 ((valueTypeProperty->type & 0xFF)) << 16 |
2882 ((prop->index & 0xFF) << 24);
2884 store.assignBinding.property = prop->index;
2885 store.assignBinding.line = binding->location.start.line;
2886 output->addInstruction(store);
2887 } else if (ref.dataType == BindingReference::V8) {
2888 QDeclarativeInstruction store;
2889 store.setType(QDeclarativeInstruction::StoreV8Binding);
2890 store.assignBinding.value = ref.compiledIndex;
2891 store.assignBinding.context = ref.bindingContext.stack;
2892 store.assignBinding.owner = ref.bindingContext.owner;
2893 store.assignBinding.line = binding->location.start.line;
2895 Q_ASSERT(ref.bindingContext.owner == 0 ||
2896 (ref.bindingContext.owner != 0 && valueTypeProperty));
2897 if (ref.bindingContext.owner) {
2898 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
2900 store.assignBinding.property = genPropertyData(prop);
2903 output->addInstruction(store);
2905 QDeclarativeInstruction store;
2907 store.setType(QDeclarativeInstruction::StoreBinding);
2909 store.setType(QDeclarativeInstruction::StoreBindingOnAlias);
2910 store.assignBinding.value = output->indexForString(ref.rewrittenExpression);
2911 store.assignBinding.context = ref.bindingContext.stack;
2912 store.assignBinding.owner = ref.bindingContext.owner;
2913 store.assignBinding.line = binding->location.start.line;
2915 Q_ASSERT(ref.bindingContext.owner == 0 ||
2916 (ref.bindingContext.owner != 0 && valueTypeProperty));
2917 if (ref.bindingContext.owner) {
2918 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
2920 store.assignBinding.property = genPropertyData(prop);
2922 output->addInstruction(store);
2926 int QDeclarativeCompiler::genContextCache()
2928 if (compileState->ids.count() == 0)
2931 QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache();
2932 cache->reserve(compileState->ids.count());
2933 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
2934 cache->add(o->id, o->idIndex);
2936 output->contextCaches.append(cache);
2937 return output->contextCaches.count() - 1;
2940 int QDeclarativeCompiler::genValueTypeData(QDeclarativeParser::Property *valueTypeProp,
2941 QDeclarativeParser::Property *prop)
2943 typedef QDeclarativePropertyPrivate QDPP;
2944 QByteArray data = QDPP::saveValueType(prop->parent->metaObject(), prop->index,
2945 enginePrivate->valueTypes[prop->type]->metaObject(),
2946 valueTypeProp->index, engine);
2948 return output->indexForByteArray(data);
2951 int QDeclarativeCompiler::genPropertyData(QDeclarativeParser::Property *prop)
2953 typedef QDeclarativePropertyPrivate QDPP;
2954 QByteArray data = QDPP::saveProperty(prop->parent->metaObject(), prop->index, engine);
2956 return output->indexForByteArray(data);
2959 bool QDeclarativeCompiler::completeComponentBuild()
2962 componentStats->componentStat.ids = compileState->ids.count();
2964 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
2965 aliasObject = compileState->aliasingObjects.next(aliasObject))
2966 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
2968 QDeclarativeV4Compiler::Expression expr(unit->imports());
2969 expr.component = compileState->root;
2970 expr.ids = &compileState->ids;
2971 expr.importCache = output->importCache;
2973 QDeclarativeV4Compiler bindingCompiler;
2975 QList<BindingReference*> sharedBindings;
2977 for (BindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
2979 BindingReference &binding = *b;
2981 // ### We don't currently optimize for bindings on alias's - because
2982 // of the solution to QTBUG-13719
2983 if (!binding.property->isAlias) {
2984 expr.context = binding.bindingContext.object;
2985 expr.property = binding.property;
2986 expr.expression = binding.expression;
2988 int index = bindingCompiler.compile(expr, enginePrivate);
2990 binding.dataType = BindingReference::V4;
2991 binding.compiledIndex = index;
2993 componentStats->componentStat.optimizedBindings.append(b->value->location);
2998 // Pre-rewrite the expression
2999 QString expression = binding.expression.asScript();
3001 QDeclarativeRewrite::RewriteBinding rewriteBinding;
3002 rewriteBinding.setName(QLatin1Char('$')+binding.property->name());
3003 bool isSharable = false;
3004 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3006 if (isSharable && !binding.property->isAlias /* See above re alias */ &&
3007 binding.property->type != qMetaTypeId<QDeclarativeBinding*>()) {
3008 binding.dataType = BindingReference::V8;
3009 sharedBindings.append(b);
3011 binding.dataType = BindingReference::QtScript;
3015 componentStats->componentStat.scriptBindings.append(b->value->location);
3018 if (!sharedBindings.isEmpty()) {
3020 static bool lt(const BindingReference *lhs, const BindingReference *rhs)
3022 return lhs->value->location.start.line < rhs->value->location.start.line;
3026 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3028 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3029 int lineNumber = startLineNumber;
3031 QString functionArray(QLatin1String("["));
3032 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3033 BindingReference *reference = sharedBindings.at(ii);
3034 QDeclarativeParser::Value *value = reference->value;
3035 const QString &expression = reference->rewrittenExpression;
3037 if (ii != 0) functionArray += QLatin1String(",");
3039 while (lineNumber < value->location.start.line) {
3041 functionArray += QLatin1String("\n");
3044 functionArray += expression;
3045 reference->compiledIndex = ii;
3047 functionArray += QLatin1String("]");
3049 compileState->v8BindingProgram = functionArray;
3050 compileState->v8BindingProgramLine = startLineNumber;
3051 compileState->v8BindingProgramIndex = output->v8bindings.count();
3052 output->v8bindings.append(v8::Persistent<v8::Array>());
3055 if (bindingCompiler.isValid())
3056 compileState->compiledBindingData = bindingCompiler.program();
3058 saveComponentState();
3063 void QDeclarativeCompiler::dumpStats()
3065 Q_ASSERT(componentStats);
3066 qWarning().nospace() << "QML Document: " << output->url.toString();
3067 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3068 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3069 qWarning().nospace() << " Component Line " << stat.lineNumber;
3070 qWarning().nospace() << " Total Objects: " << stat.objects;
3071 qWarning().nospace() << " IDs Used: " << stat.ids;
3072 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3076 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3077 if (0 == (ii % 10)) {
3078 if (ii) output.append("\n");
3083 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3085 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3086 output.append(") ");
3088 if (!output.isEmpty())
3089 qWarning().nospace() << output.constData();
3092 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3095 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3096 if (0 == (ii % 10)) {
3097 if (ii) output.append("\n");
3102 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3104 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3105 output.append(") ");
3107 if (!output.isEmpty())
3108 qWarning().nospace() << output.constData();
3114 Returns true if from can be assigned to a (QObject) property of type
3117 bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeParser::Object *from)
3119 const QMetaObject *toMo =
3120 enginePrivate->rawMetaObjectForType(to);
3121 const QMetaObject *fromMo = from->metaObject();
3124 if (QDeclarativePropertyPrivate::equal(fromMo, toMo))
3126 fromMo = fromMo->superClass();
3132 Returns the element name, as written in the QML file, for o.
3134 QString QDeclarativeCompiler::elementName(QDeclarativeParser::Object *o)
3137 if (o->type != -1) {
3138 return output->types.at(o->type).className;
3144 QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeParser::Object *from)
3147 const QMetaObject *mo = from->metatype;
3148 QDeclarativeType *type = 0;
3149 while (!type && mo) {
3150 type = QDeclarativeMetaType::qmlType(mo);
3151 mo = mo->superClass();
3156 QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeParser::Object *obj)
3158 const QMetaObject *mo = obj->metatype;
3160 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3162 return QStringList();
3164 QMetaClassInfo classInfo = mo->classInfo(idx);
3165 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3169 QDeclarativePropertyCache::Data *
3170 QDeclarativeCompiler::property(QDeclarativeParser::Object *object, int index)
3172 QDeclarativePropertyCache *cache = 0;
3174 if (object->synthCache)
3175 cache = object->synthCache;
3176 else if (object->type != -1)
3177 cache = output->types[object->type].createPropertyCache(engine);
3179 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3181 return cache->property(index);
3184 QDeclarativePropertyCache::Data *
3185 QDeclarativeCompiler::property(QDeclarativeParser::Object *object, const QStringRef &name, bool *notInRevision)
3187 if (notInRevision) *notInRevision = false;
3189 QDeclarativePropertyCache *cache = 0;
3191 if (object->synthCache)
3192 cache = object->synthCache;
3193 else if (object->type != -1)
3194 cache = output->types[object->type].createPropertyCache(engine);
3196 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3198 QDeclarativePropertyCache::Data *d = cache->property(QHashedStringRef(name.constData(), name.length()));
3200 // Find the first property
3201 while (d && d->isFunction())
3202 d = cache->overrideData(d);
3204 if (d && !cache->isAllowedInRevision(d)) {
3205 if (notInRevision) *notInRevision = true;
3212 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3213 QDeclarativePropertyCache::Data *
3214 QDeclarativeCompiler::signal(QDeclarativeParser::Object *object, const QStringRef &name, bool *notInRevision)
3216 if (notInRevision) *notInRevision = false;
3218 QDeclarativePropertyCache *cache = 0;
3220 if (object->synthCache)
3221 cache = object->synthCache;
3222 else if (object->type != -1)
3223 cache = output->types[object->type].createPropertyCache(engine);
3225 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3228 QDeclarativePropertyCache::Data *d = cache->property(QHashedStringRef(name.constData(), name.length()));
3229 if (notInRevision) *notInRevision = false;
3231 while (d && !(d->isFunction()))
3232 d = cache->overrideData(d);
3234 if (d && !cache->isAllowedInRevision(d)) {
3235 if (notInRevision) *notInRevision = true;
3241 if (name.endsWith(Changed_string)) {
3242 QStringRef propName(name.string(), name.position(), name.length() - Changed_string.length());
3244 d = property(object, propName, notInRevision);
3246 return cache->method(d->notifyIndex);
3252 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3253 int QDeclarativeCompiler::indexOfSignal(QDeclarativeParser::Object *object, const QString &name,
3254 bool *notInRevision)
3256 QDeclarativePropertyCache::Data *d = signal(object, QStringRef(&name), notInRevision);
3257 return d?d->coreIndex:-1;
3260 int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QString &name,
3261 bool *notInRevision)
3263 return indexOfProperty(object, QStringRef(&name), notInRevision);
3266 int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QStringRef &name,
3267 bool *notInRevision)
3269 QDeclarativePropertyCache::Data *d = property(object, name, notInRevision);
3270 return d?d->coreIndex:-1;