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(QHashedStringRef(&name));
131 bool QDeclarativeCompiler::isAttachedPropertyName(const QHashedStringRef &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 QHashedStringRef &name)
154 if (name.length() < 3) return false;
155 if (!name.startsWith(on_string)) return false;
156 int ns = name.length();
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 QHashedStringRef &string)
782 for (int ii = 0; ii < list.count(); ++ii)
783 if (string == list.at(ii))
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 Property *explicitProperty = 0;
851 const QMetaObject *mo = obj->metatype;
852 int idx = mo->indexOfClassInfo("DefaultProperty");
854 QMetaClassInfo info = mo->classInfo(idx);
855 const char *p = info.value();
859 while (char c = p[plen++]) { ord |= c; };
863 // Utf8 - unoptimal, but seldom hit
864 QString *s = pool->NewString(QString::fromUtf8(p, plen));
865 QHashedStringRef r(*s);
867 if (obj->propertiesHashField.test(r.hash())) {
868 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
869 if (ep->name() == r) {
870 explicitProperty = ep;
876 if (!explicitProperty)
877 defaultProperty->setName(r);
880 QHashedCStringRef r(p, plen);
882 if (obj->propertiesHashField.test(r.hash())) {
883 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
884 if (ep->name() == r) {
885 explicitProperty = ep;
891 if (!explicitProperty) {
892 // Set the default property name
893 QChar *buffer = pool->NewRawArray<QChar>(r.length());
894 r.writeUtf16(buffer);
895 defaultProperty->setName(QHashedStringRef(buffer, r.length(), r.hash()));
901 if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) {
903 skipProperty = explicitProperty; // We merge the values into defaultProperty
905 // Find the correct insertion point
906 Value *insertPos = 0;
908 for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) {
909 if (!(v->location.start < explicitProperty->values.first()->location.start))
914 defaultProperty->values.insertAfter(insertPos, explicitProperty->values);
918 QDeclarativeCustomParser *cp = 0;
920 cp = output->types.at(obj->type).type->customParser();
922 // Build all explicit properties specified
923 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
925 if (prop == skipProperty)
927 if (prop->name() == id_string)
930 bool canDefer = false;
931 if (isCustomParser) {
932 if (doesPropertyExist(prop, obj) &&
933 (!(cp->flags() & QDeclarativeCustomParser::AcceptsAttachedProperties) ||
934 !isAttachedPropertyName(prop->name()))) {
935 int ids = compileState->ids.count();
936 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
937 canDefer = ids == compileState->ids.count();
938 } else if (isSignalPropertyName(prop->name()) &&
939 (cp->flags() & QDeclarativeCustomParser::AcceptsSignalHandlers)) {
940 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
942 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
945 if (isSignalPropertyName(prop->name())) {
946 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
948 int ids = compileState->ids.count();
949 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
950 canDefer = ids == compileState->ids.count();
954 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
955 prop->isDeferred = true;
959 // Build the default property
960 if (defaultProperty) {
961 Property *prop = defaultProperty;
963 bool canDefer = false;
964 if (isCustomParser) {
965 if (doesPropertyExist(prop, obj)) {
966 int ids = compileState->ids.count();
967 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
968 canDefer = ids == compileState->ids.count();
970 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
973 int ids = compileState->ids.count();
974 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
975 canDefer = ids == compileState->ids.count();
978 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
979 prop->isDeferred = true;
982 // Compile custom parser parts
983 if (isCustomParser && !customProps.isEmpty()) {
987 obj->custom = cp->compile(customProps);
990 foreach (QDeclarativeError err, cp->errors()) {
991 err.setUrl(output->url);
999 void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj)
1001 QDeclarativeCompiledData::TypeReference &tr = output->types[obj->type];
1002 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
1007 // Create the object
1008 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
1009 !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) {
1011 QDeclarativeInstruction create;
1012 create.setType(QDeclarativeInstruction::CreateSimpleObject);
1013 create.createSimple.create = output->types.at(obj->type).type->createFunction();
1014 create.createSimple.typeSize = output->types.at(obj->type).type->createSize();
1015 create.createSimple.type = obj->type;
1016 create.createSimple.line = obj->location.start.line;
1017 create.createSimple.column = obj->location.start.column;
1018 output->addInstruction(create);
1022 QDeclarativeInstruction create;
1023 create.setType(QDeclarativeInstruction::CreateObject);
1024 create.create.line = obj->location.start.line;
1025 create.create.column = obj->location.start.column;
1026 create.create.data = -1;
1027 if (!obj->custom.isEmpty())
1028 create.create.data = output->indexForByteArray(obj->custom);
1029 create.create.type = obj->type;
1030 if (!output->types.at(create.create.type).type &&
1031 !obj->bindingBitmask.isEmpty()) {
1032 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
1033 create.create.bindingBits =
1034 output->indexForByteArray(obj->bindingBitmask);
1036 create.create.bindingBits = -1;
1038 output->addInstruction(create);
1042 // Setup the synthesized meta object if necessary
1043 if (!obj->metadata.isEmpty()) {
1044 QDeclarativeInstruction meta;
1045 meta.setType(QDeclarativeInstruction::StoreMetaObject);
1046 meta.storeMeta.data = output->indexForByteArray(obj->metadata);
1047 meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata);
1048 meta.storeMeta.propertyCache = output->propertyCaches.count();
1050 QDeclarativePropertyCache *propertyCache = obj->synthCache;
1051 Q_ASSERT(propertyCache);
1052 propertyCache->addref();
1054 // Add flag for alias properties
1055 if (!obj->synthdata.isEmpty()) {
1056 const QDeclarativeVMEMetaData *vmeMetaData =
1057 reinterpret_cast<const QDeclarativeVMEMetaData *>(obj->synthdata.constData());
1058 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
1059 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
1060 QDeclarativePropertyCache::Data *data = propertyCache->property(index);
1061 data->setFlags(data->getFlags() | QDeclarativePropertyCache::Data::IsAlias);
1065 if (obj == unitRoot) {
1066 propertyCache->addref();
1067 output->rootPropertyCache = propertyCache;
1070 output->propertyCaches << propertyCache;
1071 output->addInstruction(meta);
1072 } else if (obj == unitRoot) {
1073 output->rootPropertyCache = tr.createPropertyCache(engine);
1074 output->rootPropertyCache->addref();
1077 // Set the object id
1078 if (!obj->id.isEmpty()) {
1079 QDeclarativeInstruction id;
1080 id.setType(QDeclarativeInstruction::SetId);
1081 id.setId.value = output->indexForString(obj->id);
1082 id.setId.index = obj->idIndex;
1083 output->addInstruction(id);
1087 if (tr.type && obj->parserStatusCast != -1) {
1088 QDeclarativeInstruction begin;
1089 begin.setType(QDeclarativeInstruction::BeginObject);
1090 begin.begin.castValue = obj->parserStatusCast;
1091 output->addInstruction(begin);
1097 void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj)
1099 for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1100 Q_ASSERT(prop->scriptStringScope != -1);
1101 const QString &script = prop->values.first()->value.asScript();
1102 QDeclarativeInstruction ss;
1103 ss.setType(QDeclarativeInstruction::StoreScriptString);
1104 ss.storeScriptString.propertyIndex = prop->index;
1105 ss.storeScriptString.value = output->indexForString(script);
1106 ss.storeScriptString.scope = prop->scriptStringScope;
1107 // ss.storeScriptString.bindingId = rewriteBinding(script, prop->name());
1108 ss.storeScriptString.bindingId = rewriteBinding(script, QString()); // XXX
1109 ss.storeScriptString.line = prop->location.start.line;
1110 output->addInstruction(ss);
1113 bool seenDefer = false;
1114 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1115 if (prop->isDeferred) {
1120 genValueProperty(prop, obj);
1123 QDeclarativeInstruction defer;
1124 defer.setType(QDeclarativeInstruction::Defer);
1125 defer.defer.deferCount = 0;
1126 int deferIdx = output->addInstruction(defer);
1127 int nextInstructionIndex = output->nextInstructionIndex();
1129 QDeclarativeInstruction init;
1130 init.setType(QDeclarativeInstruction::Init);
1131 init.init.bindingsSize = compileState->bindings.count(); // XXX - bigger than necessary
1132 init.init.parserStatusSize = compileState->parserStatusCount; // XXX - bigger than necessary
1133 init.init.contextCache = -1;
1134 init.init.compiledBinding = -1;
1135 output->addInstruction(init);
1137 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1138 if (!prop->isDeferred)
1140 genValueProperty(prop, obj);
1143 QDeclarativeInstruction done;
1144 done.setType(QDeclarativeInstruction::Done);
1145 output->addInstruction(done);
1147 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1150 for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1152 QDeclarativeParser::Value *v = prop->values.first();
1154 if (v->type == Value::SignalObject) {
1156 genObject(v->object);
1158 QDeclarativeInstruction assign;
1159 assign.setType(QDeclarativeInstruction::AssignSignalObject);
1160 assign.assignSignalObject.line = v->location.start.line;
1161 assign.assignSignalObject.signal = output->indexForString(prop->name().toString());
1162 output->addInstruction(assign);
1164 } else if (v->type == Value::SignalExpression) {
1166 QDeclarativeInstruction store;
1167 store.setType(QDeclarativeInstruction::StoreSignal);
1168 store.storeSignal.signalIndex = prop->index;
1169 store.storeSignal.value =
1170 output->indexForString(v->value.asScript().trimmed());
1171 store.storeSignal.context = v->signalExpressionContextStack;
1172 store.storeSignal.name = output->indexForByteArray(prop->name().toUtf8());
1173 store.storeSignal.line = v->location.start.line;
1174 output->addInstruction(store);
1180 for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1181 QDeclarativeInstruction fetch;
1182 fetch.setType(QDeclarativeInstruction::FetchAttached);
1183 fetch.fetchAttached.id = prop->index;
1184 fetch.fetchAttached.line = prop->location.start.line;
1185 output->addInstruction(fetch);
1187 genObjectBody(prop->value);
1189 QDeclarativeInstruction pop;
1190 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1191 output->addInstruction(pop);
1194 for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1195 QDeclarativeInstruction fetch;
1196 fetch.setType(QDeclarativeInstruction::FetchObject);
1197 fetch.fetch.property = prop->index;
1198 fetch.fetch.line = prop->location.start.line;
1199 output->addInstruction(fetch);
1201 if (!prop->value->metadata.isEmpty()) {
1202 QDeclarativeInstruction meta;
1203 meta.setType(QDeclarativeInstruction::StoreMetaObject);
1204 meta.storeMeta.data = output->indexForByteArray(prop->value->metadata);
1205 meta.storeMeta.aliasData = output->indexForByteArray(prop->value->synthdata);
1206 meta.storeMeta.propertyCache = -1;
1207 output->addInstruction(meta);
1210 genObjectBody(prop->value);
1212 QDeclarativeInstruction pop;
1213 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1214 output->addInstruction(pop);
1217 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1219 genValueTypeProperty(obj, prop);
1222 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1223 if (prop->isDeferred)
1226 genValueProperty(prop, obj);
1229 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1231 genValueTypeProperty(obj, prop);
1235 void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeParser::Object *obj,QDeclarativeParser::Property *prop)
1237 QDeclarativeInstruction fetch;
1238 fetch.setType(QDeclarativeInstruction::FetchValueType);
1239 fetch.fetchValue.property = prop->index;
1240 fetch.fetchValue.type = prop->type;
1241 fetch.fetchValue.bindingSkipList = 0;
1243 if (obj->type == -1 || output->types.at(obj->type).component) {
1244 // We only have to do this if this is a composite type. If it is a builtin
1245 // type it can't possibly already have bindings that need to be cleared.
1246 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1247 if (!vprop->values.isEmpty()) {
1248 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1249 fetch.fetchValue.bindingSkipList |= (1 << vprop->index);
1254 output->addInstruction(fetch);
1256 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1257 genPropertyAssignment(vprop, prop->value, prop);
1260 QDeclarativeInstruction pop;
1261 pop.setType(QDeclarativeInstruction::PopValueType);
1262 pop.fetchValue.property = prop->index;
1263 pop.fetchValue.type = prop->type;
1264 pop.fetchValue.bindingSkipList = 0;
1265 output->addInstruction(pop);
1268 void QDeclarativeCompiler::genComponent(QDeclarativeParser::Object *obj)
1270 QDeclarativeParser::Object *root = obj->defaultProperty->values.first()->object;
1273 QDeclarativeInstruction create;
1274 create.setType(QDeclarativeInstruction::CreateComponent);
1275 create.createComponent.line = root->location.start.line;
1276 create.createComponent.column = root->location.start.column;
1277 create.createComponent.endLine = root->location.end.line;
1278 int createInstruction = output->addInstruction(create);
1279 int nextInstructionIndex = output->nextInstructionIndex();
1281 ComponentCompileState *oldCompileState = compileState;
1282 compileState = componentState(root);
1284 QDeclarativeInstruction init;
1285 init.setType(QDeclarativeInstruction::Init);
1286 init.init.bindingsSize = compileState->bindings.count();
1287 init.init.parserStatusSize = compileState->parserStatusCount;
1288 init.init.contextCache = genContextCache();
1289 if (compileState->compiledBindingData.isEmpty())
1290 init.init.compiledBinding = -1;
1292 init.init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
1293 output->addInstruction(init);
1295 if (!compileState->v8BindingProgram.isEmpty()) {
1296 QDeclarativeInstruction bindings;
1297 bindings.setType(QDeclarativeInstruction::InitV8Bindings);
1298 bindings.initV8Bindings.program = output->indexForString(compileState->v8BindingProgram);
1299 bindings.initV8Bindings.programIndex = compileState->v8BindingProgramIndex;
1300 bindings.initV8Bindings.line = compileState->v8BindingProgramLine;
1301 output->addInstruction(bindings);
1306 QDeclarativeInstruction def;
1307 def.setType(QDeclarativeInstruction::SetDefault);
1308 output->addInstruction(def);
1310 QDeclarativeInstruction done;
1311 done.setType(QDeclarativeInstruction::Done);
1312 output->addInstruction(done);
1314 output->instruction(createInstruction)->createComponent.count =
1315 output->nextInstructionIndex() - nextInstructionIndex;
1317 compileState = oldCompileState;
1319 if (!obj->id.isEmpty()) {
1320 QDeclarativeInstruction id;
1321 id.setType(QDeclarativeInstruction::SetId);
1322 id.setId.value = output->indexForString(obj->id);
1323 id.setId.index = obj->idIndex;
1324 output->addInstruction(id);
1327 if (obj == unitRoot) {
1328 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1329 output->rootPropertyCache->addref();
1333 bool QDeclarativeCompiler::buildComponent(QDeclarativeParser::Object *obj,
1334 const BindingContext &ctxt)
1336 // The special "Component" element can only have the id property and a
1337 // default property, that actually defines the component's tree
1339 // Find, check and set the "id" property (if any)
1340 Property *idProp = 0;
1341 if (obj->properties.isMany() ||
1342 (obj->properties.isOne() && obj->properties.first()->name() != id_string))
1343 COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
1345 if (!obj->properties.isEmpty())
1346 idProp = obj->properties.first();
1349 if (idProp->value || idProp->values.isMany() || idProp->values.first()->object)
1350 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1351 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1353 QString idVal = idProp->values.first()->primitive();
1355 if (compileState->ids.value(idVal))
1356 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1362 // Check the Component tree is well formed
1363 if (obj->defaultProperty &&
1364 (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
1365 (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
1366 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1368 if (!obj->dynamicProperties.isEmpty())
1369 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1370 if (!obj->dynamicSignals.isEmpty())
1371 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1372 if (!obj->dynamicSlots.isEmpty())
1373 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1375 QDeclarativeParser::Object *root = 0;
1376 if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
1377 root = obj->defaultProperty->values.first()->object;
1380 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1382 // Build the component tree
1383 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1388 bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeParser::Object *obj,
1389 const BindingContext &ctxt)
1391 ComponentCompileState *oldComponentCompileState = compileState;
1392 compileState = pool->New<ComponentCompileState>();
1393 compileState->root = obj;
1394 compileState->nested = true;
1396 if (componentStats) {
1397 ComponentStat oldComponentStat = componentStats->componentStat;
1399 componentStats->componentStat = ComponentStat();
1400 componentStats->componentStat.lineNumber = obj->location.start.line;
1403 COMPILE_CHECK(buildObject(obj, ctxt));
1405 COMPILE_CHECK(completeComponentBuild());
1407 componentStats->componentStat = oldComponentStat;
1410 COMPILE_CHECK(buildObject(obj, ctxt));
1412 COMPILE_CHECK(completeComponentBuild());
1415 compileState = oldComponentCompileState;
1421 // Build a sub-object. A sub-object is one that was not created directly by
1422 // QML - such as a grouped property object, or an attached object. Sub-object's
1423 // can't have an id, involve a custom parser, have attached properties etc.
1424 bool QDeclarativeCompiler::buildSubObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
1426 Q_ASSERT(obj->metatype);
1427 Q_ASSERT(!obj->defaultProperty);
1428 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1431 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1432 if (isSignalPropertyName(prop->name())) {
1433 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1435 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1442 int QDeclarativeCompiler::componentTypeRef()
1444 QDeclarativeType *t = QDeclarativeMetaType::qmlType(QLatin1String("QtQuick/Component"),2,0);
1445 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1446 if (output->types.at(ii).type == t)
1449 QDeclarativeCompiledData::TypeReference ref;
1450 ref.className = Component_string;
1452 output->types << ref;
1453 return output->types.count() - 1;
1456 bool QDeclarativeCompiler::buildSignal(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj,
1457 const BindingContext &ctxt)
1459 Q_ASSERT(obj->metaObject());
1461 const QHashedStringRef &propName = prop->name();
1463 Q_ASSERT(propName.startsWith(on_string));
1464 QString name = propName.mid(2, -1).toString();
1466 // Note that the property name could start with any alpha or '_' or '$' character,
1467 // so we need to do the lower-casing of the first alpha character.
1468 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1469 if (QDeclarativeUtils::isUpper(name.at(firstAlphaIndex))) {
1470 name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1475 bool notInRevision = false;
1477 QDeclarativePropertyCache::Data *sig = signal(obj, QStringRef(&name), ¬InRevision);
1481 if (notInRevision && 0 == property(obj, propName, 0)) {
1482 Q_ASSERT(obj->type != -1);
1483 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1484 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1486 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(elementName(obj)).arg(prop->name().toString()).arg(type.type->module()).arg(type.majorVersion).arg(type.minorVersion));
1488 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1492 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1494 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1498 if (prop->value || !prop->values.isOne())
1499 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1501 prop->index = sig->coreIndex;
1504 obj->addSignalProperty(prop);
1506 if (prop->values.first()->object) {
1507 COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1508 prop->values.first()->type = Value::SignalObject;
1510 prop->values.first()->type = Value::SignalExpression;
1512 if (!prop->values.first()->value.isScript())
1513 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1515 QString script = prop->values.first()->value.asScript().trimmed();
1516 if (script.isEmpty())
1517 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1519 prop->values.first()->signalExpressionContextStack = ctxt.stack;
1528 Returns true if (value) property \a prop exists on obj, false otherwise.
1530 bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeParser::Property *prop,
1531 QDeclarativeParser::Object *obj)
1533 if (prop->name().isEmpty())
1535 if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1538 return property(obj, prop->name()) != 0;
1541 bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop,
1542 QDeclarativeParser::Object *obj,
1543 const BindingContext &ctxt)
1545 if (prop->isEmpty())
1546 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1548 const QMetaObject *metaObject = obj->metaObject();
1549 Q_ASSERT(metaObject);
1551 if (isAttachedPropertyName(prop->name())) {
1552 // Setup attached property data
1554 if (ctxt.isSubContext()) {
1555 // Attached properties cannot be used on sub-objects. Sub-objects
1556 // always exist in a binding sub-context, which is what we test
1558 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1561 QDeclarativeType *type = 0;
1562 QDeclarativeImportedNamespace *typeNamespace = 0;
1563 unit->imports().resolveType(prop->name().toString(), &type, 0, 0, 0, &typeNamespace);
1565 if (typeNamespace) {
1566 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1569 } else if (!type || !type->attachedPropertiesType()) {
1570 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1574 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1576 Q_ASSERT(type->attachedPropertiesFunction());
1577 prop->index = type->attachedPropertiesId();
1578 prop->value->metatype = type->attachedPropertiesType();
1580 // Setup regular property data
1581 if (prop->isDefault) {
1582 QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
1585 prop->setName(p.name());
1588 bool notInRevision = false;
1589 QDeclarativePropertyCache::Data *d =
1590 prop->name().isEmpty()?0:property(obj, prop->name(), ¬InRevision);
1592 if (d == 0 && notInRevision) {
1593 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1594 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1596 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(elementName(obj)).arg(prop->name().toString()).arg(type.type->module()).arg(type.majorVersion).arg(type.minorVersion));
1598 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1601 prop->index = d->coreIndex;
1605 // We can't error here as the "id" property does not require a
1606 // successful index resolution
1607 if (prop->index != -1)
1608 prop->type = prop->core.propType;
1610 // Check if this is an alias
1611 if (prop->index != -1 &&
1613 prop->parent->type != -1 &&
1614 output->types.at(prop->parent->type).component) {
1616 QDeclarativePropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1617 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1618 prop->isAlias = true;
1621 if (prop->index != -1 && !prop->values.isEmpty())
1622 prop->parent->setBindingBit(prop->index);
1625 if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1627 // The magic "id" behavior doesn't apply when "id" is resolved as a
1628 // default property or to sub-objects (which are always in binding
1630 COMPILE_CHECK(buildIdProperty(prop, obj));
1631 if (prop->type == QVariant::String &&
1632 prop->values.first()->value.isString())
1633 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1635 } else if (isAttachedPropertyName(prop->name())) {
1637 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1639 } else if (prop->index == -1) {
1641 if (prop->isDefault) {
1642 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1644 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1647 } else if (prop->value) {
1649 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1651 } else if (prop->core.isQList()) {
1653 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1655 } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) {
1657 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1661 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1668 bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
1669 QDeclarativeParser::Property *nsProp,
1670 QDeclarativeParser::Object *obj,
1671 const BindingContext &ctxt)
1674 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1676 for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1678 if (!isAttachedPropertyName(prop->name()))
1679 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1681 // Setup attached property data
1683 QDeclarativeType *type = 0;
1684 unit->imports().resolveType(ns, prop->name().toString(), &type, 0, 0, 0);
1686 if (!type || !type->attachedPropertiesType())
1687 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1690 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1692 Q_ASSERT(type->attachedPropertiesFunction());
1693 prop->index = type->index();
1694 prop->value->metatype = type->attachedPropertiesType();
1696 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1702 void QDeclarativeCompiler::genValueProperty(QDeclarativeParser::Property *prop,
1703 QDeclarativeParser::Object *obj)
1705 if (prop->core.isQList()) {
1706 genListProperty(prop, obj);
1708 genPropertyAssignment(prop, obj);
1712 void QDeclarativeCompiler::genListProperty(QDeclarativeParser::Property *prop,
1713 QDeclarativeParser::Object *obj)
1715 int listType = enginePrivate->listType(prop->type);
1717 QDeclarativeInstruction fetch;
1718 fetch.setType(QDeclarativeInstruction::FetchQList);
1719 fetch.fetchQmlList.property = prop->index;
1720 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1721 fetch.fetchQmlList.type = listType;
1722 output->addInstruction(fetch);
1724 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1726 if (v->type == Value::CreatedObject) {
1728 genObject(v->object);
1729 if (listTypeIsInterface) {
1730 QDeclarativeInstruction assign;
1731 assign.setType(QDeclarativeInstruction::AssignObjectList);
1732 assign.assignObjectList.line = prop->location.start.line;
1733 output->addInstruction(assign);
1735 QDeclarativeInstruction store;
1736 store.setType(QDeclarativeInstruction::StoreObjectQList);
1737 output->addInstruction(store);
1740 } else if (v->type == Value::PropertyBinding) {
1742 genBindingAssignment(v, prop, obj);
1748 QDeclarativeInstruction pop;
1749 pop.setType(QDeclarativeInstruction::PopQList);
1750 output->addInstruction(pop);
1753 void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *prop,
1754 QDeclarativeParser::Object *obj,
1755 QDeclarativeParser::Property *valueTypeProperty)
1757 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1759 Q_ASSERT(v->type == Value::CreatedObject ||
1760 v->type == Value::PropertyBinding ||
1761 v->type == Value::Literal);
1763 if (v->type == Value::CreatedObject) {
1765 genObject(v->object);
1767 if (QDeclarativeMetaType::isInterface(prop->type)) {
1769 QDeclarativeInstruction store;
1770 store.setType(QDeclarativeInstruction::StoreInterface);
1771 store.storeObject.line = v->object->location.start.line;
1772 store.storeObject.propertyIndex = prop->index;
1773 output->addInstruction(store);
1775 } else if (prop->type == QMetaType::QVariant) {
1777 QDeclarativeInstruction store;
1778 store.setType(QDeclarativeInstruction::StoreVariantObject);
1779 store.storeObject.line = v->object->location.start.line;
1780 store.storeObject.propertyIndex = prop->index;
1781 output->addInstruction(store);
1785 QDeclarativeInstruction store;
1786 store.setType(QDeclarativeInstruction::StoreObject);
1787 store.storeObject.line = v->object->location.start.line;
1788 store.storeObject.propertyIndex = prop->index;
1789 output->addInstruction(store);
1792 } else if (v->type == Value::PropertyBinding) {
1794 genBindingAssignment(v, prop, obj, valueTypeProperty);
1796 } else if (v->type == Value::Literal) {
1798 genLiteralAssignment(prop, v);
1804 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
1806 Q_ASSERT(v->type == Value::ValueSource ||
1807 v->type == Value::ValueInterceptor);
1809 if (v->type == Value::ValueSource) {
1810 genObject(v->object);
1812 QDeclarativeInstruction store;
1813 store.setType(QDeclarativeInstruction::StoreValueSource);
1814 if (valueTypeProperty) {
1815 store.assignValueSource.property = genValueTypeData(prop, valueTypeProperty);
1816 store.assignValueSource.owner = 1;
1818 store.assignValueSource.property = genPropertyData(prop);
1819 store.assignValueSource.owner = 0;
1821 QDeclarativeType *valueType = toQmlType(v->object);
1822 store.assignValueSource.castValue = valueType->propertyValueSourceCast();
1823 output->addInstruction(store);
1825 } else if (v->type == Value::ValueInterceptor) {
1826 genObject(v->object);
1828 QDeclarativeInstruction store;
1829 store.setType(QDeclarativeInstruction::StoreValueInterceptor);
1830 if (valueTypeProperty) {
1831 store.assignValueInterceptor.property = genValueTypeData(prop, valueTypeProperty);
1832 store.assignValueInterceptor.owner = 1;
1834 store.assignValueInterceptor.property = genPropertyData(prop);
1835 store.assignValueInterceptor.owner = 0;
1837 QDeclarativeType *valueType = toQmlType(v->object);
1838 store.assignValueInterceptor.castValue = valueType->propertyValueInterceptorCast();
1839 output->addInstruction(store);
1845 bool QDeclarativeCompiler::buildIdProperty(QDeclarativeParser::Property *prop,
1846 QDeclarativeParser::Object *obj)
1849 prop->values.isMany() ||
1850 prop->values.first()->object)
1851 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
1853 QDeclarativeParser::Value *idValue = prop->values.first();
1854 QString val = idValue->primitive();
1856 COMPILE_CHECK(checkValidId(idValue, val));
1858 if (compileState->ids.value(val))
1859 COMPILE_EXCEPTION(prop, tr("id is not unique"));
1861 prop->values.first()->type = Value::Id;
1869 void QDeclarativeCompiler::addId(const QString &id, QDeclarativeParser::Object *obj)
1871 Q_ASSERT(!compileState->ids.value(id));
1872 Q_ASSERT(obj->id == id);
1873 obj->idIndex = compileState->ids.count();
1874 compileState->ids.append(obj);
1877 void QDeclarativeCompiler::addBindingReference(BindingReference *ref)
1879 Q_ASSERT(ref->value && !ref->value->bindingReference);
1880 ref->value->bindingReference = ref;
1881 compileState->bindings.prepend(ref);
1884 void QDeclarativeCompiler::saveComponentState()
1886 Q_ASSERT(compileState->root);
1887 Q_ASSERT(compileState->root->componentCompileState == 0);
1889 compileState->root->componentCompileState = compileState;
1892 componentStats->savedComponentStats.append(componentStats->componentStat);
1895 QDeclarativeCompilerTypes::ComponentCompileState *
1896 QDeclarativeCompiler::componentState(QDeclarativeParser::Object *obj)
1898 Q_ASSERT(obj->componentCompileState);
1899 return obj->componentCompileState;
1902 // Build attached property object. In this example,
1906 // GridView is an attached property object.
1907 bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeParser::Property *prop,
1908 QDeclarativeParser::Object *obj,
1909 const BindingContext &ctxt)
1911 Q_ASSERT(prop->value);
1912 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
1914 obj->addAttachedProperty(prop);
1916 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1922 // Build "grouped" properties. In this example:
1924 // font.pointSize: 12
1925 // font.family: "Helvetica"
1927 // font is a nested property. pointSize and family are not.
1928 bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeParser::Property *prop,
1929 QDeclarativeParser::Object *obj,
1930 const BindingContext &ctxt)
1932 Q_ASSERT(prop->type != 0);
1933 Q_ASSERT(prop->index != -1);
1935 if (QDeclarativeValueTypeFactory::isValueType(prop->type)) {
1936 if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
1938 if (!prop->values.isEmpty()) {
1939 if (prop->values.first()->location < prop->value->location) {
1940 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
1942 COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
1946 if (!obj->metaObject()->property(prop->index).isWritable()) {
1947 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
1951 if (prop->isAlias) {
1952 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
1953 vtProp->isAlias = true;
1957 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
1958 prop->value, obj, ctxt.incr()));
1959 obj->addValueTypeProperty(prop);
1961 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1965 // Load the nested property's meta type
1966 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
1967 if (!prop->value->metatype)
1968 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1970 if (!prop->values.isEmpty())
1971 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
1973 obj->addGroupedProperty(prop);
1975 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1981 bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
1982 QDeclarativeParser::Object *obj,
1983 QDeclarativeParser::Object *baseObj,
1984 const BindingContext &ctxt)
1986 if (obj->defaultProperty)
1987 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
1988 obj->metatype = type->metaObject();
1990 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1992 QDeclarativePropertyCache::Data *d = property(obj, prop->name());
1994 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1996 prop->index = d->coreIndex;
1997 prop->type = d->propType;
1999 prop->isValueTypeSubProperty = true;
2002 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
2004 if (prop->values.isMany()) {
2005 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
2006 } else if (!prop->values.isEmpty()) {
2007 QDeclarativeParser::Value *value = prop->values.first();
2009 if (value->object) {
2010 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
2011 } else if (value->value.isScript()) {
2012 // ### Check for writability
2014 //optimization for <Type>.<EnumValue> enum assignments
2015 bool isEnumAssignment = false;
2017 if (prop->core.isEnum())
2018 COMPILE_CHECK(testQualifiedEnumAssignment(obj->metatype->property(prop->index), obj,
2019 value, &isEnumAssignment));
2021 if (isEnumAssignment) {
2022 value->type = Value::Literal;
2024 BindingReference *reference = pool->New<BindingReference>();
2025 reference->expression = value->value;
2026 reference->property = prop;
2027 reference->value = value;
2028 reference->bindingContext = ctxt;
2029 reference->bindingContext.owner++;
2030 addBindingReference(reference);
2031 value->type = Value::PropertyBinding;
2034 COMPILE_CHECK(testLiteralAssignment(prop, value));
2035 value->type = Value::Literal;
2039 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2040 Q_ASSERT(v->object);
2042 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
2045 obj->addValueProperty(prop);
2051 // Build assignments to QML lists. QML lists are properties of type
2052 // QDeclarativeListProperty<T>. List properties can accept a list of
2053 // objects, or a single binding.
2054 bool QDeclarativeCompiler::buildListProperty(QDeclarativeParser::Property *prop,
2055 QDeclarativeParser::Object *obj,
2056 const BindingContext &ctxt)
2058 Q_ASSERT(prop->core.isQList());
2062 obj->addValueProperty(prop);
2064 int listType = enginePrivate->listType(t);
2065 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
2067 bool assignedBinding = false;
2068 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2070 v->type = Value::CreatedObject;
2071 COMPILE_CHECK(buildObject(v->object, ctxt));
2073 // We check object coercian here. We check interface assignment
2075 if (!listTypeIsInterface) {
2076 if (!canCoerce(listType, v->object)) {
2077 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2081 } else if (v->value.isScript()) {
2082 if (assignedBinding)
2083 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2085 assignedBinding = true;
2086 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2087 v->type = Value::PropertyBinding;
2089 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2096 // Compiles an assignment to a QDeclarativeScriptString property
2097 bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeParser::Property *prop,
2098 QDeclarativeParser::Object *obj,
2099 const BindingContext &ctxt)
2101 if (prop->values.isMany())
2102 COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2104 if (prop->values.first()->object)
2105 COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2107 prop->scriptStringScope = ctxt.stack;
2108 obj->addScriptStringProperty(prop);
2113 // Compile regular property assignments of the form "property: <value>"
2114 bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeParser::Property *prop,
2115 QDeclarativeParser::Object *obj,
2116 const BindingContext &ctxt)
2118 obj->addValueProperty(prop);
2120 if (prop->values.isMany())
2121 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2123 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2126 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2130 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2135 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2136 Q_ASSERT(v->object);
2137 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2143 // Compile assigning a single object instance to a regular property
2144 bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeParser::Property *prop,
2145 QDeclarativeParser::Object *obj,
2146 QDeclarativeParser::Value *v,
2147 const BindingContext &ctxt)
2149 Q_ASSERT(prop->index != -1);
2150 Q_ASSERT(v->object->type != -1);
2152 if (!obj->metaObject()->property(prop->index).isWritable())
2153 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2155 if (QDeclarativeMetaType::isInterface(prop->type)) {
2157 // Assigning an object to an interface ptr property
2158 COMPILE_CHECK(buildObject(v->object, ctxt));
2160 v->type = Value::CreatedObject;
2162 } else if (prop->type == QMetaType::QVariant) {
2164 // Assigning an object to a QVariant
2165 COMPILE_CHECK(buildObject(v->object, ctxt));
2167 v->type = Value::CreatedObject;
2169 // Normally buildObject() will set this up, but we need the static
2170 // meta object earlier to test for assignability. It doesn't matter
2171 // that there may still be outstanding synthesized meta object changes
2172 // on this type, as they are not relevant for assignability testing
2173 v->object->metatype = output->types.at(v->object->type).metaObject();
2174 Q_ASSERT(v->object->metaObject());
2176 // We want to raw metaObject here as the raw metaobject is the
2177 // actual property type before we applied any extensions that might
2178 // effect the properties on the type, but don't effect assignability
2179 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2181 // Will be true if the assgned type inherits propertyMetaObject
2182 bool isAssignable = false;
2183 // Determine isAssignable value
2184 if (propertyMetaObject) {
2185 const QMetaObject *c = v->object->metatype;
2187 isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject));
2188 c = c->superClass();
2193 // Simple assignment
2194 COMPILE_CHECK(buildObject(v->object, ctxt));
2196 v->type = Value::CreatedObject;
2197 } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) {
2198 // Automatic "Component" insertion
2199 QDeclarativeParser::Object *root = v->object;
2200 QDeclarativeParser::Object *component = pool->New<Object>();
2201 component->type = componentTypeRef();
2202 component->typeName = "Qt/Component";
2203 component->metatype = &QDeclarativeComponent::staticMetaObject;
2204 component->location = root->location;
2205 QDeclarativeParser::Value *componentValue = pool->New<Value>();
2206 componentValue->object = root;
2207 component->getDefaultProperty()->addValue(componentValue);
2208 v->object = component;
2209 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2211 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2218 // Compile assigning a single object instance to a regular property using the "on" syntax.
2222 // NumberAnimation on x { }
2224 bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeParser::Property *prop,
2225 QDeclarativeParser::Object *obj,
2226 QDeclarativeParser::Object *baseObj,
2227 QDeclarativeParser::Value *v,
2228 const BindingContext &ctxt)
2230 Q_ASSERT(prop->index != -1);
2231 Q_ASSERT(v->object->type != -1);
2233 if (!obj->metaObject()->property(prop->index).isWritable())
2234 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2237 // Normally buildObject() will set this up, but we need the static
2238 // meta object earlier to test for assignability. It doesn't matter
2239 // that there may still be outstanding synthesized meta object changes
2240 // on this type, as they are not relevant for assignability testing
2241 v->object->metatype = output->types.at(v->object->type).metaObject();
2242 Q_ASSERT(v->object->metaObject());
2244 // Will be true if the assigned type inherits QDeclarativePropertyValueSource
2245 bool isPropertyValue = false;
2246 // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor
2247 bool isPropertyInterceptor = false;
2248 if (QDeclarativeType *valueType = toQmlType(v->object)) {
2249 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2250 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2253 if (isPropertyValue || isPropertyInterceptor) {
2254 // Assign as a property value source
2255 COMPILE_CHECK(buildObject(v->object, ctxt));
2257 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2258 buildDynamicMeta(baseObj, ForceCreation);
2259 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2261 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(QString::fromUtf8(v->object->typeName)).arg(prop->name().toString()));
2267 // Compile assigning a literal or binding to a regular property
2268 bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeParser::Property *prop,
2269 QDeclarativeParser::Object *obj,
2270 QDeclarativeParser::Value *v,
2271 const BindingContext &ctxt)
2273 Q_ASSERT(prop->index != -1);
2275 if (v->value.isScript()) {
2277 //optimization for <Type>.<EnumValue> enum assignments
2278 if (prop->core.isEnum()) {
2279 bool isEnumAssignment = false;
2280 COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj,
2281 v, &isEnumAssignment));
2282 if (isEnumAssignment) {
2283 v->type = Value::Literal;
2288 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2290 v->type = Value::PropertyBinding;
2294 COMPILE_CHECK(testLiteralAssignment(prop, v));
2296 v->type = Value::Literal;
2302 bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop,
2303 QDeclarativeParser::Object *obj,
2304 QDeclarativeParser::Value *v,
2307 *isAssignment = false;
2308 if (!prop.isEnumType())
2311 if (!prop.isWritable())
2312 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
2314 QString string = v->value.asString();
2315 if (!QDeclarativeUtils::isUpper(string.at(0)))
2318 QStringList parts = string.split(QLatin1Char('.'));
2319 if (parts.count() != 2)
2322 QString typeName = parts.at(0);
2323 QDeclarativeType *type = 0;
2324 unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
2326 //handle enums on value types (where obj->typeName is empty)
2327 QByteArray objTypeName = obj->typeName;
2328 if (objTypeName.isEmpty()) {
2329 QDeclarativeType *objType = toQmlType(obj);
2331 objTypeName = objType->qmlTypeName();
2337 QString enumValue = parts.at(1);
2340 if (objTypeName == type->qmlTypeName()) {
2341 // When these two match, we can short cut the search
2342 if (prop.isFlagType()) {
2343 value = prop.enumerator().keysToValue(enumValue.toUtf8().constData());
2345 value = prop.enumerator().keyToValue(enumValue.toUtf8().constData());
2348 // Otherwise we have to search the whole type
2349 // This matches the logic in QV8TypeWrapper
2350 QByteArray enumName = enumValue.toUtf8();
2351 const QMetaObject *metaObject = type->baseMetaObject();
2352 for (int ii = metaObject->enumeratorCount() - 1; value == -1 && ii >= 0; --ii) {
2353 QMetaEnum e = metaObject->enumerator(ii);
2354 value = e.keyToValue(enumName.constData());
2361 v->type = Value::Literal;
2362 v->value = QDeclarativeParser::Variant((double)value);
2363 *isAssignment = true;
2368 struct StaticQtMetaObject : public QObject
2370 static const QMetaObject *get()
2371 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2374 // Similar logic to above, but not knowing target property.
2375 int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const
2377 int dot = script.indexOf('.');
2379 const QByteArray &scope = script.left(dot);
2380 QDeclarativeType *type = 0;
2381 unit->imports().resolveType(QString::fromUtf8(script.left(dot)), &type, 0, 0, 0, 0);
2382 if (!type && scope != "Qt")
2384 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2385 const char *key = script.constData() + dot+1;
2386 int i = mo->enumeratorCount();
2388 int v = mo->enumerator(i).keyToValue(key);
2396 const QMetaObject *QDeclarativeCompiler::resolveType(const QByteArray& name) const
2398 QDeclarativeType *qmltype = 0;
2399 if (!unit->imports().resolveType(QString::fromUtf8(name), &qmltype, 0, 0, 0, 0))
2403 return qmltype->metaObject();
2406 // similar to logic of completeComponentBuild, but also sticks data
2407 // into primitives at the end
2408 int QDeclarativeCompiler::rewriteBinding(const QString& expression, const QString& name)
2410 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2411 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf('.') + 1));
2413 QString rewrite = rewriteBinding(expression, 0, 0);
2415 return output->indexForString(rewrite);
2418 // Ensures that the dynamic meta specification on obj is valid
2419 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj)
2421 bool seenDefaultProperty = false;
2423 // We use a coarse grain, 31 bit hash to check if there are duplicates.
2424 // Calculating the hash for the names is not a waste as we have to test
2425 // them against the illegalNames set anyway.
2426 QHashField propNames;
2427 QHashField methodNames;
2430 int dpCount = obj->dynamicProperties.count();
2431 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2432 const QDeclarativeParser::Object::DynamicProperty &prop = *p;
2434 if (prop.isDefaultProperty) {
2435 if (seenDefaultProperty)
2436 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2437 seenDefaultProperty = true;
2440 if (propNames.testAndSet(prop.name.hash())) {
2441 for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p;
2442 p2 = obj->dynamicProperties.next(p2)) {
2443 if (p2->name == prop.name)
2444 COMPILE_EXCEPTION(&prop, tr("Duplicate property name"));
2448 if (QDeclarativeUtils::isUpper(prop.name.at(0)))
2449 COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
2451 if (enginePrivate->v8engine()->illegalNames().contains(prop.name))
2452 COMPILE_EXCEPTION(&prop, tr("Illegal property name"));
2455 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2456 const QDeclarativeScript::Object::DynamicSignal &currSig = *s;
2458 if (methodNames.testAndSet(currSig.name.hash())) {
2459 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2460 s2 = obj->dynamicSignals.next(s2)) {
2461 if (s2->name == currSig.name)
2462 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2466 if (currSig.name.at(0).isUpper())
2467 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2468 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2469 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2472 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2473 const QDeclarativeScript::Object::DynamicSlot &currSlot = *s;
2475 if (methodNames.testAndSet(currSlot.name.hash())) {
2476 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2477 s2 = obj->dynamicSignals.next(s2)) {
2478 if (s2->name == currSlot.name)
2479 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2481 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2482 s2 = obj->dynamicSlots.next(s2)) {
2483 if (s2->name == currSlot.name)
2484 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2488 if (currSlot.name.at(0).isUpper())
2489 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2490 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2491 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2497 bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeParser::Object *obj)
2499 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2501 if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2504 Property *property = 0;
2505 if (p->isDefaultProperty) {
2506 property = obj->getDefaultProperty();
2508 property = obj->getProperty(p->name);
2509 if (!property->values.isEmpty())
2510 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2513 if (property->value)
2514 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2516 property->values.append(p->defaultValue->values);
2521 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2523 bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, DynamicMetaMode mode)
2526 Q_ASSERT(obj->metatype);
2528 if (mode != ForceCreation &&
2529 obj->dynamicProperties.isEmpty() &&
2530 obj->dynamicSignals.isEmpty() &&
2531 obj->dynamicSlots.isEmpty())
2534 bool resolveAlias = (mode == ResolveAliases);
2536 const Object::DynamicProperty *defaultProperty = 0;
2539 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2541 if (p->type == Object::DynamicProperty::Alias)
2544 if (p->isDefaultProperty &&
2545 (resolveAlias || p->type != Object::DynamicProperty::Alias))
2546 defaultProperty = p;
2548 if (!resolveAlias) {
2549 // No point doing this for both the alias and non alias cases
2550 QDeclarativePropertyCache::Data *d = property(obj, p->name);
2551 if (d && d->isFinal())
2552 COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2556 bool buildData = resolveAlias || aliasCount == 0;
2558 QByteArray dynamicData;
2560 typedef QDeclarativeVMEMetaData VMD;
2562 dynamicData = QByteArray(sizeof(QDeclarativeVMEMetaData) +
2563 (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) +
2564 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2565 aliasCount * sizeof(VMD::AliasData), 0);
2568 int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1);
2570 QByteArray newClassName = obj->metatype->className();
2571 newClassName.append("_QML_");
2572 newClassName.append(QByteArray::number(uniqueClassId));
2574 if (compileState->root == obj && !compileState->nested) {
2575 QString path = output->url.path();
2576 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2577 if (lastSlash > -1) {
2578 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2579 if (!nameBase.isEmpty() && QDeclarativeUtils::isUpper(nameBase.at(0)))
2580 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId);
2584 QFastMetaBuilder builder;
2585 QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(),
2586 obj->dynamicProperties.count() - (resolveAlias?0:aliasCount),
2587 obj->dynamicSlots.count(),
2588 obj->dynamicSignals.count() + obj->dynamicProperties.count(),
2589 defaultProperty?1:0);
2592 Object::DynamicProperty::Type dtype;
2594 const char *cppType;
2595 } builtinTypes[] = {
2596 { Object::DynamicProperty::Variant, 0, "QVariant" },
2597 { Object::DynamicProperty::Int, QMetaType::Int, "int" },
2598 { Object::DynamicProperty::Bool, QMetaType::Bool, "bool" },
2599 { Object::DynamicProperty::Real, QMetaType::Double, "double" },
2600 { Object::DynamicProperty::String, QMetaType::QString, "QString" },
2601 { Object::DynamicProperty::Url, QMetaType::QUrl, "QUrl" },
2602 { Object::DynamicProperty::Color, QMetaType::QColor, "QColor" },
2603 { Object::DynamicProperty::Time, QMetaType::QTime, "QTime" },
2604 { Object::DynamicProperty::Date, QMetaType::QDate, "QDate" },
2605 { Object::DynamicProperty::DateTime, QMetaType::QDateTime, "QDateTime" },
2607 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2608 QFastMetaBuilder::StringRef typeRefs[builtinTypeCount];
2610 // Reserve dynamic properties
2611 if (obj->dynamicProperties.count()) {
2612 typedef QDeclarativeVMEMetaData VMD;
2614 int effectivePropertyIndex = 0;
2615 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2617 // Reserve space for name
2618 p->nameRef = builder.newString(p->name.utf8length());
2620 int propertyType = 0;
2621 bool readonly = false;
2622 QFastMetaBuilder::StringRef typeRef;
2624 if (p->type == Object::DynamicProperty::Alias) {
2626 } else if (p->type < builtinTypeCount) {
2627 Q_ASSERT(builtinTypes[p->type].dtype == p->type);
2628 propertyType = builtinTypes[p->type].metaType;
2629 if (typeRefs[p->type].isEmpty())
2630 typeRefs[p->type] = builder.newString(strlen(builtinTypes[p->type].cppType));
2631 typeRef = typeRefs[p->type];
2632 if (p->type == Object::DynamicProperty::Variant)
2636 Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
2637 p->type == Object::DynamicProperty::Custom);
2639 // XXX don't double resolve this in the case of an alias run
2641 QByteArray customTypeName;
2642 QDeclarativeType *qmltype = 0;
2644 if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
2645 COMPILE_EXCEPTION(p, tr("Invalid property type"));
2648 QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(QUrl(url));
2650 Q_ASSERT(tdata->isComplete());
2652 QDeclarativeCompiledData *data = tdata->compiledData();
2653 customTypeName = data->root->className();
2657 customTypeName = qmltype->typeName();
2660 if (p->type == Object::DynamicProperty::Custom) {
2661 customTypeName += '*';
2662 propertyType = QMetaType::QObjectStar;
2665 customTypeName = QByteArray("QDeclarativeListProperty<") + customTypeName + QByteArray(">");
2666 propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
2669 p->resolvedCustomTypeName = pool->NewByteArray(customTypeName);
2670 p->typeRef = builder.newString(customTypeName.length());
2671 typeRef = p->typeRef;
2675 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2676 vmd->propertyCount++;
2677 (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType;
2680 if (p->type < builtinTypeCount)
2681 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef, (QMetaType::Type)propertyType,
2682 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2683 effectivePropertyIndex);
2685 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef,
2686 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2687 effectivePropertyIndex);
2689 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2690 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2692 effectivePropertyIndex++;
2697 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2698 if (p->type == Object::DynamicProperty::Alias) {
2700 Q_ASSERT(buildData);
2701 ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++;
2702 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex,
2705 // Even if we aren't resolving the alias, we need a fake signal so that the
2706 // metaobject remains consistent across the resolve and non-resolve alias runs
2707 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2708 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2709 effectivePropertyIndex++;
2716 // Reserve default property
2717 QFastMetaBuilder::StringRef defPropRef;
2718 if (defaultProperty) {
2719 defPropRef = builder.newString(strlen("DefaultProperty"));
2720 builder.setClassInfo(0, defPropRef, defaultProperty->nameRef);
2723 // Reserve dynamic signals
2724 int signalIndex = 0;
2725 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2727 int paramCount = s->parameterNames.count();
2729 int signatureSize = s->name.utf8length() + 2 /* paren */;
2731 if (paramCount) signatureSize += s->parameterTypesLength() + (paramCount - 1) /* commas */;
2732 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1) /* commas */;
2734 s->signatureRef = builder.newString(signatureSize);
2735 if (namesSize) s->parameterNamesRef = builder.newString(namesSize);
2738 ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++;
2740 builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->signatureRef, s->parameterNamesRef);
2744 // Reserve dynamic slots
2745 if (obj->dynamicSlots.count()) {
2747 // Allocate QVariant string
2748 if (typeRefs[0].isEmpty())
2749 typeRefs[0] = builder.newString(strlen(builtinTypes[0].cppType));
2751 typedef QDeclarativeVMEMetaData VMD;
2753 int methodIndex = 0;
2754 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2755 int paramCount = s->parameterNames.count();
2757 int signatureSize = s->name.utf8length() + 2 /* paren */;
2759 if (paramCount) signatureSize += (paramCount * strlen("QVariant") + (paramCount - 1));
2760 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
2762 s->signatureRef = builder.newString(signatureSize);
2763 if (namesSize) s->parameterNamesRef = builder.newString(namesSize);
2765 builder.setMethod(methodIndex, s->signatureRef, s->parameterNamesRef, typeRefs[0]);
2769 funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ +
2770 namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
2771 funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
2772 for (int jj = 0; jj < paramCount; ++jj) {
2773 if (jj) funcScript.append(QLatin1Char(','));
2774 funcScript.append(QLatin1String(s->parameterNames.at(jj)));
2776 funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
2778 VMD::MethodData methodData = { s->parameterNames.count(), 0,
2779 funcScript.length(),
2780 s->location.start.line };
2782 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2785 VMD::MethodData &md = *(vmd->methodData() + methodIndex);
2787 md.bodyOffset = dynamicData.size();
2789 dynamicData.append((const char *)funcScript.constData(),
2790 (funcScript.length() * sizeof(QChar)));
2797 // Now allocate used builtin types
2798 for (int ii = 0; ii < builtinTypeCount; ++ii) {
2799 if (!typeRefs[ii].isEmpty())
2800 typeRefs[ii].load(builtinTypes[ii].cppType);
2803 // Now allocate properties
2804 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2806 char *d = p->changedSignatureRef.data();
2807 p->name.writeUtf8(d);
2808 strcpy(d + p->name.utf8length(), "Changed()");
2810 if (p->type == Object::DynamicProperty::Alias && !resolveAlias)
2813 p->nameRef.load(p->name);
2815 if (p->type >= builtinTypeCount) {
2816 Q_ASSERT(p->resolvedCustomTypeName);
2817 p->typeRef.load(*p->resolvedCustomTypeName);
2821 // Allocate default property if necessary
2822 if (defaultProperty)
2823 strcpy(defPropRef.data(), "DefaultProperty");
2825 // Now allocate signals
2826 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2828 char *d = s->signatureRef.data();
2829 char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data();
2830 s->name.writeUtf8(d); d += s->name.utf8length();
2833 for (int jj = 0; jj < s->parameterNames.count(); ++jj) {
2834 if (jj != 0) { *d++ = ','; *d2++ = ','; }
2835 strcpy(d, s->parameterTypes.at(jj).constData());
2836 d += s->parameterTypes.at(jj).length();
2837 s->parameterNames.at(jj).writeUtf8(d2);
2838 d2 += s->parameterNames.at(jj).utf8length();
2845 // Now allocate methods
2846 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2847 char *d = s->signatureRef.data();
2848 char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data();
2849 s->name.writeUtf8(d); d += s->name.utf8length();
2851 for (int jj = 0; jj < s->parameterNames.count(); ++jj) {
2852 if (jj != 0) { *d++ = ','; *d2++ = ','; }
2853 strcpy(d, "QVariant");
2854 d += strlen("QVariant");
2855 strcpy(d2, s->parameterNames.at(jj).constData());
2856 d2 += s->parameterNames.at(jj).length();
2863 // Now allocate class name
2864 classNameRef.load(newClassName);
2866 obj->metadata = builder.toData();
2867 builder.fromData(&obj->extObject, obj->metatype, obj->metadata);
2869 if (mode == IgnoreAliases && aliasCount)
2870 compileState->aliasingObjects.append(obj);
2872 obj->synthdata = dynamicData;
2874 if (obj->synthCache) {
2875 obj->synthCache->release();
2876 obj->synthCache = 0;
2879 if (obj->type != -1) {
2880 QDeclarativePropertyCache *cache = output->types[obj->type].createPropertyCache(engine)->copy();
2881 cache->append(engine, &obj->extObject, QDeclarativePropertyCache::Data::NoFlags,
2882 QDeclarativePropertyCache::Data::IsVMEFunction,
2883 QDeclarativePropertyCache::Data::IsVMESignal);
2884 obj->synthCache = cache;
2890 bool QDeclarativeCompiler::checkValidId(QDeclarativeParser::Value *v, const QString &val)
2893 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
2895 QChar ch = val.at(0);
2896 if (QDeclarativeUtils::isLetter(ch) && !QDeclarativeUtils::isLower(ch))
2897 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
2899 QChar u(QLatin1Char('_'));
2900 if (!QDeclarativeUtils::isLetter(ch) && ch != u)
2901 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
2903 for (int ii = 1; ii < val.count(); ++ii) {
2905 if (!QDeclarativeUtils::isLetterOrNumber(ch) && ch != u)
2906 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
2909 if (enginePrivate->v8engine()->illegalNames().contains(val))
2910 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
2915 #include <qdeclarativejsparser_p.h>
2917 static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node)
2919 if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) {
2921 static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name.toString();
2922 return QStringList() << name;
2923 } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) {
2924 QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node);
2926 QStringList rv = astNodeToStringList(expr->base);
2929 rv.append(expr->name.toString());
2932 return QStringList();
2935 bool QDeclarativeCompiler::compileAlias(QFastMetaBuilder &builder,
2937 QDeclarativeParser::Object *obj,
2938 int propIndex, int aliasIndex,
2939 Object::DynamicProperty &prop)
2941 if (!prop.defaultValue)
2942 COMPILE_EXCEPTION(obj, tr("No property alias location"));
2944 if (!prop.defaultValue->values.isOne() ||
2945 prop.defaultValue->values.first()->object ||
2946 !prop.defaultValue->values.first()->value.isScript())
2947 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2949 QDeclarativeJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST();
2951 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
2953 QStringList alias = astNodeToStringList(node);
2955 if (alias.count() < 1 || alias.count() > 3)
2956 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
2958 QDeclarativeParser::Object *idObject = compileState->ids.value(alias.at(0));
2960 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
2962 QByteArray typeName;
2967 bool writable = false;
2968 bool resettable = false;
2969 if (alias.count() == 2 || alias.count() == 3) {
2970 propIdx = indexOfProperty(idObject, alias.at(1));
2972 if (-1 == propIdx) {
2973 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2974 } else if (propIdx > 0xFFFF) {
2975 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
2978 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
2979 if (!aliasProperty.isScriptable())
2980 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2982 writable = aliasProperty.isWritable();
2983 resettable = aliasProperty.isResettable();
2985 if (aliasProperty.type() < QVariant::UserType)
2986 type = aliasProperty.type();
2988 if (alias.count() == 3) {
2989 QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
2991 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2993 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
2995 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
2996 if (valueTypeIndex == -1)
2997 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2998 Q_ASSERT(valueTypeIndex <= 0xFF);
3000 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
3001 propIdx |= (valueTypeIndex << 16);
3003 // update the property type
3004 type = aliasProperty.type();
3005 if (type >= QVariant::UserType)
3009 if (aliasProperty.isEnumType())
3010 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
3012 typeName = aliasProperty.typeName();
3014 Q_ASSERT(idObject->type != -1); // How else did it get an id?
3016 const QDeclarativeCompiledData::TypeReference &ref = output->types.at(idObject->type);
3018 typeName = ref.type->typeName();
3020 typeName = ref.component->root->className();
3025 if (typeName.endsWith('*'))
3026 flags |= QML_ALIAS_FLAG_PTR;
3028 QDeclarativeVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags };
3030 typedef QDeclarativeVMEMetaData VMD;
3031 VMD *vmd = (QDeclarativeVMEMetaData *)data.data();
3032 *(vmd->aliasData() + aliasIndex) = aliasData;
3034 prop.nameRef = builder.newString(prop.name.utf8length());
3035 prop.resolvedCustomTypeName = pool->NewByteArray(typeName);
3036 prop.typeRef = builder.newString(typeName.length());
3038 builder.setProperty(propIndex, prop.nameRef, prop.typeRef, (QMetaType::Type)type,
3039 (QFastMetaBuilder::PropertyFlag)(writable?int(QFastMetaBuilder::Writable):0),
3045 bool QDeclarativeCompiler::buildBinding(QDeclarativeParser::Value *value,
3046 QDeclarativeParser::Property *prop,
3047 const BindingContext &ctxt)
3049 Q_ASSERT(prop->index != -1);
3050 Q_ASSERT(prop->parent);
3051 Q_ASSERT(prop->parent->metaObject());
3053 if (!prop->core.isWritable() && !prop->core.isQList())
3054 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3056 BindingReference *reference = pool->New<BindingReference>();
3057 reference->expression = value->value;
3058 reference->property = prop;
3059 reference->value = value;
3060 reference->bindingContext = ctxt;
3061 addBindingReference(reference);
3066 void QDeclarativeCompiler::genBindingAssignment(QDeclarativeParser::Value *binding,
3067 QDeclarativeParser::Property *prop,
3068 QDeclarativeParser::Object *obj,
3069 QDeclarativeParser::Property *valueTypeProperty)
3072 Q_ASSERT(binding->bindingReference);
3074 const BindingReference &ref = *binding->bindingReference;
3075 if (ref.dataType == BindingReference::V4) {
3076 QDeclarativeInstruction store;
3077 store.setType(QDeclarativeInstruction::StoreV4Binding);
3078 store.assignBinding.value = ref.compiledIndex;
3079 store.assignBinding.context = ref.bindingContext.stack;
3080 store.assignBinding.owner = ref.bindingContext.owner;
3081 if (valueTypeProperty)
3082 store.assignBinding.property = (valueTypeProperty->index & 0xFFFF) |
3083 ((valueTypeProperty->type & 0xFF)) << 16 |
3084 ((prop->index & 0xFF) << 24);
3086 store.assignBinding.property = prop->index;
3087 store.assignBinding.line = binding->location.start.line;
3088 output->addInstruction(store);
3089 } else if (ref.dataType == BindingReference::V8) {
3090 QDeclarativeInstruction store;
3091 store.setType(QDeclarativeInstruction::StoreV8Binding);
3092 store.assignBinding.value = ref.compiledIndex;
3093 store.assignBinding.context = ref.bindingContext.stack;
3094 store.assignBinding.owner = ref.bindingContext.owner;
3095 store.assignBinding.line = binding->location.start.line;
3097 Q_ASSERT(ref.bindingContext.owner == 0 ||
3098 (ref.bindingContext.owner != 0 && valueTypeProperty));
3099 if (ref.bindingContext.owner) {
3100 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
3102 store.assignBinding.property = genPropertyData(prop);
3105 output->addInstruction(store);
3107 QDeclarativeInstruction store;
3109 store.setType(QDeclarativeInstruction::StoreBinding);
3111 store.setType(QDeclarativeInstruction::StoreBindingOnAlias);
3112 store.assignBinding.value = output->indexForString(ref.rewrittenExpression);
3113 store.assignBinding.context = ref.bindingContext.stack;
3114 store.assignBinding.owner = ref.bindingContext.owner;
3115 store.assignBinding.line = binding->location.start.line;
3117 Q_ASSERT(ref.bindingContext.owner == 0 ||
3118 (ref.bindingContext.owner != 0 && valueTypeProperty));
3119 if (ref.bindingContext.owner) {
3120 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
3122 store.assignBinding.property = genPropertyData(prop);
3124 output->addInstruction(store);
3128 int QDeclarativeCompiler::genContextCache()
3130 if (compileState->ids.count() == 0)
3133 QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache();
3134 cache->reserve(compileState->ids.count());
3135 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
3136 cache->add(o->id, o->idIndex);
3138 output->contextCaches.append(cache);
3139 return output->contextCaches.count() - 1;
3142 int QDeclarativeCompiler::genValueTypeData(QDeclarativeParser::Property *valueTypeProp,
3143 QDeclarativeParser::Property *prop)
3145 typedef QDeclarativePropertyPrivate QDPP;
3146 QByteArray data = QDPP::saveValueType(prop->parent->metaObject(), prop->index,
3147 enginePrivate->valueTypes[prop->type]->metaObject(),
3148 valueTypeProp->index, engine);
3150 return output->indexForByteArray(data);
3153 int QDeclarativeCompiler::genPropertyData(QDeclarativeParser::Property *prop)
3155 typedef QDeclarativePropertyPrivate QDPP;
3156 QByteArray data = QDPP::saveProperty(prop->parent->metaObject(), prop->index, engine);
3158 return output->indexForByteArray(data);
3161 bool QDeclarativeCompiler::completeComponentBuild()
3164 componentStats->componentStat.ids = compileState->ids.count();
3166 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
3167 aliasObject = compileState->aliasingObjects.next(aliasObject))
3168 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
3170 QDeclarativeV4Compiler::Expression expr(unit->imports());
3171 expr.component = compileState->root;
3172 expr.ids = &compileState->ids;
3173 expr.importCache = output->importCache;
3175 QDeclarativeV4Compiler bindingCompiler;
3177 QList<BindingReference*> sharedBindings;
3179 for (BindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3181 BindingReference &binding = *b;
3183 // ### We don't currently optimize for bindings on alias's - because
3184 // of the solution to QTBUG-13719
3185 if (!binding.property->isAlias) {
3186 expr.context = binding.bindingContext.object;
3187 expr.property = binding.property;
3188 expr.expression = binding.expression;
3190 int index = bindingCompiler.compile(expr, enginePrivate);
3192 binding.dataType = BindingReference::V4;
3193 binding.compiledIndex = index;
3195 componentStats->componentStat.optimizedBindings.append(b->value->location);
3200 // Pre-rewrite the expression
3201 QString expression = binding.expression.asScript();
3203 QDeclarativeRewrite::RewriteBinding rewriteBinding;
3204 rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3205 bool isSharable = false;
3206 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3208 if (isSharable && !binding.property->isAlias /* See above re alias */ &&
3209 binding.property->type != qMetaTypeId<QDeclarativeBinding*>()) {
3210 binding.dataType = BindingReference::V8;
3211 sharedBindings.append(b);
3213 binding.dataType = BindingReference::QtScript;
3217 componentStats->componentStat.scriptBindings.append(b->value->location);
3220 if (!sharedBindings.isEmpty()) {
3222 static bool lt(const BindingReference *lhs, const BindingReference *rhs)
3224 return lhs->value->location.start.line < rhs->value->location.start.line;
3228 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3230 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3231 int lineNumber = startLineNumber;
3233 QString functionArray(QLatin1String("["));
3234 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3235 BindingReference *reference = sharedBindings.at(ii);
3236 QDeclarativeParser::Value *value = reference->value;
3237 const QString &expression = reference->rewrittenExpression;
3239 if (ii != 0) functionArray += QLatin1String(",");
3241 while (lineNumber < value->location.start.line) {
3243 functionArray += QLatin1String("\n");
3246 functionArray += expression;
3247 reference->compiledIndex = ii;
3249 functionArray += QLatin1String("]");
3251 compileState->v8BindingProgram = functionArray;
3252 compileState->v8BindingProgramLine = startLineNumber;
3253 compileState->v8BindingProgramIndex = output->v8bindings.count();
3254 output->v8bindings.append(v8::Persistent<v8::Array>());
3257 if (bindingCompiler.isValid())
3258 compileState->compiledBindingData = bindingCompiler.program();
3260 saveComponentState();
3265 void QDeclarativeCompiler::dumpStats()
3267 Q_ASSERT(componentStats);
3268 qWarning().nospace() << "QML Document: " << output->url.toString();
3269 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3270 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3271 qWarning().nospace() << " Component Line " << stat.lineNumber;
3272 qWarning().nospace() << " Total Objects: " << stat.objects;
3273 qWarning().nospace() << " IDs Used: " << stat.ids;
3274 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3278 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3279 if (0 == (ii % 10)) {
3280 if (ii) output.append("\n");
3285 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3287 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3288 output.append(") ");
3290 if (!output.isEmpty())
3291 qWarning().nospace() << output.constData();
3294 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3297 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3298 if (0 == (ii % 10)) {
3299 if (ii) output.append("\n");
3304 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3306 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3307 output.append(") ");
3309 if (!output.isEmpty())
3310 qWarning().nospace() << output.constData();
3316 Returns true if from can be assigned to a (QObject) property of type
3319 bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeParser::Object *from)
3321 const QMetaObject *toMo =
3322 enginePrivate->rawMetaObjectForType(to);
3323 const QMetaObject *fromMo = from->metaObject();
3326 if (QDeclarativePropertyPrivate::equal(fromMo, toMo))
3328 fromMo = fromMo->superClass();
3334 Returns the element name, as written in the QML file, for o.
3336 QString QDeclarativeCompiler::elementName(QDeclarativeParser::Object *o)
3339 if (o->type != -1) {
3340 return output->types.at(o->type).className;
3346 QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeParser::Object *from)
3349 const QMetaObject *mo = from->metatype;
3350 QDeclarativeType *type = 0;
3351 while (!type && mo) {
3352 type = QDeclarativeMetaType::qmlType(mo);
3353 mo = mo->superClass();
3358 QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeParser::Object *obj)
3360 const QMetaObject *mo = obj->metatype;
3362 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3364 return QStringList();
3366 QMetaClassInfo classInfo = mo->classInfo(idx);
3367 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3371 QDeclarativePropertyCache::Data *
3372 QDeclarativeCompiler::property(QDeclarativeParser::Object *object, int index)
3374 QDeclarativePropertyCache *cache = 0;
3376 if (object->synthCache)
3377 cache = object->synthCache;
3378 else if (object->type != -1)
3379 cache = output->types[object->type].createPropertyCache(engine);
3381 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3383 return cache->property(index);
3386 QDeclarativePropertyCache::Data *
3387 QDeclarativeCompiler::property(QDeclarativeParser::Object *object, const QHashedStringRef &name, bool *notInRevision)
3389 if (notInRevision) *notInRevision = false;
3391 QDeclarativePropertyCache *cache = 0;
3393 if (object->synthCache)
3394 cache = object->synthCache;
3395 else if (object->type != -1)
3396 cache = output->types[object->type].createPropertyCache(engine);
3398 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3400 QDeclarativePropertyCache::Data *d = cache->property(name);
3402 // Find the first property
3403 while (d && d->isFunction())
3404 d = cache->overrideData(d);
3406 if (d && !cache->isAllowedInRevision(d)) {
3407 if (notInRevision) *notInRevision = true;
3414 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3415 QDeclarativePropertyCache::Data *
3416 QDeclarativeCompiler::signal(QDeclarativeParser::Object *object, const QHashedStringRef &name, bool *notInRevision)
3418 if (notInRevision) *notInRevision = false;
3420 QDeclarativePropertyCache *cache = 0;
3422 if (object->synthCache)
3423 cache = object->synthCache;
3424 else if (object->type != -1)
3425 cache = output->types[object->type].createPropertyCache(engine);
3427 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3430 QDeclarativePropertyCache::Data *d = cache->property(name);
3431 if (notInRevision) *notInRevision = false;
3433 while (d && !(d->isFunction()))
3434 d = cache->overrideData(d);
3436 if (d && !cache->isAllowedInRevision(d)) {
3437 if (notInRevision) *notInRevision = true;
3443 if (name.endsWith(Changed_string)) {
3444 QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3446 d = property(object, propName, notInRevision);
3448 return cache->method(d->notifyIndex);
3454 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3455 int QDeclarativeCompiler::indexOfSignal(QDeclarativeParser::Object *object, const QString &name,
3456 bool *notInRevision)
3458 QDeclarativePropertyCache::Data *d = signal(object, QStringRef(&name), notInRevision);
3459 return d?d->coreIndex:-1;
3462 int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QString &name,
3463 bool *notInRevision)
3465 return indexOfProperty(object, QStringRef(&name), notInRevision);
3468 int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QHashedStringRef &name,
3469 bool *notInRevision)
3471 QDeclarativePropertyCache::Data *d = property(object, name, notInRevision);
3472 return d?d->coreIndex:-1;