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/qfastmetabuilder_p.h"
50 #include "private/qdeclarativestringconverters_p.h"
51 #include "private/qdeclarativeengine_p.h"
52 #include "qdeclarativeengine.h"
53 #include "qdeclarativecontext.h"
54 #include "private/qdeclarativemetatype_p.h"
55 #include "private/qdeclarativecustomparser_p_p.h"
56 #include "private/qdeclarativecontext_p.h"
57 #include "private/qdeclarativecomponent_p.h"
58 #include "parser/qdeclarativejsast_p.h"
59 #include "private/qdeclarativevmemetaobject_p.h"
60 #include "private/qdeclarativeexpression_p.h"
61 #include "private/qdeclarativeproperty_p.h"
62 #include "private/qdeclarativerewrite_p.h"
63 #include "qdeclarativescriptstring.h"
64 #include "private/qdeclarativeglobal_p.h"
65 #include "private/qdeclarativescriptparser_p.h"
66 #include "private/qdeclarativebinding_p.h"
67 #include "private/qdeclarativev4compiler_p.h"
68 #include "private/qdeclarativeutils_p.h"
76 #include <QtCore/qdebug.h>
77 #include <QtCore/qdatetime.h>
81 DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP);
82 DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS);
84 using namespace QDeclarativeParser;
85 using namespace QDeclarativeCompilerTypes;
87 static QString id_string(QLatin1String("id"));
88 static QString on_string(QLatin1String("on"));
89 static QString Changed_string(QLatin1String("Changed"));
90 static QString Component_string(QLatin1String("Component"));
93 Instantiate a new QDeclarativeCompiler.
95 QDeclarativeCompiler::QDeclarativeCompiler(QDeclarativePool *pool)
96 : pool(pool), output(0), engine(0), unitRoot(0), unit(0), componentStats(0)
98 if (compilerStatDump())
99 componentStats = pool->New<ComponentStats>();
103 Returns true if the last call to compile() caused errors.
107 bool QDeclarativeCompiler::isError() const
109 return !exceptions.isEmpty();
113 Return the list of errors from the last call to compile(), or an empty list
114 if there were no errors.
116 QList<QDeclarativeError> QDeclarativeCompiler::errors() const
122 Returns true if \a name refers to an attached property, false otherwise.
124 Attached property names are those that start with a capital letter.
126 bool QDeclarativeCompiler::isAttachedPropertyName(const QString &name)
128 return isAttachedPropertyName(QStringRef(&name));
131 bool QDeclarativeCompiler::isAttachedPropertyName(const QStringRef &name)
133 return !name.isEmpty() && QDeclarativeUtils::isUpper(name.at(0));
137 Returns true if \a name refers to a signal property, false otherwise.
139 Signal property names are those that start with "on", followed by a first
140 character which is either a capital letter or one or more underscores followed
141 by a capital letter, which is then followed by other allowed characters.
143 Note that although ECMA-262r3 supports dollarsigns and escaped unicode
144 character codes in property names, for simplicity and performance reasons
145 QML only supports letters, numbers and underscores.
147 bool QDeclarativeCompiler::isSignalPropertyName(const QString &name)
149 return isSignalPropertyName(QStringRef(&name));
152 bool QDeclarativeCompiler::isSignalPropertyName(const QStringRef &name)
154 if (name.length() < 3) return false;
155 if (!name.startsWith(on_string)) return false;
156 int ns = name.size();
157 for (int i = 2; i < ns; ++i) {
158 const QChar curr = name.at(i);
159 if (curr.unicode() == '_') continue;
160 if (QDeclarativeUtils::isUpper(curr)) return true;
163 return false; // consists solely of underscores - invalid.
167 \macro COMPILE_EXCEPTION
169 Inserts an error into the QDeclarativeCompiler error list, and returns false
172 \a token is used to source the error line and column, and \a desc is the
173 error itself. \a desc can be an expression that can be piped into QDebug.
178 COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(property->name));
181 #define COMPILE_EXCEPTION(token, desc) \
183 QString exceptionDescription; \
184 QDeclarativeError error; \
185 error.setUrl(output->url); \
186 error.setLine((token)->location.start.line); \
187 error.setColumn((token)->location.start.column); \
188 error.setDescription(desc.trimmed()); \
189 exceptions << error; \
196 Returns false if \a is false, otherwise does nothing.
198 #define COMPILE_CHECK(a) \
200 if (!a) return false; \
204 Returns true if literal \a v can be assigned to property \a prop, otherwise
207 This test corresponds to action taken by genLiteralAssignment(). Any change
208 made here, must have a corresponding action in genLiteralAssigment().
210 bool QDeclarativeCompiler::testLiteralAssignment(QDeclarativeParser::Property *prop,
211 QDeclarativeParser::Value *v)
213 const QDeclarativeParser::Variant &value = v->value;
215 if (!prop->core.isWritable())
216 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
218 if (prop->core.isEnum()) {
219 QMetaProperty p = prop->parent->metaObject()->property(prop->index);
221 if (p.isFlagType()) {
222 enumValue = p.enumerator().keysToValue(value.asString().toUtf8().constData());
224 enumValue = p.enumerator().keyToValue(value.asString().toUtf8().constData());
227 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration"));
229 v->value = QDeclarativeParser::Variant((double)enumValue);
233 int type = prop->type;
236 case QMetaType::QVariant:
238 case QVariant::String:
239 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
241 case QVariant::ByteArray:
242 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected"));
245 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected"));
249 bool ok = v->value.isNumber();
251 double n = v->value.asNumber();
252 if (double(uint(n)) != n)
255 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected"));
260 bool ok = v->value.isNumber();
262 double n = v->value.asNumber();
263 if (double(int(n)) != n)
266 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected"));
269 case QMetaType::Float:
270 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
272 case QVariant::Double:
273 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
275 case QVariant::Color:
278 QDeclarativeStringConverters::colorFromString(value.asString(), &ok);
279 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected"));
282 #ifndef QT_NO_DATESTRING
286 QDeclarativeStringConverters::dateFromString(value.asString(), &ok);
287 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected"));
293 QDeclarativeStringConverters::timeFromString(value.asString(), &ok);
294 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected"));
297 case QVariant::DateTime:
300 QDeclarativeStringConverters::dateTimeFromString(value.asString(), &ok);
301 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected"));
304 #endif // QT_NO_DATESTRING
305 case QVariant::Point:
306 case QVariant::PointF:
309 QPointF point = QDeclarativeStringConverters::pointFFromString(value.asString(), &ok);
310 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected"));
314 case QVariant::SizeF:
317 QSizeF size = QDeclarativeStringConverters::sizeFFromString(value.asString(), &ok);
318 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected"));
322 case QVariant::RectF:
325 QRectF rect = QDeclarativeStringConverters::rectFFromString(value.asString(), &ok);
326 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected"));
331 if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected"));
334 case QVariant::Vector3D:
337 QDeclarativeStringConverters::vector3DFromString(value.asString(), &ok);
338 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected"));
341 case QVariant::Vector4D:
344 QDeclarativeStringConverters::vector4DFromString(string, &ok);
345 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 4D vector expected"));
350 QDeclarativeMetaType::StringConverter converter = QDeclarativeMetaType::customStringConverter(type);
352 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName((QVariant::Type)type))));
360 Generate a store instruction for assigning literal \a v to property \a prop.
362 Any literal assignment that is approved in testLiteralAssignment() must have
363 a corresponding action in this method.
365 void QDeclarativeCompiler::genLiteralAssignment(QDeclarativeParser::Property *prop,
366 QDeclarativeParser::Value *v)
368 QDeclarativeInstruction instr;
370 if (prop->core.isEnum()) {
371 Q_ASSERT(v->value.isNumber());
373 int value = (int)v->value.asNumber();
375 instr.setType(QDeclarativeInstruction::StoreInteger);
376 instr.storeInteger.propertyIndex = prop->index;
377 instr.storeInteger.value = value;
378 output->addInstruction(instr);
382 int type = prop->type;
384 case QMetaType::QVariant:
386 if (v->value.isNumber()) {
387 double n = v->value.asNumber();
388 if (double(int(n)) == n) {
389 instr.setType(QDeclarativeInstruction::StoreVariantInteger);
390 instr.storeInteger.propertyIndex = prop->index;
391 instr.storeInteger.value = int(n);
393 instr.setType(QDeclarativeInstruction::StoreVariantDouble);
394 instr.storeDouble.propertyIndex = prop->index;
395 instr.storeDouble.value = n;
397 } else if(v->value.isBoolean()) {
398 instr.setType(QDeclarativeInstruction::StoreVariantBool);
399 instr.storeBool.propertyIndex = prop->index;
400 instr.storeBool.value = v->value.asBoolean();
402 instr.setType(QDeclarativeInstruction::StoreVariant);
403 instr.storeString.propertyIndex = prop->index;
404 instr.storeString.value = output->indexForString(v->value.asString());
408 case QVariant::String:
410 instr.setType(QDeclarativeInstruction::StoreString);
411 instr.storeString.propertyIndex = prop->index;
412 instr.storeString.value = output->indexForString(v->value.asString());
415 case QVariant::ByteArray:
417 instr.setType(QDeclarativeInstruction::StoreByteArray);
418 instr.storeByteArray.propertyIndex = prop->index;
419 instr.storeByteArray.value = output->indexForByteArray(v->value.asString().toLatin1());
424 instr.setType(QDeclarativeInstruction::StoreUrl);
425 QString string = v->value.asString();
426 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
427 instr.storeUrl.propertyIndex = prop->index;
428 instr.storeUrl.value = output->indexForUrl(u);
433 instr.setType(QDeclarativeInstruction::StoreInteger);
434 instr.storeInteger.propertyIndex = prop->index;
435 instr.storeInteger.value = uint(v->value.asNumber());
440 instr.setType(QDeclarativeInstruction::StoreInteger);
441 instr.storeInteger.propertyIndex = prop->index;
442 instr.storeInteger.value = int(v->value.asNumber());
445 case QMetaType::Float:
447 instr.setType(QDeclarativeInstruction::StoreFloat);
448 instr.storeFloat.propertyIndex = prop->index;
449 instr.storeFloat.value = float(v->value.asNumber());
452 case QVariant::Double:
454 instr.setType(QDeclarativeInstruction::StoreDouble);
455 instr.storeDouble.propertyIndex = prop->index;
456 instr.storeDouble.value = v->value.asNumber();
459 case QVariant::Color:
461 QColor c = QDeclarativeStringConverters::colorFromString(v->value.asString());
462 instr.setType(QDeclarativeInstruction::StoreColor);
463 instr.storeColor.propertyIndex = prop->index;
464 instr.storeColor.value = c.rgba();
467 #ifndef QT_NO_DATESTRING
470 QDate d = QDeclarativeStringConverters::dateFromString(v->value.asString());
471 instr.setType(QDeclarativeInstruction::StoreDate);
472 instr.storeDate.propertyIndex = prop->index;
473 instr.storeDate.value = d.toJulianDay();
478 QTime time = QDeclarativeStringConverters::timeFromString(v->value.asString());
479 instr.setType(QDeclarativeInstruction::StoreTime);
480 instr.storeTime.propertyIndex = prop->index;
481 Q_ASSERT(sizeof(instr.storeTime.time) == sizeof(QTime));
482 ::memcpy(&instr.storeTime.time, &time, sizeof(QTime)); }
485 case QVariant::DateTime:
487 QDateTime dateTime = QDeclarativeStringConverters::dateTimeFromString(v->value.asString());
488 QTime time = dateTime.time();
489 instr.setType(QDeclarativeInstruction::StoreDateTime);
490 instr.storeDateTime.propertyIndex = prop->index;
491 instr.storeDateTime.date = dateTime.date().toJulianDay();
492 Q_ASSERT(sizeof(instr.storeDateTime.time) == sizeof(QTime));
493 ::memcpy(&instr.storeDateTime.time, &time, sizeof(QTime));
496 #endif // QT_NO_DATESTRING
497 case QVariant::Point:
500 QPoint point = QDeclarativeStringConverters::pointFFromString(v->value.asString(), &ok).toPoint();
501 instr.setType(QDeclarativeInstruction::StorePoint);
502 instr.storePoint.propertyIndex = prop->index;
503 instr.storePoint.point.xp = point.x();
504 instr.storePoint.point.yp = point.y();
507 case QVariant::PointF:
510 QPointF point = QDeclarativeStringConverters::pointFFromString(v->value.asString(), &ok);
511 instr.setType(QDeclarativeInstruction::StorePointF);
512 instr.storePointF.propertyIndex = prop->index;
513 instr.storePointF.point.xp = point.x();
514 instr.storePointF.point.yp = point.y();
520 QSize size = QDeclarativeStringConverters::sizeFFromString(v->value.asString(), &ok).toSize();
521 instr.setType(QDeclarativeInstruction::StoreSize);
522 instr.storeSize.propertyIndex = prop->index;
523 instr.storeSize.size.wd = size.width();
524 instr.storeSize.size.ht = size.height();
527 case QVariant::SizeF:
530 QSizeF size = QDeclarativeStringConverters::sizeFFromString(v->value.asString(), &ok);
531 instr.setType(QDeclarativeInstruction::StoreSizeF);
532 instr.storeSizeF.propertyIndex = prop->index;
533 instr.storeSizeF.size.wd = size.width();
534 instr.storeSizeF.size.ht = size.height();
540 QRect rect = QDeclarativeStringConverters::rectFFromString(v->value.asString(), &ok).toRect();
541 instr.setType(QDeclarativeInstruction::StoreRect);
542 instr.storeRect.propertyIndex = prop->index;
543 instr.storeRect.rect.x1 = rect.left();
544 instr.storeRect.rect.y1 = rect.top();
545 instr.storeRect.rect.x2 = rect.right();
546 instr.storeRect.rect.y2 = rect.bottom();
549 case QVariant::RectF:
552 QRectF rect = QDeclarativeStringConverters::rectFFromString(v->value.asString(), &ok);
553 instr.setType(QDeclarativeInstruction::StoreRectF);
554 instr.storeRectF.propertyIndex = prop->index;
555 instr.storeRectF.rect.xp = rect.left();
556 instr.storeRectF.rect.yp = rect.top();
557 instr.storeRectF.rect.w = rect.width();
558 instr.storeRectF.rect.h = rect.height();
563 bool b = v->value.asBoolean();
564 instr.setType(QDeclarativeInstruction::StoreBool);
565 instr.storeBool.propertyIndex = prop->index;
566 instr.storeBool.value = b;
569 case QVariant::Vector3D:
572 QVector3D vector = QDeclarativeStringConverters::vector3DFromString(v->value.asString(), &ok);
573 instr.setType(QDeclarativeInstruction::StoreVector3D);
574 instr.storeVector3D.propertyIndex = prop->index;
575 instr.storeVector3D.vector.xp = vector.x();
576 instr.storeVector3D.vector.yp = vector.y();
577 instr.storeVector3D.vector.zp = vector.z();
580 case QVariant::Vector4D:
583 QVector4D vector = QDeclarativeStringConverters::vector4DFromString(string, &ok);
584 instr.setType(QDeclarativeInstruction::StoreVector4D);
585 instr.storeVector4D.propertyIndex = prop.propertyIndex();
586 instr.storeVector4D.vector.xp = vector.x();
587 instr.storeVector4D.vector.yp = vector.y();
588 instr.storeVector4D.vector.zp = vector.z();
589 instr.storeVector4D.vector.wp = vector.w();
594 instr.setType(QDeclarativeInstruction::AssignCustomType);
595 instr.assignCustomType.propertyIndex = prop->index;
596 instr.assignCustomType.primitive = output->indexForString(v->value.asString());
597 instr.assignCustomType.type = type;
601 output->addInstruction(instr);
605 Resets data by clearing the lists that the QDeclarativeCompiler modifies.
607 void QDeclarativeCompiler::reset(QDeclarativeCompiledData *data)
610 data->primitives.clear();
612 data->bytecode.resize(0);
616 Compile \a unit, and store the output in \a out. \a engine is the QDeclarativeEngine
617 with which the QDeclarativeCompiledData will be associated.
619 Returns true on success, false on failure. On failure, the compile errors
620 are available from errors().
622 If the environment variant QML_COMPILER_DUMP is set
623 (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
624 on a successful compiler.
626 bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine,
627 QDeclarativeTypeData *unit,
628 QDeclarativeCompiledData *out)
638 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
639 QList<QDeclarativeScriptParser::TypeReference *> referencedTypes = unit->parser().referencedTypes();
641 for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
642 QDeclarativeCompiledData::TypeReference ref;
644 const QDeclarativeTypeData::TypeReference &tref = resolvedTypes.at(ii);
645 QDeclarativeScriptParser::TypeReference *parserRef = referencedTypes.at(ii);
648 ref.type = tref.type;
649 if (!ref.type->isCreatable()) {
650 QString err = ref.type->noCreationReason();
652 err = tr( "Element is not creatable.");
653 COMPILE_EXCEPTION(parserRef->refObjects.first(), err);
656 if (ref.type->containsRevisionedAttributes()) {
657 QDeclarativeError cacheError;
658 ref.typePropertyCache =
659 QDeclarativeEnginePrivate::get(engine)->cache(ref.type, resolvedTypes.at(ii).minorVersion, cacheError);
661 if (!ref.typePropertyCache) {
662 COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description());
664 ref.typePropertyCache->addref();
667 } else if (tref.typeData) {
668 ref.component = tref.typeData->compiledData();
670 ref.className = parserRef->name;
674 QDeclarativeParser::Object *root = unit->parser().tree();
677 this->engine = engine;
678 this->enginePrivate = QDeclarativeEnginePrivate::get(engine);
680 this->unitRoot = root;
685 out->dumpInstructions();
688 Q_ASSERT(out->rootPropertyCache);
696 this->enginePrivate = 0;
703 void QDeclarativeCompiler::compileTree(QDeclarativeParser::Object *tree)
705 compileState = pool->New<ComponentCompileState>();
707 compileState->root = tree;
709 componentStats->componentStat.lineNumber = tree->location.start.line;
711 // Build global import scripts
712 QStringList importedScriptIndexes;
714 foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
715 importedScriptIndexes.append(script.qualifier);
717 QDeclarativeInstruction import;
718 import.setType(QDeclarativeInstruction::StoreImportedScript);
719 import.storeScript.value = output->scripts.count();
721 QDeclarativeScriptData *scriptData = script.script->scriptData();
722 scriptData->addref();
723 output->scripts << scriptData;
724 output->addInstruction(import);
727 // We generate the importCache before we build the tree so that
728 // it can be used in the binding compiler. Given we "expect" the
729 // QML compilation to succeed, this isn't a waste.
730 output->importCache = new QDeclarativeTypeNameCache(engine);
731 for (int ii = 0; ii < importedScriptIndexes.count(); ++ii)
732 output->importCache->add(importedScriptIndexes.at(ii), ii);
733 unit->imports().populateCache(output->importCache, engine);
735 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
738 QDeclarativeInstruction init;
739 init.setType(QDeclarativeInstruction::Init);
740 init.init.bindingsSize = compileState->bindings.count();
741 init.init.parserStatusSize = compileState->parserStatusCount;
742 init.init.contextCache = genContextCache();
743 if (compileState->compiledBindingData.isEmpty())
744 init.init.compiledBinding = -1;
746 init.init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
747 output->addInstruction(init);
749 if (!compileState->v8BindingProgram.isEmpty()) {
750 QDeclarativeInstruction bindings;
751 bindings.setType(QDeclarativeInstruction::InitV8Bindings);
752 bindings.initV8Bindings.program = output->indexForString(compileState->v8BindingProgram);
753 bindings.initV8Bindings.programIndex = compileState->v8BindingProgramIndex;
754 bindings.initV8Bindings.line = compileState->v8BindingProgramLine;
755 output->addInstruction(bindings);
760 QDeclarativeInstruction def;
761 def.setType(QDeclarativeInstruction::SetDefault);
762 output->addInstruction(def);
764 QDeclarativeInstruction done;
765 done.setType(QDeclarativeInstruction::Done);
766 output->addInstruction(done);
768 Q_ASSERT(tree->metatype);
770 if (tree->metadata.isEmpty()) {
771 output->root = tree->metatype;
773 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
774 output->root = &output->rootData;
776 if (!tree->metadata.isEmpty())
777 enginePrivate->registerCompositeType(output);
780 static bool QStringList_contains(const QStringList &list, const QStringRef &string)
782 for (int ii = 0; ii < list.count(); ++ii)
783 if (list.at(ii) == string)
789 bool QDeclarativeCompiler::buildObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
792 componentStats->componentStat.objects++;
794 Q_ASSERT (obj->type != -1);
795 const QDeclarativeCompiledData::TypeReference &tr =
796 output->types.at(obj->type);
797 obj->metatype = tr.metaObject();
800 obj->typeName = tr.type->qmlTypeName();
802 // This object is a "Component" element
803 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
804 COMPILE_CHECK(buildComponent(obj, ctxt));
808 // Object instantiations reset the binding context
809 BindingContext objCtxt(obj);
811 // Create the synthesized meta object, ignoring aliases
812 COMPILE_CHECK(checkDynamicMeta(obj));
813 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
814 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
816 // Find the native type and check for the QDeclarativeParserStatus interface
817 QDeclarativeType *type = toQmlType(obj);
819 obj->parserStatusCast = type->parserStatusCast();
820 if (obj->parserStatusCast != -1)
821 compileState->parserStatusCount++;
823 // Check if this is a custom parser type. Custom parser types allow
824 // assignments to non-existent properties. These assignments are then
825 // compiled by the type.
826 bool isCustomParser = output->types.at(obj->type).type &&
827 output->types.at(obj->type).type->customParser() != 0;
828 QList<QDeclarativeCustomParserProperty> customProps;
830 // Fetch the list of deferred properties
831 QStringList deferredList = deferredProperties(obj);
833 // Must do id property first. This is to ensure that the id given to any
834 // id reference created matches the order in which the objects are
836 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
837 if (prop->name() == id_string) {
838 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
844 Property *defaultProperty = 0;
845 Property *skipProperty = 0;
846 if (obj->defaultProperty) {
847 defaultProperty = obj->defaultProperty;
849 const QMetaObject *metaObject = obj->metaObject();
850 Q_ASSERT(metaObject);
851 QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
853 Property *explicitProperty = obj->getProperty(QString::fromUtf8(p.name()), false);
854 if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) {
856 skipProperty = explicitProperty; // We merge the values into defaultProperty
858 // Find the correct insertion point
859 Value *insertPos = 0;
861 for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) {
862 if (!(v->location.start < explicitProperty->values.first()->location.start))
867 defaultProperty->values.insertAfter(insertPos, explicitProperty->values);
873 QDeclarativeCustomParser *cp = 0;
875 cp = output->types.at(obj->type).type->customParser();
877 // Build all explicit properties specified
878 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
880 if (prop == skipProperty)
882 if (prop->name() == id_string)
885 bool canDefer = false;
886 if (isCustomParser) {
887 if (doesPropertyExist(prop, obj) &&
888 (!(cp->flags() & QDeclarativeCustomParser::AcceptsAttachedProperties) ||
889 !isAttachedPropertyName(prop->name()))) {
890 int ids = compileState->ids.count();
891 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
892 canDefer = ids == compileState->ids.count();
893 } else if (isSignalPropertyName(prop->name()) &&
894 (cp->flags() & QDeclarativeCustomParser::AcceptsSignalHandlers)) {
895 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
897 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
900 if (isSignalPropertyName(prop->name())) {
901 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
903 int ids = compileState->ids.count();
904 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
905 canDefer = ids == compileState->ids.count();
909 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
910 prop->isDeferred = true;
914 // Build the default property
915 if (defaultProperty) {
916 Property *prop = defaultProperty;
918 bool canDefer = false;
919 if (isCustomParser) {
920 if (doesPropertyExist(prop, obj)) {
921 int ids = compileState->ids.count();
922 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
923 canDefer = ids == compileState->ids.count();
925 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
928 int ids = compileState->ids.count();
929 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
930 canDefer = ids == compileState->ids.count();
933 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
934 prop->isDeferred = true;
937 // Compile custom parser parts
938 if (isCustomParser && !customProps.isEmpty()) {
942 obj->custom = cp->compile(customProps);
945 foreach (QDeclarativeError err, cp->errors()) {
946 err.setUrl(output->url);
954 void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj)
956 QDeclarativeCompiledData::TypeReference &tr = output->types[obj->type];
957 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
963 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
964 !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) {
966 QDeclarativeInstruction create;
967 create.setType(QDeclarativeInstruction::CreateSimpleObject);
968 create.createSimple.create = output->types.at(obj->type).type->createFunction();
969 create.createSimple.typeSize = output->types.at(obj->type).type->createSize();
970 create.createSimple.type = obj->type;
971 create.createSimple.line = obj->location.start.line;
972 create.createSimple.column = obj->location.start.column;
973 output->addInstruction(create);
977 QDeclarativeInstruction create;
978 create.setType(QDeclarativeInstruction::CreateObject);
979 create.create.line = obj->location.start.line;
980 create.create.column = obj->location.start.column;
981 create.create.data = -1;
982 if (!obj->custom.isEmpty())
983 create.create.data = output->indexForByteArray(obj->custom);
984 create.create.type = obj->type;
985 if (!output->types.at(create.create.type).type &&
986 !obj->bindingBitmask.isEmpty()) {
987 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
988 create.create.bindingBits =
989 output->indexForByteArray(obj->bindingBitmask);
991 create.create.bindingBits = -1;
993 output->addInstruction(create);
997 // Setup the synthesized meta object if necessary
998 if (!obj->metadata.isEmpty()) {
999 QDeclarativeInstruction meta;
1000 meta.setType(QDeclarativeInstruction::StoreMetaObject);
1001 meta.storeMeta.data = output->indexForByteArray(obj->metadata);
1002 meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata);
1003 meta.storeMeta.propertyCache = output->propertyCaches.count();
1005 QDeclarativePropertyCache *propertyCache = obj->synthCache;
1006 Q_ASSERT(propertyCache);
1007 propertyCache->addref();
1009 // Add flag for alias properties
1010 if (!obj->synthdata.isEmpty()) {
1011 const QDeclarativeVMEMetaData *vmeMetaData =
1012 reinterpret_cast<const QDeclarativeVMEMetaData *>(obj->synthdata.constData());
1013 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
1014 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
1015 QDeclarativePropertyCache::Data *data = propertyCache->property(index);
1016 data->setFlags(data->getFlags() | QDeclarativePropertyCache::Data::IsAlias);
1020 if (obj == unitRoot) {
1021 propertyCache->addref();
1022 output->rootPropertyCache = propertyCache;
1025 output->propertyCaches << propertyCache;
1026 output->addInstruction(meta);
1027 } else if (obj == unitRoot) {
1028 output->rootPropertyCache = tr.createPropertyCache(engine);
1029 output->rootPropertyCache->addref();
1032 // Set the object id
1033 if (!obj->id.isEmpty()) {
1034 QDeclarativeInstruction id;
1035 id.setType(QDeclarativeInstruction::SetId);
1036 id.setId.value = output->indexForString(obj->id);
1037 id.setId.index = obj->idIndex;
1038 output->addInstruction(id);
1042 if (tr.type && obj->parserStatusCast != -1) {
1043 QDeclarativeInstruction begin;
1044 begin.setType(QDeclarativeInstruction::BeginObject);
1045 begin.begin.castValue = obj->parserStatusCast;
1046 output->addInstruction(begin);
1052 void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj)
1054 for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1055 Q_ASSERT(prop->scriptStringScope != -1);
1056 const QString &script = prop->values.first()->value.asScript();
1057 QDeclarativeInstruction ss;
1058 ss.setType(QDeclarativeInstruction::StoreScriptString);
1059 ss.storeScriptString.propertyIndex = prop->index;
1060 ss.storeScriptString.value = output->indexForString(script);
1061 ss.storeScriptString.scope = prop->scriptStringScope;
1062 // ss.storeScriptString.bindingId = rewriteBinding(script, prop->name());
1063 ss.storeScriptString.bindingId = rewriteBinding(script, QString()); // XXX
1064 ss.storeScriptString.line = prop->location.start.line;
1065 output->addInstruction(ss);
1068 bool seenDefer = false;
1069 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1070 if (prop->isDeferred) {
1075 genValueProperty(prop, obj);
1078 QDeclarativeInstruction defer;
1079 defer.setType(QDeclarativeInstruction::Defer);
1080 defer.defer.deferCount = 0;
1081 int deferIdx = output->addInstruction(defer);
1082 int nextInstructionIndex = output->nextInstructionIndex();
1084 QDeclarativeInstruction init;
1085 init.setType(QDeclarativeInstruction::Init);
1086 init.init.bindingsSize = compileState->bindings.count(); // XXX - bigger than necessary
1087 init.init.parserStatusSize = compileState->parserStatusCount; // XXX - bigger than necessary
1088 init.init.contextCache = -1;
1089 init.init.compiledBinding = -1;
1090 output->addInstruction(init);
1092 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1093 if (!prop->isDeferred)
1095 genValueProperty(prop, obj);
1098 QDeclarativeInstruction done;
1099 done.setType(QDeclarativeInstruction::Done);
1100 output->addInstruction(done);
1102 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1105 for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1107 QDeclarativeParser::Value *v = prop->values.first();
1109 if (v->type == Value::SignalObject) {
1111 genObject(v->object);
1113 QDeclarativeInstruction assign;
1114 assign.setType(QDeclarativeInstruction::AssignSignalObject);
1115 assign.assignSignalObject.line = v->location.start.line;
1116 assign.assignSignalObject.signal = output->indexForString(prop->name().toString());
1117 output->addInstruction(assign);
1119 } else if (v->type == Value::SignalExpression) {
1121 QDeclarativeInstruction store;
1122 store.setType(QDeclarativeInstruction::StoreSignal);
1123 store.storeSignal.signalIndex = prop->index;
1124 store.storeSignal.value =
1125 output->indexForString(v->value.asScript().trimmed());
1126 store.storeSignal.context = v->signalExpressionContextStack;
1127 store.storeSignal.name = output->indexForByteArray(prop->name().toUtf8());
1128 store.storeSignal.line = v->location.start.line;
1129 output->addInstruction(store);
1135 for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1136 QDeclarativeInstruction fetch;
1137 fetch.setType(QDeclarativeInstruction::FetchAttached);
1138 fetch.fetchAttached.id = prop->index;
1139 fetch.fetchAttached.line = prop->location.start.line;
1140 output->addInstruction(fetch);
1142 genObjectBody(prop->value);
1144 QDeclarativeInstruction pop;
1145 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1146 output->addInstruction(pop);
1149 for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1150 QDeclarativeInstruction fetch;
1151 fetch.setType(QDeclarativeInstruction::FetchObject);
1152 fetch.fetch.property = prop->index;
1153 fetch.fetch.line = prop->location.start.line;
1154 output->addInstruction(fetch);
1156 if (!prop->value->metadata.isEmpty()) {
1157 QDeclarativeInstruction meta;
1158 meta.setType(QDeclarativeInstruction::StoreMetaObject);
1159 meta.storeMeta.data = output->indexForByteArray(prop->value->metadata);
1160 meta.storeMeta.aliasData = output->indexForByteArray(prop->value->synthdata);
1161 meta.storeMeta.propertyCache = -1;
1162 output->addInstruction(meta);
1165 genObjectBody(prop->value);
1167 QDeclarativeInstruction pop;
1168 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1169 output->addInstruction(pop);
1172 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1174 genValueTypeProperty(obj, prop);
1177 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1178 if (prop->isDeferred)
1181 genValueProperty(prop, obj);
1184 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1186 genValueTypeProperty(obj, prop);
1190 void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeParser::Object *obj,QDeclarativeParser::Property *prop)
1192 QDeclarativeInstruction fetch;
1193 fetch.setType(QDeclarativeInstruction::FetchValueType);
1194 fetch.fetchValue.property = prop->index;
1195 fetch.fetchValue.type = prop->type;
1196 fetch.fetchValue.bindingSkipList = 0;
1198 if (obj->type == -1 || output->types.at(obj->type).component) {
1199 // We only have to do this if this is a composite type. If it is a builtin
1200 // type it can't possibly already have bindings that need to be cleared.
1201 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1202 if (!vprop->values.isEmpty()) {
1203 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1204 fetch.fetchValue.bindingSkipList |= (1 << vprop->index);
1209 output->addInstruction(fetch);
1211 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1212 genPropertyAssignment(vprop, prop->value, prop);
1215 QDeclarativeInstruction pop;
1216 pop.setType(QDeclarativeInstruction::PopValueType);
1217 pop.fetchValue.property = prop->index;
1218 pop.fetchValue.type = prop->type;
1219 pop.fetchValue.bindingSkipList = 0;
1220 output->addInstruction(pop);
1223 void QDeclarativeCompiler::genComponent(QDeclarativeParser::Object *obj)
1225 QDeclarativeParser::Object *root = obj->defaultProperty->values.first()->object;
1228 QDeclarativeInstruction create;
1229 create.setType(QDeclarativeInstruction::CreateComponent);
1230 create.createComponent.line = root->location.start.line;
1231 create.createComponent.column = root->location.start.column;
1232 create.createComponent.endLine = root->location.end.line;
1233 int createInstruction = output->addInstruction(create);
1234 int nextInstructionIndex = output->nextInstructionIndex();
1236 ComponentCompileState *oldCompileState = compileState;
1237 compileState = componentState(root);
1239 QDeclarativeInstruction init;
1240 init.setType(QDeclarativeInstruction::Init);
1241 init.init.bindingsSize = compileState->bindings.count();
1242 init.init.parserStatusSize = compileState->parserStatusCount;
1243 init.init.contextCache = genContextCache();
1244 if (compileState->compiledBindingData.isEmpty())
1245 init.init.compiledBinding = -1;
1247 init.init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
1248 output->addInstruction(init);
1250 if (!compileState->v8BindingProgram.isEmpty()) {
1251 QDeclarativeInstruction bindings;
1252 bindings.setType(QDeclarativeInstruction::InitV8Bindings);
1253 bindings.initV8Bindings.program = output->indexForString(compileState->v8BindingProgram);
1254 bindings.initV8Bindings.programIndex = compileState->v8BindingProgramIndex;
1255 bindings.initV8Bindings.line = compileState->v8BindingProgramLine;
1256 output->addInstruction(bindings);
1261 QDeclarativeInstruction def;
1262 def.setType(QDeclarativeInstruction::SetDefault);
1263 output->addInstruction(def);
1265 QDeclarativeInstruction done;
1266 done.setType(QDeclarativeInstruction::Done);
1267 output->addInstruction(done);
1269 output->instruction(createInstruction)->createComponent.count =
1270 output->nextInstructionIndex() - nextInstructionIndex;
1272 compileState = oldCompileState;
1274 if (!obj->id.isEmpty()) {
1275 QDeclarativeInstruction id;
1276 id.setType(QDeclarativeInstruction::SetId);
1277 id.setId.value = output->indexForString(obj->id);
1278 id.setId.index = obj->idIndex;
1279 output->addInstruction(id);
1282 if (obj == unitRoot) {
1283 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1284 output->rootPropertyCache->addref();
1288 bool QDeclarativeCompiler::buildComponent(QDeclarativeParser::Object *obj,
1289 const BindingContext &ctxt)
1291 // The special "Component" element can only have the id property and a
1292 // default property, that actually defines the component's tree
1294 // Find, check and set the "id" property (if any)
1295 Property *idProp = 0;
1296 if (obj->properties.isMany() ||
1297 (obj->properties.isOne() && obj->properties.first()->name() != id_string))
1298 COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
1300 if (!obj->properties.isEmpty())
1301 idProp = obj->properties.first();
1304 if (idProp->value || idProp->values.isMany() || idProp->values.first()->object)
1305 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1306 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1308 QString idVal = idProp->values.first()->primitive();
1310 if (compileState->ids.value(idVal))
1311 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1317 // Check the Component tree is well formed
1318 if (obj->defaultProperty &&
1319 (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
1320 (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
1321 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1323 if (!obj->dynamicProperties.isEmpty())
1324 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1325 if (!obj->dynamicSignals.isEmpty())
1326 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1327 if (!obj->dynamicSlots.isEmpty())
1328 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1330 QDeclarativeParser::Object *root = 0;
1331 if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
1332 root = obj->defaultProperty->values.first()->object;
1335 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1337 // Build the component tree
1338 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1343 bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeParser::Object *obj,
1344 const BindingContext &ctxt)
1346 ComponentCompileState *oldComponentCompileState = compileState;
1347 compileState = pool->New<ComponentCompileState>();
1348 compileState->root = obj;
1349 compileState->nested = true;
1351 if (componentStats) {
1352 ComponentStat oldComponentStat = componentStats->componentStat;
1354 componentStats->componentStat = ComponentStat();
1355 componentStats->componentStat.lineNumber = obj->location.start.line;
1358 COMPILE_CHECK(buildObject(obj, ctxt));
1360 COMPILE_CHECK(completeComponentBuild());
1362 componentStats->componentStat = oldComponentStat;
1365 COMPILE_CHECK(buildObject(obj, ctxt));
1367 COMPILE_CHECK(completeComponentBuild());
1370 compileState = oldComponentCompileState;
1376 // Build a sub-object. A sub-object is one that was not created directly by
1377 // QML - such as a grouped property object, or an attached object. Sub-object's
1378 // can't have an id, involve a custom parser, have attached properties etc.
1379 bool QDeclarativeCompiler::buildSubObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
1381 Q_ASSERT(obj->metatype);
1382 Q_ASSERT(!obj->defaultProperty);
1383 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1386 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1387 if (isSignalPropertyName(prop->name())) {
1388 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1390 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1397 int QDeclarativeCompiler::componentTypeRef()
1399 QDeclarativeType *t = QDeclarativeMetaType::qmlType("QtQuick/Component",2,0);
1400 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1401 if (output->types.at(ii).type == t)
1404 QDeclarativeCompiledData::TypeReference ref;
1405 ref.className = Component_string;
1407 output->types << ref;
1408 return output->types.count() - 1;
1411 bool QDeclarativeCompiler::buildSignal(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj,
1412 const BindingContext &ctxt)
1414 Q_ASSERT(obj->metaObject());
1416 QStringRef propName = prop->name();
1417 Q_ASSERT(propName.startsWith(on_string));
1418 QString name = propName.string()->mid(propName.position() + 2, propName.length() - 2);
1420 // Note that the property name could start with any alpha or '_' or '$' character,
1421 // so we need to do the lower-casing of the first alpha character.
1422 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1423 if (QDeclarativeUtils::isUpper(name.at(firstAlphaIndex))) {
1424 name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1429 bool notInRevision = false;
1431 QDeclarativePropertyCache::Data *sig = signal(obj, QStringRef(&name), ¬InRevision);
1435 if (notInRevision && 0 == property(obj, propName, 0)) {
1436 Q_ASSERT(obj->type != -1);
1437 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1438 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1440 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));
1442 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1446 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1448 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1452 if (prop->value || !prop->values.isOne())
1453 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1455 prop->index = sig->coreIndex;
1458 obj->addSignalProperty(prop);
1460 if (prop->values.first()->object) {
1461 COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1462 prop->values.first()->type = Value::SignalObject;
1464 prop->values.first()->type = Value::SignalExpression;
1466 if (!prop->values.first()->value.isScript())
1467 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1469 QString script = prop->values.first()->value.asScript().trimmed();
1470 if (script.isEmpty())
1471 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1473 prop->values.first()->signalExpressionContextStack = ctxt.stack;
1482 Returns true if (value) property \a prop exists on obj, false otherwise.
1484 bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeParser::Property *prop,
1485 QDeclarativeParser::Object *obj)
1487 if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1490 if (prop->isDefault) {
1491 const QMetaObject *mo = obj->metaObject();
1492 QMetaProperty p = QDeclarativeMetaType::defaultProperty(mo);
1493 return p.name() != 0;
1495 return property(obj, prop->name()) != 0;
1499 bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop,
1500 QDeclarativeParser::Object *obj,
1501 const BindingContext &ctxt)
1503 if (prop->isEmpty())
1504 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1506 const QMetaObject *metaObject = obj->metaObject();
1507 Q_ASSERT(metaObject);
1509 if (isAttachedPropertyName(prop->name())) {
1510 // Setup attached property data
1512 if (ctxt.isSubContext()) {
1513 // Attached properties cannot be used on sub-objects. Sub-objects
1514 // always exist in a binding sub-context, which is what we test
1516 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1519 QDeclarativeType *type = 0;
1520 QDeclarativeImportedNamespace *typeNamespace = 0;
1521 unit->imports().resolveType(prop->name().toUtf8(), &type, 0, 0, 0, &typeNamespace);
1523 if (typeNamespace) {
1524 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1527 } else if (!type || !type->attachedPropertiesType()) {
1528 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1532 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1534 Q_ASSERT(type->attachedPropertiesFunction());
1535 prop->index = type->attachedPropertiesId();
1536 prop->value->metatype = type->attachedPropertiesType();
1538 // Setup regular property data
1540 if (prop->isDefault) {
1541 QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
1544 prop->setName(QString::fromLatin1(p.name()));
1546 QDeclarativePropertyCache::Data *d = property(obj, p.propertyIndex());
1547 prop->index = d->coreIndex;
1552 bool notInRevision = false;
1553 QDeclarativePropertyCache::Data *d = property(obj, prop->name(), ¬InRevision);
1555 if (d == 0 && notInRevision) {
1556 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1557 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1559 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));
1561 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1564 prop->index = d->coreIndex;
1569 // We can't error here as the "id" property does not require a
1570 // successful index resolution
1571 if (prop->index != -1)
1572 prop->type = prop->core.propType;
1574 // Check if this is an alias
1575 if (prop->index != -1 &&
1577 prop->parent->type != -1 &&
1578 output->types.at(prop->parent->type).component) {
1580 QDeclarativePropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1581 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1582 prop->isAlias = true;
1585 if (prop->index != -1 && !prop->values.isEmpty())
1586 prop->parent->setBindingBit(prop->index);
1589 if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1591 // The magic "id" behavior doesn't apply when "id" is resolved as a
1592 // default property or to sub-objects (which are always in binding
1594 COMPILE_CHECK(buildIdProperty(prop, obj));
1595 if (prop->type == QVariant::String &&
1596 prop->values.first()->value.isString())
1597 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1599 } else if (isAttachedPropertyName(prop->name())) {
1601 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1603 } else if (prop->index == -1) {
1605 if (prop->isDefault) {
1606 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1608 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1611 } else if (prop->value) {
1613 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1615 } else if (enginePrivate->isList(prop->type)) {
1617 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1619 } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) {
1621 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1625 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1632 bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
1633 QDeclarativeParser::Property *nsProp,
1634 QDeclarativeParser::Object *obj,
1635 const BindingContext &ctxt)
1638 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1640 for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1642 if (!isAttachedPropertyName(prop->name()))
1643 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1645 // Setup attached property data
1647 QDeclarativeType *type = 0;
1648 unit->imports().resolveType(ns, prop->name().toUtf8(), &type, 0, 0, 0);
1650 if (!type || !type->attachedPropertiesType())
1651 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1654 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1656 Q_ASSERT(type->attachedPropertiesFunction());
1657 prop->index = type->index();
1658 prop->value->metatype = type->attachedPropertiesType();
1660 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1666 void QDeclarativeCompiler::genValueProperty(QDeclarativeParser::Property *prop,
1667 QDeclarativeParser::Object *obj)
1669 if (enginePrivate->isList(prop->type)) {
1670 genListProperty(prop, obj);
1672 genPropertyAssignment(prop, obj);
1676 void QDeclarativeCompiler::genListProperty(QDeclarativeParser::Property *prop,
1677 QDeclarativeParser::Object *obj)
1679 int listType = enginePrivate->listType(prop->type);
1681 QDeclarativeInstruction fetch;
1682 fetch.setType(QDeclarativeInstruction::FetchQList);
1683 fetch.fetchQmlList.property = prop->index;
1684 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1685 fetch.fetchQmlList.type = listType;
1686 output->addInstruction(fetch);
1688 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1690 if (v->type == Value::CreatedObject) {
1692 genObject(v->object);
1693 if (listTypeIsInterface) {
1694 QDeclarativeInstruction assign;
1695 assign.setType(QDeclarativeInstruction::AssignObjectList);
1696 assign.assignObjectList.line = prop->location.start.line;
1697 output->addInstruction(assign);
1699 QDeclarativeInstruction store;
1700 store.setType(QDeclarativeInstruction::StoreObjectQList);
1701 output->addInstruction(store);
1704 } else if (v->type == Value::PropertyBinding) {
1706 genBindingAssignment(v, prop, obj);
1712 QDeclarativeInstruction pop;
1713 pop.setType(QDeclarativeInstruction::PopQList);
1714 output->addInstruction(pop);
1717 void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *prop,
1718 QDeclarativeParser::Object *obj,
1719 QDeclarativeParser::Property *valueTypeProperty)
1721 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1723 Q_ASSERT(v->type == Value::CreatedObject ||
1724 v->type == Value::PropertyBinding ||
1725 v->type == Value::Literal);
1727 if (v->type == Value::CreatedObject) {
1729 genObject(v->object);
1731 if (QDeclarativeMetaType::isInterface(prop->type)) {
1733 QDeclarativeInstruction store;
1734 store.setType(QDeclarativeInstruction::StoreInterface);
1735 store.storeObject.line = v->object->location.start.line;
1736 store.storeObject.propertyIndex = prop->index;
1737 output->addInstruction(store);
1739 } else if (prop->type == QMetaType::QVariant) {
1741 QDeclarativeInstruction store;
1742 store.setType(QDeclarativeInstruction::StoreVariantObject);
1743 store.storeObject.line = v->object->location.start.line;
1744 store.storeObject.propertyIndex = prop->index;
1745 output->addInstruction(store);
1749 QDeclarativeInstruction store;
1750 store.setType(QDeclarativeInstruction::StoreObject);
1751 store.storeObject.line = v->object->location.start.line;
1752 store.storeObject.propertyIndex = prop->index;
1753 output->addInstruction(store);
1756 } else if (v->type == Value::PropertyBinding) {
1758 genBindingAssignment(v, prop, obj, valueTypeProperty);
1760 } else if (v->type == Value::Literal) {
1762 genLiteralAssignment(prop, v);
1768 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
1770 Q_ASSERT(v->type == Value::ValueSource ||
1771 v->type == Value::ValueInterceptor);
1773 if (v->type == Value::ValueSource) {
1774 genObject(v->object);
1776 QDeclarativeInstruction store;
1777 store.setType(QDeclarativeInstruction::StoreValueSource);
1778 if (valueTypeProperty) {
1779 store.assignValueSource.property = genValueTypeData(prop, valueTypeProperty);
1780 store.assignValueSource.owner = 1;
1782 store.assignValueSource.property = genPropertyData(prop);
1783 store.assignValueSource.owner = 0;
1785 QDeclarativeType *valueType = toQmlType(v->object);
1786 store.assignValueSource.castValue = valueType->propertyValueSourceCast();
1787 output->addInstruction(store);
1789 } else if (v->type == Value::ValueInterceptor) {
1790 genObject(v->object);
1792 QDeclarativeInstruction store;
1793 store.setType(QDeclarativeInstruction::StoreValueInterceptor);
1794 if (valueTypeProperty) {
1795 store.assignValueInterceptor.property = genValueTypeData(prop, valueTypeProperty);
1796 store.assignValueInterceptor.owner = 1;
1798 store.assignValueInterceptor.property = genPropertyData(prop);
1799 store.assignValueInterceptor.owner = 0;
1801 QDeclarativeType *valueType = toQmlType(v->object);
1802 store.assignValueInterceptor.castValue = valueType->propertyValueInterceptorCast();
1803 output->addInstruction(store);
1809 bool QDeclarativeCompiler::buildIdProperty(QDeclarativeParser::Property *prop,
1810 QDeclarativeParser::Object *obj)
1813 prop->values.isMany() ||
1814 prop->values.first()->object)
1815 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
1817 QDeclarativeParser::Value *idValue = prop->values.first();
1818 QString val = idValue->primitive();
1820 COMPILE_CHECK(checkValidId(idValue, val));
1822 if (compileState->ids.value(val))
1823 COMPILE_EXCEPTION(prop, tr("id is not unique"));
1825 prop->values.first()->type = Value::Id;
1833 void QDeclarativeCompiler::addId(const QString &id, QDeclarativeParser::Object *obj)
1835 Q_ASSERT(!compileState->ids.value(id));
1836 Q_ASSERT(obj->id == id);
1837 obj->idIndex = compileState->ids.count();
1838 compileState->ids.append(obj);
1841 void QDeclarativeCompiler::addBindingReference(BindingReference *ref)
1843 Q_ASSERT(ref->value && !ref->value->bindingReference);
1844 ref->value->bindingReference = ref;
1845 compileState->bindings.prepend(ref);
1848 void QDeclarativeCompiler::saveComponentState()
1850 Q_ASSERT(compileState->root);
1851 Q_ASSERT(compileState->root->componentCompileState == 0);
1853 compileState->root->componentCompileState = compileState;
1856 componentStats->savedComponentStats.append(componentStats->componentStat);
1859 QDeclarativeCompilerTypes::ComponentCompileState *
1860 QDeclarativeCompiler::componentState(QDeclarativeParser::Object *obj)
1862 Q_ASSERT(obj->componentCompileState);
1863 return obj->componentCompileState;
1866 // Build attached property object. In this example,
1870 // GridView is an attached property object.
1871 bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeParser::Property *prop,
1872 QDeclarativeParser::Object *obj,
1873 const BindingContext &ctxt)
1875 Q_ASSERT(prop->value);
1876 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
1878 obj->addAttachedProperty(prop);
1880 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1886 // Build "grouped" properties. In this example:
1888 // font.pointSize: 12
1889 // font.family: "Helvetica"
1891 // font is a nested property. pointSize and family are not.
1892 bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeParser::Property *prop,
1893 QDeclarativeParser::Object *obj,
1894 const BindingContext &ctxt)
1896 Q_ASSERT(prop->type != 0);
1897 Q_ASSERT(prop->index != -1);
1899 if (QDeclarativeValueTypeFactory::isValueType(prop->type)) {
1900 if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
1902 if (!prop->values.isEmpty()) {
1903 if (prop->values.first()->location < prop->value->location) {
1904 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
1906 COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
1910 if (!obj->metaObject()->property(prop->index).isWritable()) {
1911 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
1915 if (prop->isAlias) {
1916 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
1917 vtProp->isAlias = true;
1921 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
1922 prop->value, obj, ctxt.incr()));
1923 obj->addValueTypeProperty(prop);
1925 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1929 // Load the nested property's meta type
1930 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
1931 if (!prop->value->metatype)
1932 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1934 if (!prop->values.isEmpty())
1935 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
1937 obj->addGroupedProperty(prop);
1939 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1945 bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
1946 QDeclarativeParser::Object *obj,
1947 QDeclarativeParser::Object *baseObj,
1948 const BindingContext &ctxt)
1950 if (obj->defaultProperty)
1951 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
1952 obj->metatype = type->metaObject();
1954 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1956 QDeclarativePropertyCache::Data *d = property(obj, prop->name());
1958 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1960 prop->index = d->coreIndex;
1961 prop->type = d->propType;
1963 prop->isValueTypeSubProperty = true;
1966 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
1968 if (prop->values.isMany()) {
1969 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
1970 } else if (!prop->values.isEmpty()) {
1971 QDeclarativeParser::Value *value = prop->values.first();
1973 if (value->object) {
1974 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
1975 } else if (value->value.isScript()) {
1976 // ### Check for writability
1978 //optimization for <Type>.<EnumValue> enum assignments
1979 bool isEnumAssignment = false;
1981 if (prop->core.isEnum())
1982 COMPILE_CHECK(testQualifiedEnumAssignment(obj->metatype->property(prop->index), obj,
1983 value, &isEnumAssignment));
1985 if (isEnumAssignment) {
1986 value->type = Value::Literal;
1988 BindingReference *reference = pool->New<BindingReference>();
1989 reference->expression = value->value;
1990 reference->property = prop;
1991 reference->value = value;
1992 reference->bindingContext = ctxt;
1993 reference->bindingContext.owner++;
1994 addBindingReference(reference);
1995 value->type = Value::PropertyBinding;
1998 COMPILE_CHECK(testLiteralAssignment(prop, value));
1999 value->type = Value::Literal;
2003 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2004 Q_ASSERT(v->object);
2006 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
2009 obj->addValueProperty(prop);
2015 // Build assignments to QML lists. QML lists are properties of type
2016 // QDeclarativeListProperty<T>. List properties can accept a list of
2017 // objects, or a single binding.
2018 bool QDeclarativeCompiler::buildListProperty(QDeclarativeParser::Property *prop,
2019 QDeclarativeParser::Object *obj,
2020 const BindingContext &ctxt)
2022 Q_ASSERT(enginePrivate->isList(prop->type));
2026 obj->addValueProperty(prop);
2028 int listType = enginePrivate->listType(t);
2029 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
2031 bool assignedBinding = false;
2032 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2034 v->type = Value::CreatedObject;
2035 COMPILE_CHECK(buildObject(v->object, ctxt));
2037 // We check object coercian here. We check interface assignment
2039 if (!listTypeIsInterface) {
2040 if (!canCoerce(listType, v->object)) {
2041 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2045 } else if (v->value.isScript()) {
2046 if (assignedBinding)
2047 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2049 assignedBinding = true;
2050 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2051 v->type = Value::PropertyBinding;
2053 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2060 // Compiles an assignment to a QDeclarativeScriptString property
2061 bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeParser::Property *prop,
2062 QDeclarativeParser::Object *obj,
2063 const BindingContext &ctxt)
2065 if (prop->values.isMany())
2066 COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2068 if (prop->values.first()->object)
2069 COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2071 prop->scriptStringScope = ctxt.stack;
2072 obj->addScriptStringProperty(prop);
2077 // Compile regular property assignments of the form "property: <value>"
2078 bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeParser::Property *prop,
2079 QDeclarativeParser::Object *obj,
2080 const BindingContext &ctxt)
2082 obj->addValueProperty(prop);
2084 if (prop->values.isMany())
2085 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2087 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2090 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2094 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2099 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2100 Q_ASSERT(v->object);
2101 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2107 // Compile assigning a single object instance to a regular property
2108 bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeParser::Property *prop,
2109 QDeclarativeParser::Object *obj,
2110 QDeclarativeParser::Value *v,
2111 const BindingContext &ctxt)
2113 Q_ASSERT(prop->index != -1);
2114 Q_ASSERT(v->object->type != -1);
2116 if (!obj->metaObject()->property(prop->index).isWritable())
2117 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2119 if (QDeclarativeMetaType::isInterface(prop->type)) {
2121 // Assigning an object to an interface ptr property
2122 COMPILE_CHECK(buildObject(v->object, ctxt));
2124 v->type = Value::CreatedObject;
2126 } else if (prop->type == QMetaType::QVariant) {
2128 // Assigning an object to a QVariant
2129 COMPILE_CHECK(buildObject(v->object, ctxt));
2131 v->type = Value::CreatedObject;
2133 // Normally buildObject() will set this up, but we need the static
2134 // meta object earlier to test for assignability. It doesn't matter
2135 // that there may still be outstanding synthesized meta object changes
2136 // on this type, as they are not relevant for assignability testing
2137 v->object->metatype = output->types.at(v->object->type).metaObject();
2138 Q_ASSERT(v->object->metaObject());
2140 // We want to raw metaObject here as the raw metaobject is the
2141 // actual property type before we applied any extensions that might
2142 // effect the properties on the type, but don't effect assignability
2143 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2145 // Will be true if the assgned type inherits propertyMetaObject
2146 bool isAssignable = false;
2147 // Determine isAssignable value
2148 if (propertyMetaObject) {
2149 const QMetaObject *c = v->object->metatype;
2151 isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject));
2152 c = c->superClass();
2157 // Simple assignment
2158 COMPILE_CHECK(buildObject(v->object, ctxt));
2160 v->type = Value::CreatedObject;
2161 } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) {
2162 // Automatic "Component" insertion
2163 QDeclarativeParser::Object *root = v->object;
2164 QDeclarativeParser::Object *component = pool->New<Object>();
2165 component->type = componentTypeRef();
2166 component->typeName = "Qt/Component";
2167 component->metatype = &QDeclarativeComponent::staticMetaObject;
2168 component->location = root->location;
2169 QDeclarativeParser::Value *componentValue = pool->New<Value>();
2170 componentValue->object = root;
2171 component->getDefaultProperty()->addValue(componentValue);
2172 v->object = component;
2173 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2175 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2182 // Compile assigning a single object instance to a regular property using the "on" syntax.
2186 // NumberAnimation on x { }
2188 bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeParser::Property *prop,
2189 QDeclarativeParser::Object *obj,
2190 QDeclarativeParser::Object *baseObj,
2191 QDeclarativeParser::Value *v,
2192 const BindingContext &ctxt)
2194 Q_ASSERT(prop->index != -1);
2195 Q_ASSERT(v->object->type != -1);
2197 if (!obj->metaObject()->property(prop->index).isWritable())
2198 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2201 // Normally buildObject() will set this up, but we need the static
2202 // meta object earlier to test for assignability. It doesn't matter
2203 // that there may still be outstanding synthesized meta object changes
2204 // on this type, as they are not relevant for assignability testing
2205 v->object->metatype = output->types.at(v->object->type).metaObject();
2206 Q_ASSERT(v->object->metaObject());
2208 // Will be true if the assigned type inherits QDeclarativePropertyValueSource
2209 bool isPropertyValue = false;
2210 // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor
2211 bool isPropertyInterceptor = false;
2212 if (QDeclarativeType *valueType = toQmlType(v->object)) {
2213 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2214 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2217 if (isPropertyValue || isPropertyInterceptor) {
2218 // Assign as a property value source
2219 COMPILE_CHECK(buildObject(v->object, ctxt));
2221 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2222 buildDynamicMeta(baseObj, ForceCreation);
2223 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2225 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(QString::fromUtf8(v->object->typeName)).arg(prop->name().toString()));
2231 // Compile assigning a literal or binding to a regular property
2232 bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeParser::Property *prop,
2233 QDeclarativeParser::Object *obj,
2234 QDeclarativeParser::Value *v,
2235 const BindingContext &ctxt)
2237 Q_ASSERT(prop->index != -1);
2239 if (v->value.isScript()) {
2241 //optimization for <Type>.<EnumValue> enum assignments
2242 if (prop->core.isEnum()) {
2243 bool isEnumAssignment = false;
2244 COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj,
2245 v, &isEnumAssignment));
2246 if (isEnumAssignment) {
2247 v->type = Value::Literal;
2252 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2254 v->type = Value::PropertyBinding;
2258 COMPILE_CHECK(testLiteralAssignment(prop, v));
2260 v->type = Value::Literal;
2266 bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop,
2267 QDeclarativeParser::Object *obj,
2268 QDeclarativeParser::Value *v,
2271 *isAssignment = false;
2272 if (!prop.isEnumType())
2275 if (!prop.isWritable())
2276 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
2278 QString string = v->value.asString();
2279 if (!QDeclarativeUtils::isUpper(string.at(0)))
2282 QStringList parts = string.split(QLatin1Char('.'));
2283 if (parts.count() != 2)
2286 QString typeName = parts.at(0);
2287 QDeclarativeType *type = 0;
2288 unit->imports().resolveType(typeName.toUtf8(), &type, 0, 0, 0, 0);
2290 //handle enums on value types (where obj->typeName is empty)
2291 QByteArray objTypeName = obj->typeName;
2292 if (objTypeName.isEmpty()) {
2293 QDeclarativeType *objType = toQmlType(obj);
2295 objTypeName = objType->qmlTypeName();
2301 QString enumValue = parts.at(1);
2304 if (objTypeName == type->qmlTypeName()) {
2305 // When these two match, we can short cut the search
2306 if (prop.isFlagType()) {
2307 value = prop.enumerator().keysToValue(enumValue.toUtf8().constData());
2309 value = prop.enumerator().keyToValue(enumValue.toUtf8().constData());
2312 // Otherwise we have to search the whole type
2313 // This matches the logic in QV8TypeWrapper
2314 QByteArray enumName = enumValue.toUtf8();
2315 const QMetaObject *metaObject = type->baseMetaObject();
2316 for (int ii = metaObject->enumeratorCount() - 1; value == -1 && ii >= 0; --ii) {
2317 QMetaEnum e = metaObject->enumerator(ii);
2318 value = e.keyToValue(enumName.constData());
2325 v->type = Value::Literal;
2326 v->value = QDeclarativeParser::Variant((double)value);
2327 *isAssignment = true;
2332 struct StaticQtMetaObject : public QObject
2334 static const QMetaObject *get()
2335 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2338 // Similar logic to above, but not knowing target property.
2339 int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const
2341 int dot = script.indexOf('.');
2343 const QByteArray &scope = script.left(dot);
2344 QDeclarativeType *type = 0;
2345 unit->imports().resolveType(scope, &type, 0, 0, 0, 0);
2346 if (!type && scope != "Qt")
2348 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2349 const char *key = script.constData() + dot+1;
2350 int i = mo->enumeratorCount();
2352 int v = mo->enumerator(i).keyToValue(key);
2360 const QMetaObject *QDeclarativeCompiler::resolveType(const QByteArray& name) const
2362 QDeclarativeType *qmltype = 0;
2363 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2367 return qmltype->metaObject();
2370 // similar to logic of completeComponentBuild, but also sticks data
2371 // into primitives at the end
2372 int QDeclarativeCompiler::rewriteBinding(const QString& expression, const QString& name)
2374 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2375 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf('.') + 1));
2377 QString rewrite = rewriteBinding(expression, 0, 0);
2379 return output->indexForString(rewrite);
2382 // Ensures that the dynamic meta specification on obj is valid
2383 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj)
2385 QSet<QByteArray> propNames;
2386 QSet<QByteArray> methodNames;
2387 bool seenDefaultProperty = false;
2390 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2391 const QDeclarativeParser::Object::DynamicProperty &prop =
2392 obj->dynamicProperties.at(ii);
2394 if (prop.isDefaultProperty) {
2395 if (seenDefaultProperty)
2396 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2397 seenDefaultProperty = true;
2400 if (propNames.contains(prop.name))
2401 COMPILE_EXCEPTION(&prop, tr("Duplicate property name"));
2403 QString propName = QString::fromUtf8(prop.name);
2404 if (QDeclarativeUtils::isUpper(propName.at(0)))
2405 COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
2407 if (enginePrivate->v8engine()->illegalNames().contains(propName))
2408 COMPILE_EXCEPTION(&prop, tr("Illegal property name"));
2410 propNames.insert(prop.name);
2413 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2414 const QDeclarativeScript::Object::DynamicSignal &currSig = *s;
2416 if (methodNames.testAndSet(currSig.name.hash())) {
2417 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2418 s2 = obj->dynamicSignals.next(s2)) {
2419 if (s2->name == currSig.name)
2420 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2424 if (currSig.name.at(0).isUpper())
2425 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2426 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2427 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2430 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2431 const QDeclarativeScript::Object::DynamicSlot &currSlot = *s;
2433 if (methodNames.testAndSet(currSlot.name.hash())) {
2434 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2435 s2 = obj->dynamicSignals.next(s2)) {
2436 if (s2->name == currSlot.name)
2437 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2439 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2440 s2 = obj->dynamicSlots.next(s2)) {
2441 if (s2->name == currSlot.name)
2442 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2446 if (currSlot.name.at(0).isUpper())
2447 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2448 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2449 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2455 bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeParser::Object *obj)
2457 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2458 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2460 if (!p.defaultValue || p.type == Object::DynamicProperty::Alias)
2463 Property *property = 0;
2464 if (p.isDefaultProperty) {
2465 property = obj->getDefaultProperty();
2467 property = obj->getProperty(p.name);
2468 if (!property->values.isEmpty())
2469 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2472 if (property->value)
2473 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2475 property->values.append(p.defaultValue->values);
2480 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2482 bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, DynamicMetaMode mode)
2485 Q_ASSERT(obj->metatype);
2487 if (mode != ForceCreation &&
2488 obj->dynamicProperties.isEmpty() &&
2489 obj->dynamicSignals.isEmpty() &&
2490 obj->dynamicSlots.isEmpty())
2493 bool resolveAlias = (mode == ResolveAliases);
2495 const Object::DynamicProperty *defaultProperty = 0;
2498 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2499 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2501 if (p.type == Object::DynamicProperty::Alias)
2504 if (p.isDefaultProperty &&
2505 (resolveAlias || p.type != Object::DynamicProperty::Alias))
2506 defaultProperty = &p;
2508 if (!resolveAlias) {
2509 // No point doing this for both the alias and non alias cases
2510 QString name = QString::fromUtf8(p.name);
2511 QDeclarativePropertyCache::Data *d = property(obj, QStringRef(&name));
2512 if (d && d->isFinal())
2513 COMPILE_EXCEPTION(&p, tr("Cannot override FINAL property"));
2517 bool buildData = resolveAlias || aliasCount == 0;
2519 QByteArray dynamicData;
2521 typedef QDeclarativeVMEMetaData VMD;
2523 dynamicData = QByteArray(sizeof(QDeclarativeVMEMetaData) +
2524 (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) +
2525 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2526 aliasCount * sizeof(VMD::AliasData), 0);
2529 int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1);
2531 QByteArray newClassName = obj->metatype->className();
2532 newClassName.append("_QML_");
2533 newClassName.append(QByteArray::number(uniqueClassId));
2535 if (compileState->root == obj && !compileState->nested) {
2536 QString path = output->url.path();
2537 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2538 if (lastSlash > -1) {
2539 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2540 if (!nameBase.isEmpty() && QDeclarativeUtils::isUpper(nameBase.at(0)))
2541 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId);
2545 QFastMetaBuilder builder;
2546 QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(),
2547 obj->dynamicProperties.count() - (resolveAlias?0:aliasCount),
2548 obj->dynamicSlots.count(),
2549 obj->dynamicSignals.count() + obj->dynamicProperties.count(),
2550 defaultProperty?1:0);
2553 Object::DynamicProperty::Type dtype;
2555 const char *cppType;
2556 } builtinTypes[] = {
2557 { Object::DynamicProperty::Variant, 0, "QVariant" },
2558 { Object::DynamicProperty::Int, QMetaType::Int, "int" },
2559 { Object::DynamicProperty::Bool, QMetaType::Bool, "bool" },
2560 { Object::DynamicProperty::Real, QMetaType::Double, "double" },
2561 { Object::DynamicProperty::String, QMetaType::QString, "QString" },
2562 { Object::DynamicProperty::Url, QMetaType::QUrl, "QUrl" },
2563 { Object::DynamicProperty::Color, QMetaType::QColor, "QColor" },
2564 { Object::DynamicProperty::Time, QMetaType::QTime, "QTime" },
2565 { Object::DynamicProperty::Date, QMetaType::QDate, "QDate" },
2566 { Object::DynamicProperty::DateTime, QMetaType::QDateTime, "QDateTime" },
2568 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2569 QFastMetaBuilder::StringRef typeRefs[builtinTypeCount];
2571 // Reserve dynamic properties
2572 if (obj->dynamicProperties.count()) {
2573 typedef QDeclarativeVMEMetaData VMD;
2575 int effectivePropertyIndex = 0;
2576 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2577 Object::DynamicProperty &p = obj->dynamicProperties[ii];
2579 // Reserve space for name
2580 p.nameRef = builder.newString(p.name.length());
2582 int propertyType = 0;
2583 bool readonly = false;
2584 QFastMetaBuilder::StringRef typeRef;
2586 if (p.type == Object::DynamicProperty::Alias) {
2588 } else if (p.type < builtinTypeCount) {
2589 Q_ASSERT(builtinTypes[p.type].dtype == p.type);
2590 propertyType = builtinTypes[p.type].metaType;
2591 if (typeRefs[p.type].isEmpty())
2592 typeRefs[p.type] = builder.newString(strlen(builtinTypes[p.type].cppType));
2593 typeRef = typeRefs[p.type];
2594 if (p.type == Object::DynamicProperty::Variant)
2595 propertyType = qMetaTypeId<QVariant>();
2598 Q_ASSERT(p.type == Object::DynamicProperty::CustomList ||
2599 p.type == Object::DynamicProperty::Custom);
2601 QByteArray customTypeName;
2602 QDeclarativeType *qmltype = 0;
2604 if (!unit->imports().resolveType(p.customType, &qmltype, &url, 0, 0, 0))
2605 COMPILE_EXCEPTION(&p, tr("Invalid property type"));
2608 QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(QUrl(url));
2610 Q_ASSERT(tdata->isComplete());
2612 QDeclarativeCompiledData *data = tdata->compiledData();
2613 customTypeName = data->root->className();
2617 customTypeName = qmltype->typeName();
2620 if (p.type == Object::DynamicProperty::Custom) {
2621 customTypeName += '*';
2622 propertyType = QMetaType::QObjectStar;
2625 customTypeName = QByteArray("QDeclarativeListProperty<") + customTypeName + QByteArray(">");
2626 propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
2629 p.resolvedCustomTypeName = customTypeName;
2630 p.typeRef = builder.newString(customTypeName.length());
2631 typeRef = p.typeRef;
2635 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2636 vmd->propertyCount++;
2637 (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType;
2640 if (p.type < builtinTypeCount)
2641 builder.setProperty(effectivePropertyIndex, p.nameRef, typeRef, (QMetaType::Type)propertyType,
2642 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2643 effectivePropertyIndex);
2645 builder.setProperty(effectivePropertyIndex, p.nameRef, typeRef,
2646 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2647 effectivePropertyIndex);
2649 p.changedSignatureRef = builder.newString(p.name.length() + strlen("Changed()"));
2650 builder.setSignal(effectivePropertyIndex, p.changedSignatureRef);
2652 effectivePropertyIndex++;
2657 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2658 Object::DynamicProperty &p = obj->dynamicProperties[ii];
2659 if (p.type == Object::DynamicProperty::Alias) {
2661 Q_ASSERT(buildData);
2662 ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++;
2663 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex, aliasIndex, p));
2665 // Even if we aren't resolving the alias, we need a fake signal so that the
2666 // metaobject remains consistent across the resolve and non-resolve alias runs
2667 p.changedSignatureRef = builder.newString(p.name.length() + strlen("Changed()"));
2668 builder.setSignal(effectivePropertyIndex, p.changedSignatureRef);
2669 effectivePropertyIndex++;
2676 // Reserve default property
2677 QFastMetaBuilder::StringRef defPropRef;
2678 if (defaultProperty) {
2679 defPropRef = builder.newString(strlen("DefaultProperty"));
2680 builder.setClassInfo(0, defPropRef, defaultProperty->nameRef);
2683 // Reserve dynamic signals
2684 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2685 Object::DynamicSignal &s = obj->dynamicSignals[ii];
2687 int paramCount = s.parameterNames.count();
2689 int signatureSize = s.name.length() + 2 /* paren */;
2691 if (paramCount) signatureSize += s.parameterTypesLength() + (paramCount - 1) /* commas */;
2692 if (paramCount) namesSize += s.parameterNamesLength() + (paramCount - 1) /* commas */;
2694 s.signatureRef = builder.newString(signatureSize);
2695 if (namesSize) s.parameterNamesRef = builder.newString(namesSize);
2698 ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++;
2700 builder.setSignal(ii + obj->dynamicProperties.count(), s.signatureRef, s.parameterNamesRef);
2703 // Reserve dynamic slots
2704 if (obj->dynamicSlots.count()) {
2706 // Allocate QVariant string
2707 if (typeRefs[0].isEmpty())
2708 typeRefs[0] = builder.newString(strlen(builtinTypes[0].cppType));
2710 typedef QDeclarativeVMEMetaData VMD;
2712 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2713 Object::DynamicSlot &s = obj->dynamicSlots[ii];
2714 int paramCount = s.parameterNames.count();
2716 int signatureSize = s.name.length() + 2 /* paren */;
2718 if (paramCount) signatureSize += (paramCount * strlen("QVariant") + (paramCount - 1));
2719 if (paramCount) namesSize += s.parameterNamesLength() + (paramCount - 1 /* commas */);
2721 s.signatureRef = builder.newString(signatureSize);
2722 if (namesSize) s.parameterNamesRef = builder.newString(namesSize);
2724 builder.setMethod(ii, s.signatureRef, s.parameterNamesRef, typeRefs[0]);
2728 funcScript.reserve(strlen("(function ") + s.name.length() + 1 /* lparen */ +
2729 namesSize + 1 /* rparen */ + s.body.length() + 1 /* rparen */);
2730 funcScript = QLatin1String("(function ") + s.name + QLatin1Char('(');
2731 for (int jj = 0; jj < paramCount; ++jj) {
2732 if (jj) funcScript.append(QLatin1Char(','));
2733 funcScript.append(QLatin1String(s.parameterNames.at(jj)));
2735 funcScript += QLatin1Char(')') + s.body + QLatin1Char(')');
2737 VMD::MethodData methodData = { s.parameterNames.count(), 0,
2738 funcScript.length(),
2739 s.location.start.line };
2741 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2744 VMD::MethodData &md = *(vmd->methodData() + ii);
2746 md.bodyOffset = dynamicData.size();
2748 dynamicData.append((const char *)funcScript.constData(),
2749 (funcScript.length() * sizeof(QChar)));
2755 // Now allocate used builtin types
2756 for (int ii = 0; ii < builtinTypeCount; ++ii) {
2757 if (!typeRefs[ii].isEmpty())
2758 typeRefs[ii].load(builtinTypes[ii].cppType);
2761 // Now allocate properties
2762 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2763 Object::DynamicProperty &p = obj->dynamicProperties[ii];
2765 char *d = p.changedSignatureRef.data();
2766 strcpy(d, p.name.constData());
2767 strcpy(d + p.name.length(), "Changed()");
2769 if (p.type == Object::DynamicProperty::Alias && !resolveAlias)
2772 p.nameRef.load(p.name);
2774 if (p.type >= builtinTypeCount)
2775 p.typeRef.load(p.resolvedCustomTypeName);
2778 // Allocate default property if necessary
2779 if (defaultProperty)
2780 strcpy(defPropRef.data(), "DefaultProperty");
2782 // Now allocate signals
2783 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2784 Object::DynamicSignal &s = obj->dynamicSignals[ii];
2786 char *d = s.signatureRef.data();
2787 char *d2 = s.parameterNamesRef.isEmpty()?0:s.parameterNamesRef.data();
2788 strcpy(d, s.name.constData());
2789 d += s.name.length();
2792 for (int jj = 0; jj < s.parameterNames.count(); ++jj) {
2793 if (jj != 0) { *d++ = ','; *d2++ = ','; }
2794 strcpy(d, s.parameterTypes.at(jj).constData());
2795 d += s.parameterTypes.at(jj).length();
2796 strcpy(d2, s.parameterNames.at(jj).constData());
2797 d2 += s.parameterNames.at(jj).length();
2804 // Now allocate methods
2805 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2806 Object::DynamicSlot &s = obj->dynamicSlots[ii];
2807 char *d = s.signatureRef.data();
2808 char *d2 = s.parameterNamesRef.isEmpty()?0:s.parameterNamesRef.data();
2809 strcpy(d, s.name.constData());
2810 d += s.name.length();
2812 for (int jj = 0; jj < s.parameterNames.count(); ++jj) {
2813 if (jj != 0) { *d++ = ','; *d2++ = ','; }
2814 strcpy(d, "QVariant");
2815 d += strlen("QVariant");
2816 strcpy(d2, s.parameterNames.at(jj).constData());
2817 d2 += s.parameterNames.at(jj).length();
2824 // Now allocate class name
2825 classNameRef.load(newClassName);
2827 obj->metadata = builder.toData();
2828 builder.fromData(&obj->extObject, obj->metatype, obj->metadata);
2830 if (mode == IgnoreAliases && aliasCount)
2831 compileState->aliasingObjects.append(obj);
2833 obj->synthdata = dynamicData;
2835 if (obj->synthCache) {
2836 obj->synthCache->release();
2837 obj->synthCache = 0;
2840 if (obj->type != -1) {
2841 QDeclarativePropertyCache *cache = output->types[obj->type].createPropertyCache(engine)->copy();
2842 cache->append(engine, &obj->extObject, QDeclarativePropertyCache::Data::NoFlags,
2843 QDeclarativePropertyCache::Data::IsVMEFunction,
2844 QDeclarativePropertyCache::Data::IsVMESignal);
2845 obj->synthCache = cache;
2851 bool QDeclarativeCompiler::checkValidId(QDeclarativeParser::Value *v, const QString &val)
2854 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
2856 QChar ch = val.at(0);
2857 if (QDeclarativeUtils::isLetter(ch) && !QDeclarativeUtils::isLower(ch))
2858 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
2860 QChar u(QLatin1Char('_'));
2861 if (!QDeclarativeUtils::isLetter(ch) && ch != u)
2862 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
2864 for (int ii = 1; ii < val.count(); ++ii) {
2866 if (!QDeclarativeUtils::isLetterOrNumber(ch) && ch != u)
2867 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
2870 if (enginePrivate->v8engine()->illegalNames().contains(val))
2871 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
2876 #include <qdeclarativejsparser_p.h>
2878 static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node)
2880 if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) {
2882 static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name.toString();
2883 return QStringList() << name;
2884 } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) {
2885 QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node);
2887 QStringList rv = astNodeToStringList(expr->base);
2890 rv.append(expr->name.toString());
2893 return QStringList();
2896 bool QDeclarativeCompiler::compileAlias(QFastMetaBuilder &builder,
2898 QDeclarativeParser::Object *obj,
2899 int propIndex, int aliasIndex,
2900 Object::DynamicProperty &prop)
2902 if (!prop.defaultValue)
2903 COMPILE_EXCEPTION(obj, tr("No property alias location"));
2905 if (!prop.defaultValue->values.isOne() ||
2906 prop.defaultValue->values.first()->object ||
2907 !prop.defaultValue->values.first()->value.isScript())
2908 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2910 QDeclarativeJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST();
2912 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
2914 QStringList alias = astNodeToStringList(node);
2916 if (alias.count() < 1 || alias.count() > 3)
2917 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
2919 QDeclarativeParser::Object *idObject = compileState->ids.value(alias.at(0));
2921 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
2923 QByteArray typeName;
2928 bool writable = false;
2929 bool resettable = false;
2930 if (alias.count() == 2 || alias.count() == 3) {
2931 propIdx = indexOfProperty(idObject, alias.at(1));
2933 if (-1 == propIdx) {
2934 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2935 } else if (propIdx > 0xFFFF) {
2936 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
2939 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
2940 if (!aliasProperty.isScriptable())
2941 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2943 writable = aliasProperty.isWritable();
2944 resettable = aliasProperty.isResettable();
2946 if (aliasProperty.type() < QVariant::UserType)
2947 type = aliasProperty.type();
2949 if (alias.count() == 3) {
2950 QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
2952 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2954 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
2956 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
2957 if (valueTypeIndex == -1)
2958 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2959 Q_ASSERT(valueTypeIndex <= 0xFF);
2961 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
2962 propIdx |= (valueTypeIndex << 16);
2965 if (aliasProperty.isEnumType())
2966 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
2968 typeName = aliasProperty.typeName();
2970 Q_ASSERT(idObject->type != -1); // How else did it get an id?
2972 const QDeclarativeCompiledData::TypeReference &ref = output->types.at(idObject->type);
2974 typeName = ref.type->typeName();
2976 typeName = ref.component->root->className();
2981 if (typeName.endsWith('*'))
2982 flags |= QML_ALIAS_FLAG_PTR;
2984 QDeclarativeVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags };
2986 typedef QDeclarativeVMEMetaData VMD;
2987 VMD *vmd = (QDeclarativeVMEMetaData *)data.data();
2988 *(vmd->aliasData() + aliasIndex) = aliasData;
2990 prop.nameRef = builder.newString(prop.name.length());
2991 prop.resolvedCustomTypeName = typeName;
2992 prop.typeRef = builder.newString(typeName.length());
2994 builder.setProperty(propIndex, prop.nameRef, prop.typeRef, (QMetaType::Type)type,
2995 (QFastMetaBuilder::PropertyFlag)(writable?int(QFastMetaBuilder::Writable):0),
3001 bool QDeclarativeCompiler::buildBinding(QDeclarativeParser::Value *value,
3002 QDeclarativeParser::Property *prop,
3003 const BindingContext &ctxt)
3005 Q_ASSERT(prop->index != -1);
3006 Q_ASSERT(prop->parent);
3007 Q_ASSERT(prop->parent->metaObject());
3009 QMetaProperty mp = prop->parent->metaObject()->property(prop->index);
3010 if (!mp.isWritable() && !QDeclarativeMetaType::isList(prop->type))
3011 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3013 BindingReference *reference = pool->New<BindingReference>();
3014 reference->expression = value->value;
3015 reference->property = prop;
3016 reference->value = value;
3017 reference->bindingContext = ctxt;
3018 addBindingReference(reference);
3023 void QDeclarativeCompiler::genBindingAssignment(QDeclarativeParser::Value *binding,
3024 QDeclarativeParser::Property *prop,
3025 QDeclarativeParser::Object *obj,
3026 QDeclarativeParser::Property *valueTypeProperty)
3029 Q_ASSERT(binding->bindingReference);
3031 const BindingReference &ref = *binding->bindingReference;
3032 if (ref.dataType == BindingReference::V4) {
3033 QDeclarativeInstruction store;
3034 store.setType(QDeclarativeInstruction::StoreV4Binding);
3035 store.assignBinding.value = ref.compiledIndex;
3036 store.assignBinding.context = ref.bindingContext.stack;
3037 store.assignBinding.owner = ref.bindingContext.owner;
3038 if (valueTypeProperty)
3039 store.assignBinding.property = (valueTypeProperty->index & 0xFFFF) |
3040 ((valueTypeProperty->type & 0xFF)) << 16 |
3041 ((prop->index & 0xFF) << 24);
3043 store.assignBinding.property = prop->index;
3044 store.assignBinding.line = binding->location.start.line;
3045 output->addInstruction(store);
3046 } else if (ref.dataType == BindingReference::V8) {
3047 QDeclarativeInstruction store;
3048 store.setType(QDeclarativeInstruction::StoreV8Binding);
3049 store.assignBinding.value = ref.compiledIndex;
3050 store.assignBinding.context = ref.bindingContext.stack;
3051 store.assignBinding.owner = ref.bindingContext.owner;
3052 store.assignBinding.line = binding->location.start.line;
3054 Q_ASSERT(ref.bindingContext.owner == 0 ||
3055 (ref.bindingContext.owner != 0 && valueTypeProperty));
3056 if (ref.bindingContext.owner) {
3057 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
3059 store.assignBinding.property = genPropertyData(prop);
3062 output->addInstruction(store);
3064 QDeclarativeInstruction store;
3066 store.setType(QDeclarativeInstruction::StoreBinding);
3068 store.setType(QDeclarativeInstruction::StoreBindingOnAlias);
3069 store.assignBinding.value = output->indexForString(ref.rewrittenExpression);
3070 store.assignBinding.context = ref.bindingContext.stack;
3071 store.assignBinding.owner = ref.bindingContext.owner;
3072 store.assignBinding.line = binding->location.start.line;
3074 Q_ASSERT(ref.bindingContext.owner == 0 ||
3075 (ref.bindingContext.owner != 0 && valueTypeProperty));
3076 if (ref.bindingContext.owner) {
3077 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
3079 store.assignBinding.property = genPropertyData(prop);
3081 output->addInstruction(store);
3085 int QDeclarativeCompiler::genContextCache()
3087 if (compileState->ids.count() == 0)
3090 QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache();
3091 cache->reserve(compileState->ids.count());
3092 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
3093 cache->add(o->id, o->idIndex);
3095 output->contextCaches.append(cache);
3096 return output->contextCaches.count() - 1;
3099 int QDeclarativeCompiler::genValueTypeData(QDeclarativeParser::Property *valueTypeProp,
3100 QDeclarativeParser::Property *prop)
3102 typedef QDeclarativePropertyPrivate QDPP;
3103 QByteArray data = QDPP::saveValueType(prop->parent->metaObject(), prop->index,
3104 enginePrivate->valueTypes[prop->type]->metaObject(),
3105 valueTypeProp->index, engine);
3107 return output->indexForByteArray(data);
3110 int QDeclarativeCompiler::genPropertyData(QDeclarativeParser::Property *prop)
3112 typedef QDeclarativePropertyPrivate QDPP;
3113 QByteArray data = QDPP::saveProperty(prop->parent->metaObject(), prop->index, engine);
3115 return output->indexForByteArray(data);
3118 bool QDeclarativeCompiler::completeComponentBuild()
3121 componentStats->componentStat.ids = compileState->ids.count();
3123 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
3124 aliasObject = compileState->aliasingObjects.next(aliasObject))
3125 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
3127 QDeclarativeV4Compiler::Expression expr(unit->imports());
3128 expr.component = compileState->root;
3129 expr.ids = &compileState->ids;
3130 expr.importCache = output->importCache;
3132 QDeclarativeV4Compiler bindingCompiler;
3134 QList<BindingReference*> sharedBindings;
3136 for (BindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3138 BindingReference &binding = *b;
3140 // ### We don't currently optimize for bindings on alias's - because
3141 // of the solution to QTBUG-13719
3142 if (!binding.property->isAlias) {
3143 expr.context = binding.bindingContext.object;
3144 expr.property = binding.property;
3145 expr.expression = binding.expression;
3147 int index = bindingCompiler.compile(expr, enginePrivate);
3149 binding.dataType = BindingReference::V4;
3150 binding.compiledIndex = index;
3152 componentStats->componentStat.optimizedBindings.append(b->value->location);
3157 // Pre-rewrite the expression
3158 QString expression = binding.expression.asScript();
3160 QDeclarativeRewrite::RewriteBinding rewriteBinding;
3161 rewriteBinding.setName(QLatin1Char('$')+binding.property->name());
3162 bool isSharable = false;
3163 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3165 if (isSharable && !binding.property->isAlias /* See above re alias */ &&
3166 binding.property->type != qMetaTypeId<QDeclarativeBinding*>()) {
3167 binding.dataType = BindingReference::V8;
3168 sharedBindings.append(b);
3170 binding.dataType = BindingReference::QtScript;
3174 componentStats->componentStat.scriptBindings.append(b->value->location);
3177 if (!sharedBindings.isEmpty()) {
3179 static bool lt(const BindingReference *lhs, const BindingReference *rhs)
3181 return lhs->value->location.start.line < rhs->value->location.start.line;
3185 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3187 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3188 int lineNumber = startLineNumber;
3190 QString functionArray(QLatin1String("["));
3191 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3192 BindingReference *reference = sharedBindings.at(ii);
3193 QDeclarativeParser::Value *value = reference->value;
3194 const QString &expression = reference->rewrittenExpression;
3196 if (ii != 0) functionArray += QLatin1String(",");
3198 while (lineNumber < value->location.start.line) {
3200 functionArray += QLatin1String("\n");
3203 functionArray += expression;
3204 reference->compiledIndex = ii;
3206 functionArray += QLatin1String("]");
3208 compileState->v8BindingProgram = functionArray;
3209 compileState->v8BindingProgramLine = startLineNumber;
3210 compileState->v8BindingProgramIndex = output->v8bindings.count();
3211 output->v8bindings.append(v8::Persistent<v8::Array>());
3214 if (bindingCompiler.isValid())
3215 compileState->compiledBindingData = bindingCompiler.program();
3217 saveComponentState();
3222 void QDeclarativeCompiler::dumpStats()
3224 Q_ASSERT(componentStats);
3225 qWarning().nospace() << "QML Document: " << output->url.toString();
3226 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3227 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3228 qWarning().nospace() << " Component Line " << stat.lineNumber;
3229 qWarning().nospace() << " Total Objects: " << stat.objects;
3230 qWarning().nospace() << " IDs Used: " << stat.ids;
3231 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3235 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3236 if (0 == (ii % 10)) {
3237 if (ii) output.append("\n");
3242 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3244 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3245 output.append(") ");
3247 if (!output.isEmpty())
3248 qWarning().nospace() << output.constData();
3251 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3254 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3255 if (0 == (ii % 10)) {
3256 if (ii) output.append("\n");
3261 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3263 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3264 output.append(") ");
3266 if (!output.isEmpty())
3267 qWarning().nospace() << output.constData();
3273 Returns true if from can be assigned to a (QObject) property of type
3276 bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeParser::Object *from)
3278 const QMetaObject *toMo =
3279 enginePrivate->rawMetaObjectForType(to);
3280 const QMetaObject *fromMo = from->metaObject();
3283 if (QDeclarativePropertyPrivate::equal(fromMo, toMo))
3285 fromMo = fromMo->superClass();
3291 Returns the element name, as written in the QML file, for o.
3293 QString QDeclarativeCompiler::elementName(QDeclarativeParser::Object *o)
3296 if (o->type != -1) {
3297 return output->types.at(o->type).className;
3303 QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeParser::Object *from)
3306 const QMetaObject *mo = from->metatype;
3307 QDeclarativeType *type = 0;
3308 while (!type && mo) {
3309 type = QDeclarativeMetaType::qmlType(mo);
3310 mo = mo->superClass();
3315 QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeParser::Object *obj)
3317 const QMetaObject *mo = obj->metatype;
3319 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3321 return QStringList();
3323 QMetaClassInfo classInfo = mo->classInfo(idx);
3324 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3328 QDeclarativePropertyCache::Data *
3329 QDeclarativeCompiler::property(QDeclarativeParser::Object *object, int index)
3331 QDeclarativePropertyCache *cache = 0;
3333 if (object->synthCache)
3334 cache = object->synthCache;
3335 else if (object->type != -1)
3336 cache = output->types[object->type].createPropertyCache(engine);
3338 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3340 return cache->property(index);
3343 QDeclarativePropertyCache::Data *
3344 QDeclarativeCompiler::property(QDeclarativeParser::Object *object, const QStringRef &name, bool *notInRevision)
3346 if (notInRevision) *notInRevision = false;
3348 QDeclarativePropertyCache *cache = 0;
3350 if (object->synthCache)
3351 cache = object->synthCache;
3352 else if (object->type != -1)
3353 cache = output->types[object->type].createPropertyCache(engine);
3355 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3357 QDeclarativePropertyCache::Data *d = cache->property(QHashedStringRef(name.constData(), name.length()));
3359 // Find the first property
3360 while (d && d->isFunction())
3361 d = cache->overrideData(d);
3363 if (d && !cache->isAllowedInRevision(d)) {
3364 if (notInRevision) *notInRevision = true;
3371 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3372 QDeclarativePropertyCache::Data *
3373 QDeclarativeCompiler::signal(QDeclarativeParser::Object *object, const QStringRef &name, bool *notInRevision)
3375 if (notInRevision) *notInRevision = false;
3377 QDeclarativePropertyCache *cache = 0;
3379 if (object->synthCache)
3380 cache = object->synthCache;
3381 else if (object->type != -1)
3382 cache = output->types[object->type].createPropertyCache(engine);
3384 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3387 QDeclarativePropertyCache::Data *d = cache->property(QHashedStringRef(name.constData(), name.length()));
3388 if (notInRevision) *notInRevision = false;
3390 while (d && !(d->isFunction()))
3391 d = cache->overrideData(d);
3393 if (d && !cache->isAllowedInRevision(d)) {
3394 if (notInRevision) *notInRevision = true;
3400 if (name.endsWith(Changed_string)) {
3401 QStringRef propName(name.string(), name.position(), name.length() - Changed_string.length());
3403 d = property(object, propName, notInRevision);
3405 return cache->method(d->notifyIndex);
3411 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3412 int QDeclarativeCompiler::indexOfSignal(QDeclarativeParser::Object *object, const QString &name,
3413 bool *notInRevision)
3415 QDeclarativePropertyCache::Data *d = signal(object, QStringRef(&name), notInRevision);
3416 return d?d->coreIndex:-1;
3419 int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QString &name,
3420 bool *notInRevision)
3422 return indexOfProperty(object, QStringRef(&name), notInRevision);
3425 int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QStringRef &name,
3426 bool *notInRevision)
3428 QDeclarativePropertyCache::Data *d = property(object, name, notInRevision);
3429 return d?d->coreIndex:-1;