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 bool notInRevision = false;
1582 QDeclarativePropertyCache::Data *d =
1583 prop->name().isEmpty()?0:property(obj, prop->name(), ¬InRevision);
1585 if (d == 0 && notInRevision) {
1586 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1587 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1589 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));
1591 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1594 prop->index = d->coreIndex;
1598 // We can't error here as the "id" property does not require a
1599 // successful index resolution
1600 if (prop->index != -1)
1601 prop->type = prop->core.propType;
1603 // Check if this is an alias
1604 if (prop->index != -1 &&
1606 prop->parent->type != -1 &&
1607 output->types.at(prop->parent->type).component) {
1609 QDeclarativePropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1610 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1611 prop->isAlias = true;
1614 if (prop->index != -1 && !prop->values.isEmpty())
1615 prop->parent->setBindingBit(prop->index);
1618 if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1620 // The magic "id" behavior doesn't apply when "id" is resolved as a
1621 // default property or to sub-objects (which are always in binding
1623 COMPILE_CHECK(buildIdProperty(prop, obj));
1624 if (prop->type == QVariant::String &&
1625 prop->values.first()->value.isString())
1626 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1628 } else if (isAttachedPropertyName(prop->name())) {
1630 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1632 } else if (prop->index == -1) {
1634 if (prop->isDefault) {
1635 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1637 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1640 } else if (prop->value) {
1642 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1644 } else if (prop->core.isQList()) {
1646 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1648 } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) {
1650 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1654 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1661 bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
1662 QDeclarativeParser::Property *nsProp,
1663 QDeclarativeParser::Object *obj,
1664 const BindingContext &ctxt)
1667 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1669 for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1671 if (!isAttachedPropertyName(prop->name()))
1672 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1674 // Setup attached property data
1676 QDeclarativeType *type = 0;
1677 unit->imports().resolveType(ns, prop->name().toString(), &type, 0, 0, 0);
1679 if (!type || !type->attachedPropertiesType())
1680 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1683 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1685 Q_ASSERT(type->attachedPropertiesFunction());
1686 prop->index = type->index();
1687 prop->value->metatype = type->attachedPropertiesType();
1689 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1695 void QDeclarativeCompiler::genValueProperty(QDeclarativeParser::Property *prop,
1696 QDeclarativeParser::Object *obj)
1698 if (prop->core.isQList()) {
1699 genListProperty(prop, obj);
1701 genPropertyAssignment(prop, obj);
1705 void QDeclarativeCompiler::genListProperty(QDeclarativeParser::Property *prop,
1706 QDeclarativeParser::Object *obj)
1708 int listType = enginePrivate->listType(prop->type);
1710 QDeclarativeInstruction fetch;
1711 fetch.setType(QDeclarativeInstruction::FetchQList);
1712 fetch.fetchQmlList.property = prop->index;
1713 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1714 fetch.fetchQmlList.type = listType;
1715 output->addInstruction(fetch);
1717 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1719 if (v->type == Value::CreatedObject) {
1721 genObject(v->object);
1722 if (listTypeIsInterface) {
1723 QDeclarativeInstruction assign;
1724 assign.setType(QDeclarativeInstruction::AssignObjectList);
1725 assign.assignObjectList.line = prop->location.start.line;
1726 output->addInstruction(assign);
1728 QDeclarativeInstruction store;
1729 store.setType(QDeclarativeInstruction::StoreObjectQList);
1730 output->addInstruction(store);
1733 } else if (v->type == Value::PropertyBinding) {
1735 genBindingAssignment(v, prop, obj);
1741 QDeclarativeInstruction pop;
1742 pop.setType(QDeclarativeInstruction::PopQList);
1743 output->addInstruction(pop);
1746 void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *prop,
1747 QDeclarativeParser::Object *obj,
1748 QDeclarativeParser::Property *valueTypeProperty)
1750 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1752 Q_ASSERT(v->type == Value::CreatedObject ||
1753 v->type == Value::PropertyBinding ||
1754 v->type == Value::Literal);
1756 if (v->type == Value::CreatedObject) {
1758 genObject(v->object);
1760 if (QDeclarativeMetaType::isInterface(prop->type)) {
1762 QDeclarativeInstruction store;
1763 store.setType(QDeclarativeInstruction::StoreInterface);
1764 store.storeObject.line = v->object->location.start.line;
1765 store.storeObject.propertyIndex = prop->index;
1766 output->addInstruction(store);
1768 } else if (prop->type == QMetaType::QVariant) {
1770 QDeclarativeInstruction store;
1771 store.setType(QDeclarativeInstruction::StoreVariantObject);
1772 store.storeObject.line = v->object->location.start.line;
1773 store.storeObject.propertyIndex = prop->index;
1774 output->addInstruction(store);
1778 QDeclarativeInstruction store;
1779 store.setType(QDeclarativeInstruction::StoreObject);
1780 store.storeObject.line = v->object->location.start.line;
1781 store.storeObject.propertyIndex = prop->index;
1782 output->addInstruction(store);
1785 } else if (v->type == Value::PropertyBinding) {
1787 genBindingAssignment(v, prop, obj, valueTypeProperty);
1789 } else if (v->type == Value::Literal) {
1791 genLiteralAssignment(prop, v);
1797 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
1799 Q_ASSERT(v->type == Value::ValueSource ||
1800 v->type == Value::ValueInterceptor);
1802 if (v->type == Value::ValueSource) {
1803 genObject(v->object);
1805 QDeclarativeInstruction store;
1806 store.setType(QDeclarativeInstruction::StoreValueSource);
1807 if (valueTypeProperty) {
1808 store.assignValueSource.property = genValueTypeData(prop, valueTypeProperty);
1809 store.assignValueSource.owner = 1;
1811 store.assignValueSource.property = genPropertyData(prop);
1812 store.assignValueSource.owner = 0;
1814 QDeclarativeType *valueType = toQmlType(v->object);
1815 store.assignValueSource.castValue = valueType->propertyValueSourceCast();
1816 output->addInstruction(store);
1818 } else if (v->type == Value::ValueInterceptor) {
1819 genObject(v->object);
1821 QDeclarativeInstruction store;
1822 store.setType(QDeclarativeInstruction::StoreValueInterceptor);
1823 if (valueTypeProperty) {
1824 store.assignValueInterceptor.property = genValueTypeData(prop, valueTypeProperty);
1825 store.assignValueInterceptor.owner = 1;
1827 store.assignValueInterceptor.property = genPropertyData(prop);
1828 store.assignValueInterceptor.owner = 0;
1830 QDeclarativeType *valueType = toQmlType(v->object);
1831 store.assignValueInterceptor.castValue = valueType->propertyValueInterceptorCast();
1832 output->addInstruction(store);
1838 bool QDeclarativeCompiler::buildIdProperty(QDeclarativeParser::Property *prop,
1839 QDeclarativeParser::Object *obj)
1842 prop->values.isMany() ||
1843 prop->values.first()->object)
1844 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
1846 QDeclarativeParser::Value *idValue = prop->values.first();
1847 QString val = idValue->primitive();
1849 COMPILE_CHECK(checkValidId(idValue, val));
1851 if (compileState->ids.value(val))
1852 COMPILE_EXCEPTION(prop, tr("id is not unique"));
1854 prop->values.first()->type = Value::Id;
1862 void QDeclarativeCompiler::addId(const QString &id, QDeclarativeParser::Object *obj)
1864 Q_ASSERT(!compileState->ids.value(id));
1865 Q_ASSERT(obj->id == id);
1866 obj->idIndex = compileState->ids.count();
1867 compileState->ids.append(obj);
1870 void QDeclarativeCompiler::addBindingReference(BindingReference *ref)
1872 Q_ASSERT(ref->value && !ref->value->bindingReference);
1873 ref->value->bindingReference = ref;
1874 compileState->bindings.prepend(ref);
1877 void QDeclarativeCompiler::saveComponentState()
1879 Q_ASSERT(compileState->root);
1880 Q_ASSERT(compileState->root->componentCompileState == 0);
1882 compileState->root->componentCompileState = compileState;
1885 componentStats->savedComponentStats.append(componentStats->componentStat);
1888 QDeclarativeCompilerTypes::ComponentCompileState *
1889 QDeclarativeCompiler::componentState(QDeclarativeParser::Object *obj)
1891 Q_ASSERT(obj->componentCompileState);
1892 return obj->componentCompileState;
1895 // Build attached property object. In this example,
1899 // GridView is an attached property object.
1900 bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeParser::Property *prop,
1901 QDeclarativeParser::Object *obj,
1902 const BindingContext &ctxt)
1904 Q_ASSERT(prop->value);
1905 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
1907 obj->addAttachedProperty(prop);
1909 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1915 // Build "grouped" properties. In this example:
1917 // font.pointSize: 12
1918 // font.family: "Helvetica"
1920 // font is a nested property. pointSize and family are not.
1921 bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeParser::Property *prop,
1922 QDeclarativeParser::Object *obj,
1923 const BindingContext &ctxt)
1925 Q_ASSERT(prop->type != 0);
1926 Q_ASSERT(prop->index != -1);
1928 if (QDeclarativeValueTypeFactory::isValueType(prop->type)) {
1929 if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
1931 if (!prop->values.isEmpty()) {
1932 if (prop->values.first()->location < prop->value->location) {
1933 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
1935 COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
1939 if (!obj->metaObject()->property(prop->index).isWritable()) {
1940 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
1944 if (prop->isAlias) {
1945 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
1946 vtProp->isAlias = true;
1950 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
1951 prop->value, obj, ctxt.incr()));
1952 obj->addValueTypeProperty(prop);
1954 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1958 // Load the nested property's meta type
1959 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
1960 if (!prop->value->metatype)
1961 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1963 if (!prop->values.isEmpty())
1964 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
1966 obj->addGroupedProperty(prop);
1968 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1974 bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
1975 QDeclarativeParser::Object *obj,
1976 QDeclarativeParser::Object *baseObj,
1977 const BindingContext &ctxt)
1979 if (obj->defaultProperty)
1980 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
1981 obj->metatype = type->metaObject();
1983 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1985 QDeclarativePropertyCache::Data *d = property(obj, prop->name());
1987 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1989 prop->index = d->coreIndex;
1990 prop->type = d->propType;
1992 prop->isValueTypeSubProperty = true;
1995 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
1997 if (prop->values.isMany()) {
1998 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
1999 } else if (!prop->values.isEmpty()) {
2000 QDeclarativeParser::Value *value = prop->values.first();
2002 if (value->object) {
2003 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
2004 } else if (value->value.isScript()) {
2005 // ### Check for writability
2007 //optimization for <Type>.<EnumValue> enum assignments
2008 bool isEnumAssignment = false;
2010 if (prop->core.isEnum())
2011 COMPILE_CHECK(testQualifiedEnumAssignment(obj->metatype->property(prop->index), obj,
2012 value, &isEnumAssignment));
2014 if (isEnumAssignment) {
2015 value->type = Value::Literal;
2017 BindingReference *reference = pool->New<BindingReference>();
2018 reference->expression = value->value;
2019 reference->property = prop;
2020 reference->value = value;
2021 reference->bindingContext = ctxt;
2022 reference->bindingContext.owner++;
2023 addBindingReference(reference);
2024 value->type = Value::PropertyBinding;
2027 COMPILE_CHECK(testLiteralAssignment(prop, value));
2028 value->type = Value::Literal;
2032 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2033 Q_ASSERT(v->object);
2035 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
2038 obj->addValueProperty(prop);
2044 // Build assignments to QML lists. QML lists are properties of type
2045 // QDeclarativeListProperty<T>. List properties can accept a list of
2046 // objects, or a single binding.
2047 bool QDeclarativeCompiler::buildListProperty(QDeclarativeParser::Property *prop,
2048 QDeclarativeParser::Object *obj,
2049 const BindingContext &ctxt)
2051 Q_ASSERT(prop->core.isQList());
2055 obj->addValueProperty(prop);
2057 int listType = enginePrivate->listType(t);
2058 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
2060 bool assignedBinding = false;
2061 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2063 v->type = Value::CreatedObject;
2064 COMPILE_CHECK(buildObject(v->object, ctxt));
2066 // We check object coercian here. We check interface assignment
2068 if (!listTypeIsInterface) {
2069 if (!canCoerce(listType, v->object)) {
2070 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2074 } else if (v->value.isScript()) {
2075 if (assignedBinding)
2076 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2078 assignedBinding = true;
2079 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2080 v->type = Value::PropertyBinding;
2082 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2089 // Compiles an assignment to a QDeclarativeScriptString property
2090 bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeParser::Property *prop,
2091 QDeclarativeParser::Object *obj,
2092 const BindingContext &ctxt)
2094 if (prop->values.isMany())
2095 COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2097 if (prop->values.first()->object)
2098 COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2100 prop->scriptStringScope = ctxt.stack;
2101 obj->addScriptStringProperty(prop);
2106 // Compile regular property assignments of the form "property: <value>"
2107 bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeParser::Property *prop,
2108 QDeclarativeParser::Object *obj,
2109 const BindingContext &ctxt)
2111 obj->addValueProperty(prop);
2113 if (prop->values.isMany())
2114 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2116 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2119 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2123 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2128 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2129 Q_ASSERT(v->object);
2130 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2136 // Compile assigning a single object instance to a regular property
2137 bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeParser::Property *prop,
2138 QDeclarativeParser::Object *obj,
2139 QDeclarativeParser::Value *v,
2140 const BindingContext &ctxt)
2142 Q_ASSERT(prop->index != -1);
2143 Q_ASSERT(v->object->type != -1);
2145 if (!obj->metaObject()->property(prop->index).isWritable())
2146 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2148 if (QDeclarativeMetaType::isInterface(prop->type)) {
2150 // Assigning an object to an interface ptr property
2151 COMPILE_CHECK(buildObject(v->object, ctxt));
2153 v->type = Value::CreatedObject;
2155 } else if (prop->type == QMetaType::QVariant) {
2157 // Assigning an object to a QVariant
2158 COMPILE_CHECK(buildObject(v->object, ctxt));
2160 v->type = Value::CreatedObject;
2162 // Normally buildObject() will set this up, but we need the static
2163 // meta object earlier to test for assignability. It doesn't matter
2164 // that there may still be outstanding synthesized meta object changes
2165 // on this type, as they are not relevant for assignability testing
2166 v->object->metatype = output->types.at(v->object->type).metaObject();
2167 Q_ASSERT(v->object->metaObject());
2169 // We want to raw metaObject here as the raw metaobject is the
2170 // actual property type before we applied any extensions that might
2171 // effect the properties on the type, but don't effect assignability
2172 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2174 // Will be true if the assgned type inherits propertyMetaObject
2175 bool isAssignable = false;
2176 // Determine isAssignable value
2177 if (propertyMetaObject) {
2178 const QMetaObject *c = v->object->metatype;
2180 isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject));
2181 c = c->superClass();
2186 // Simple assignment
2187 COMPILE_CHECK(buildObject(v->object, ctxt));
2189 v->type = Value::CreatedObject;
2190 } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) {
2191 // Automatic "Component" insertion
2192 QDeclarativeParser::Object *root = v->object;
2193 QDeclarativeParser::Object *component = pool->New<Object>();
2194 component->type = componentTypeRef();
2195 component->typeName = "Qt/Component";
2196 component->metatype = &QDeclarativeComponent::staticMetaObject;
2197 component->location = root->location;
2198 QDeclarativeParser::Value *componentValue = pool->New<Value>();
2199 componentValue->object = root;
2200 component->getDefaultProperty()->addValue(componentValue);
2201 v->object = component;
2202 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2204 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2211 // Compile assigning a single object instance to a regular property using the "on" syntax.
2215 // NumberAnimation on x { }
2217 bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeParser::Property *prop,
2218 QDeclarativeParser::Object *obj,
2219 QDeclarativeParser::Object *baseObj,
2220 QDeclarativeParser::Value *v,
2221 const BindingContext &ctxt)
2223 Q_ASSERT(prop->index != -1);
2224 Q_ASSERT(v->object->type != -1);
2226 if (!obj->metaObject()->property(prop->index).isWritable())
2227 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2230 // Normally buildObject() will set this up, but we need the static
2231 // meta object earlier to test for assignability. It doesn't matter
2232 // that there may still be outstanding synthesized meta object changes
2233 // on this type, as they are not relevant for assignability testing
2234 v->object->metatype = output->types.at(v->object->type).metaObject();
2235 Q_ASSERT(v->object->metaObject());
2237 // Will be true if the assigned type inherits QDeclarativePropertyValueSource
2238 bool isPropertyValue = false;
2239 // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor
2240 bool isPropertyInterceptor = false;
2241 if (QDeclarativeType *valueType = toQmlType(v->object)) {
2242 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2243 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2246 if (isPropertyValue || isPropertyInterceptor) {
2247 // Assign as a property value source
2248 COMPILE_CHECK(buildObject(v->object, ctxt));
2250 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2251 buildDynamicMeta(baseObj, ForceCreation);
2252 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2254 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(QString::fromUtf8(v->object->typeName)).arg(prop->name().toString()));
2260 // Compile assigning a literal or binding to a regular property
2261 bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeParser::Property *prop,
2262 QDeclarativeParser::Object *obj,
2263 QDeclarativeParser::Value *v,
2264 const BindingContext &ctxt)
2266 Q_ASSERT(prop->index != -1);
2268 if (v->value.isScript()) {
2270 //optimization for <Type>.<EnumValue> enum assignments
2271 if (prop->core.isEnum()) {
2272 bool isEnumAssignment = false;
2273 COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj,
2274 v, &isEnumAssignment));
2275 if (isEnumAssignment) {
2276 v->type = Value::Literal;
2281 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2283 v->type = Value::PropertyBinding;
2287 COMPILE_CHECK(testLiteralAssignment(prop, v));
2289 v->type = Value::Literal;
2295 bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop,
2296 QDeclarativeParser::Object *obj,
2297 QDeclarativeParser::Value *v,
2300 *isAssignment = false;
2301 if (!prop.isEnumType())
2304 if (!prop.isWritable())
2305 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
2307 QString string = v->value.asString();
2308 if (!QDeclarativeUtils::isUpper(string.at(0)))
2311 QStringList parts = string.split(QLatin1Char('.'));
2312 if (parts.count() != 2)
2315 QString typeName = parts.at(0);
2316 QDeclarativeType *type = 0;
2317 unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
2319 //handle enums on value types (where obj->typeName is empty)
2320 QByteArray objTypeName = obj->typeName;
2321 if (objTypeName.isEmpty()) {
2322 QDeclarativeType *objType = toQmlType(obj);
2324 objTypeName = objType->qmlTypeName();
2330 QString enumValue = parts.at(1);
2333 if (objTypeName == type->qmlTypeName()) {
2334 // When these two match, we can short cut the search
2335 if (prop.isFlagType()) {
2336 value = prop.enumerator().keysToValue(enumValue.toUtf8().constData());
2338 value = prop.enumerator().keyToValue(enumValue.toUtf8().constData());
2341 // Otherwise we have to search the whole type
2342 // This matches the logic in QV8TypeWrapper
2343 QByteArray enumName = enumValue.toUtf8();
2344 const QMetaObject *metaObject = type->baseMetaObject();
2345 for (int ii = metaObject->enumeratorCount() - 1; value == -1 && ii >= 0; --ii) {
2346 QMetaEnum e = metaObject->enumerator(ii);
2347 value = e.keyToValue(enumName.constData());
2354 v->type = Value::Literal;
2355 v->value = QDeclarativeParser::Variant((double)value);
2356 *isAssignment = true;
2361 struct StaticQtMetaObject : public QObject
2363 static const QMetaObject *get()
2364 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2367 // Similar logic to above, but not knowing target property.
2368 int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const
2370 int dot = script.indexOf('.');
2372 const QByteArray &scope = script.left(dot);
2373 QDeclarativeType *type = 0;
2374 unit->imports().resolveType(QString::fromUtf8(script.left(dot)), &type, 0, 0, 0, 0);
2375 if (!type && scope != "Qt")
2377 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2378 const char *key = script.constData() + dot+1;
2379 int i = mo->enumeratorCount();
2381 int v = mo->enumerator(i).keyToValue(key);
2389 const QMetaObject *QDeclarativeCompiler::resolveType(const QByteArray& name) const
2391 QDeclarativeType *qmltype = 0;
2392 if (!unit->imports().resolveType(QString::fromUtf8(name), &qmltype, 0, 0, 0, 0))
2396 return qmltype->metaObject();
2399 // similar to logic of completeComponentBuild, but also sticks data
2400 // into primitives at the end
2401 int QDeclarativeCompiler::rewriteBinding(const QString& expression, const QString& name)
2403 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2404 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf('.') + 1));
2406 QString rewrite = rewriteBinding(expression, 0, 0);
2408 return output->indexForString(rewrite);
2411 // Ensures that the dynamic meta specification on obj is valid
2412 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj)
2414 bool seenDefaultProperty = false;
2416 // We use a coarse grain, 31 bit hash to check if there are duplicates.
2417 // Calculating the hash for the names is not a waste as we have to test
2418 // them against the illegalNames set anyway.
2419 QHashField propNames;
2420 QHashField methodNames;
2423 int dpCount = obj->dynamicProperties.count();
2424 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2425 const QDeclarativeParser::Object::DynamicProperty &prop = *p;
2427 if (prop.isDefaultProperty) {
2428 if (seenDefaultProperty)
2429 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2430 seenDefaultProperty = true;
2433 if (propNames.testAndSet(prop.name.hash())) {
2434 for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p;
2435 p2 = obj->dynamicProperties.next(p2)) {
2436 if (p2->name == prop.name)
2437 COMPILE_EXCEPTION(&prop, tr("Duplicate property name"));
2441 if (QDeclarativeUtils::isUpper(prop.name.at(0)))
2442 COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
2444 if (enginePrivate->v8engine()->illegalNames().contains(prop.name))
2445 COMPILE_EXCEPTION(&prop, tr("Illegal property name"));
2448 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2449 const QDeclarativeScript::Object::DynamicSignal &currSig = *s;
2451 if (methodNames.testAndSet(currSig.name.hash())) {
2452 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2453 s2 = obj->dynamicSignals.next(s2)) {
2454 if (s2->name == currSig.name)
2455 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2459 if (currSig.name.at(0).isUpper())
2460 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2461 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2462 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2465 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2466 const QDeclarativeScript::Object::DynamicSlot &currSlot = *s;
2468 if (methodNames.testAndSet(currSlot.name.hash())) {
2469 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2470 s2 = obj->dynamicSignals.next(s2)) {
2471 if (s2->name == currSlot.name)
2472 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2474 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2475 s2 = obj->dynamicSlots.next(s2)) {
2476 if (s2->name == currSlot.name)
2477 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2481 if (currSlot.name.at(0).isUpper())
2482 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2483 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2484 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2490 bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeParser::Object *obj)
2492 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2494 if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2497 Property *property = 0;
2498 if (p->isDefaultProperty) {
2499 property = obj->getDefaultProperty();
2501 property = obj->getProperty(p->name);
2502 if (!property->values.isEmpty())
2503 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2506 if (property->value)
2507 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2509 property->values.append(p->defaultValue->values);
2514 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2516 bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, DynamicMetaMode mode)
2519 Q_ASSERT(obj->metatype);
2521 if (mode != ForceCreation &&
2522 obj->dynamicProperties.isEmpty() &&
2523 obj->dynamicSignals.isEmpty() &&
2524 obj->dynamicSlots.isEmpty())
2527 bool resolveAlias = (mode == ResolveAliases);
2529 const Object::DynamicProperty *defaultProperty = 0;
2532 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2534 if (p->type == Object::DynamicProperty::Alias)
2537 if (p->isDefaultProperty &&
2538 (resolveAlias || p->type != Object::DynamicProperty::Alias))
2539 defaultProperty = p;
2541 if (!resolveAlias) {
2542 // No point doing this for both the alias and non alias cases
2543 QDeclarativePropertyCache::Data *d = property(obj, p->name);
2544 if (d && d->isFinal())
2545 COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2549 bool buildData = resolveAlias || aliasCount == 0;
2551 QByteArray dynamicData;
2553 typedef QDeclarativeVMEMetaData VMD;
2555 dynamicData = QByteArray(sizeof(QDeclarativeVMEMetaData) +
2556 (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) +
2557 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2558 aliasCount * sizeof(VMD::AliasData), 0);
2561 int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1);
2563 QByteArray newClassName = obj->metatype->className();
2564 newClassName.append("_QML_");
2565 newClassName.append(QByteArray::number(uniqueClassId));
2567 if (compileState->root == obj && !compileState->nested) {
2568 QString path = output->url.path();
2569 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2570 if (lastSlash > -1) {
2571 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2572 if (!nameBase.isEmpty() && QDeclarativeUtils::isUpper(nameBase.at(0)))
2573 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId);
2577 QFastMetaBuilder builder;
2578 QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(),
2579 obj->dynamicProperties.count() - (resolveAlias?0:aliasCount),
2580 obj->dynamicSlots.count(),
2581 obj->dynamicSignals.count() + obj->dynamicProperties.count(),
2582 defaultProperty?1:0);
2585 Object::DynamicProperty::Type dtype;
2587 const char *cppType;
2588 } builtinTypes[] = {
2589 { Object::DynamicProperty::Variant, 0, "QVariant" },
2590 { Object::DynamicProperty::Int, QMetaType::Int, "int" },
2591 { Object::DynamicProperty::Bool, QMetaType::Bool, "bool" },
2592 { Object::DynamicProperty::Real, QMetaType::Double, "double" },
2593 { Object::DynamicProperty::String, QMetaType::QString, "QString" },
2594 { Object::DynamicProperty::Url, QMetaType::QUrl, "QUrl" },
2595 { Object::DynamicProperty::Color, QMetaType::QColor, "QColor" },
2596 { Object::DynamicProperty::Time, QMetaType::QTime, "QTime" },
2597 { Object::DynamicProperty::Date, QMetaType::QDate, "QDate" },
2598 { Object::DynamicProperty::DateTime, QMetaType::QDateTime, "QDateTime" },
2600 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2601 QFastMetaBuilder::StringRef typeRefs[builtinTypeCount];
2603 // Reserve dynamic properties
2604 if (obj->dynamicProperties.count()) {
2605 typedef QDeclarativeVMEMetaData VMD;
2607 int effectivePropertyIndex = 0;
2608 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2610 // Reserve space for name
2611 p->nameRef = builder.newString(p->name.utf8length());
2613 int propertyType = 0;
2614 bool readonly = false;
2615 QFastMetaBuilder::StringRef typeRef;
2617 if (p->type == Object::DynamicProperty::Alias) {
2619 } else if (p->type < builtinTypeCount) {
2620 Q_ASSERT(builtinTypes[p->type].dtype == p->type);
2621 propertyType = builtinTypes[p->type].metaType;
2622 if (typeRefs[p->type].isEmpty())
2623 typeRefs[p->type] = builder.newString(strlen(builtinTypes[p->type].cppType));
2624 typeRef = typeRefs[p->type];
2625 if (p->type == Object::DynamicProperty::Variant)
2629 Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
2630 p->type == Object::DynamicProperty::Custom);
2632 // XXX don't double resolve this in the case of an alias run
2634 QByteArray customTypeName;
2635 QDeclarativeType *qmltype = 0;
2637 if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
2638 COMPILE_EXCEPTION(p, tr("Invalid property type"));
2641 QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(QUrl(url));
2643 Q_ASSERT(tdata->isComplete());
2645 QDeclarativeCompiledData *data = tdata->compiledData();
2646 customTypeName = data->root->className();
2650 customTypeName = qmltype->typeName();
2653 if (p->type == Object::DynamicProperty::Custom) {
2654 customTypeName += '*';
2655 propertyType = QMetaType::QObjectStar;
2658 customTypeName = QByteArray("QDeclarativeListProperty<") + customTypeName + QByteArray(">");
2659 propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
2662 p->resolvedCustomTypeName = pool->NewByteArray(customTypeName);
2663 p->typeRef = builder.newString(customTypeName.length());
2664 typeRef = p->typeRef;
2668 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2669 vmd->propertyCount++;
2670 (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType;
2673 if (p->type < builtinTypeCount)
2674 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef, (QMetaType::Type)propertyType,
2675 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2676 effectivePropertyIndex);
2678 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef,
2679 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2680 effectivePropertyIndex);
2682 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2683 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2685 effectivePropertyIndex++;
2690 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2691 if (p->type == Object::DynamicProperty::Alias) {
2693 Q_ASSERT(buildData);
2694 ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++;
2695 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex,
2698 // Even if we aren't resolving the alias, we need a fake signal so that the
2699 // metaobject remains consistent across the resolve and non-resolve alias runs
2700 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2701 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2702 effectivePropertyIndex++;
2709 // Reserve default property
2710 QFastMetaBuilder::StringRef defPropRef;
2711 if (defaultProperty) {
2712 defPropRef = builder.newString(strlen("DefaultProperty"));
2713 builder.setClassInfo(0, defPropRef, defaultProperty->nameRef);
2716 // Reserve dynamic signals
2717 int signalIndex = 0;
2718 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2720 int paramCount = s->parameterNames.count();
2722 int signatureSize = s->name.utf8length() + 2 /* paren */;
2724 if (paramCount) signatureSize += s->parameterTypesLength() + (paramCount - 1) /* commas */;
2725 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1) /* commas */;
2727 s->signatureRef = builder.newString(signatureSize);
2728 if (namesSize) s->parameterNamesRef = builder.newString(namesSize);
2731 ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++;
2733 builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->signatureRef, s->parameterNamesRef);
2737 // Reserve dynamic slots
2738 if (obj->dynamicSlots.count()) {
2740 // Allocate QVariant string
2741 if (typeRefs[0].isEmpty())
2742 typeRefs[0] = builder.newString(strlen(builtinTypes[0].cppType));
2744 typedef QDeclarativeVMEMetaData VMD;
2746 int methodIndex = 0;
2747 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2748 int paramCount = s->parameterNames.count();
2750 int signatureSize = s->name.utf8length() + 2 /* paren */;
2752 if (paramCount) signatureSize += (paramCount * strlen("QVariant") + (paramCount - 1));
2753 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
2755 s->signatureRef = builder.newString(signatureSize);
2756 if (namesSize) s->parameterNamesRef = builder.newString(namesSize);
2758 builder.setMethod(methodIndex, s->signatureRef, s->parameterNamesRef, typeRefs[0]);
2762 funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ +
2763 namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
2764 funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
2765 for (int jj = 0; jj < paramCount; ++jj) {
2766 if (jj) funcScript.append(QLatin1Char(','));
2767 funcScript.append(QLatin1String(s->parameterNames.at(jj)));
2769 funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
2771 VMD::MethodData methodData = { s->parameterNames.count(), 0,
2772 funcScript.length(),
2773 s->location.start.line };
2775 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2778 VMD::MethodData &md = *(vmd->methodData() + methodIndex);
2780 md.bodyOffset = dynamicData.size();
2782 dynamicData.append((const char *)funcScript.constData(),
2783 (funcScript.length() * sizeof(QChar)));
2790 // Now allocate used builtin types
2791 for (int ii = 0; ii < builtinTypeCount; ++ii) {
2792 if (!typeRefs[ii].isEmpty())
2793 typeRefs[ii].load(builtinTypes[ii].cppType);
2796 // Now allocate properties
2797 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2799 char *d = p->changedSignatureRef.data();
2800 p->name.writeUtf8(d);
2801 strcpy(d + p->name.utf8length(), "Changed()");
2803 if (p->type == Object::DynamicProperty::Alias && !resolveAlias)
2806 p->nameRef.load(p->name);
2808 if (p->type >= builtinTypeCount) {
2809 Q_ASSERT(p->resolvedCustomTypeName);
2810 p->typeRef.load(*p->resolvedCustomTypeName);
2814 // Allocate default property if necessary
2815 if (defaultProperty)
2816 strcpy(defPropRef.data(), "DefaultProperty");
2818 // Now allocate signals
2819 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2821 char *d = s->signatureRef.data();
2822 char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data();
2823 s->name.writeUtf8(d); d += s->name.utf8length();
2826 for (int jj = 0; jj < s->parameterNames.count(); ++jj) {
2827 if (jj != 0) { *d++ = ','; *d2++ = ','; }
2828 strcpy(d, s->parameterTypes.at(jj).constData());
2829 d += s->parameterTypes.at(jj).length();
2830 s->parameterNames.at(jj).writeUtf8(d2);
2831 d2 += s->parameterNames.at(jj).utf8length();
2838 // Now allocate methods
2839 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2840 char *d = s->signatureRef.data();
2841 char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data();
2842 s->name.writeUtf8(d); d += s->name.utf8length();
2844 for (int jj = 0; jj < s->parameterNames.count(); ++jj) {
2845 if (jj != 0) { *d++ = ','; *d2++ = ','; }
2846 strcpy(d, "QVariant");
2847 d += strlen("QVariant");
2848 strcpy(d2, s->parameterNames.at(jj).constData());
2849 d2 += s->parameterNames.at(jj).length();
2856 // Now allocate class name
2857 classNameRef.load(newClassName);
2859 obj->metadata = builder.toData();
2860 builder.fromData(&obj->extObject, obj->metatype, obj->metadata);
2862 if (mode == IgnoreAliases && aliasCount)
2863 compileState->aliasingObjects.append(obj);
2865 obj->synthdata = dynamicData;
2867 if (obj->synthCache) {
2868 obj->synthCache->release();
2869 obj->synthCache = 0;
2872 if (obj->type != -1) {
2873 QDeclarativePropertyCache *cache = output->types[obj->type].createPropertyCache(engine)->copy();
2874 cache->append(engine, &obj->extObject, QDeclarativePropertyCache::Data::NoFlags,
2875 QDeclarativePropertyCache::Data::IsVMEFunction,
2876 QDeclarativePropertyCache::Data::IsVMESignal);
2877 obj->synthCache = cache;
2883 bool QDeclarativeCompiler::checkValidId(QDeclarativeParser::Value *v, const QString &val)
2886 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
2888 QChar ch = val.at(0);
2889 if (QDeclarativeUtils::isLetter(ch) && !QDeclarativeUtils::isLower(ch))
2890 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
2892 QChar u(QLatin1Char('_'));
2893 if (!QDeclarativeUtils::isLetter(ch) && ch != u)
2894 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
2896 for (int ii = 1; ii < val.count(); ++ii) {
2898 if (!QDeclarativeUtils::isLetterOrNumber(ch) && ch != u)
2899 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
2902 if (enginePrivate->v8engine()->illegalNames().contains(val))
2903 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
2908 #include <qdeclarativejsparser_p.h>
2910 static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node)
2912 if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) {
2914 static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name.toString();
2915 return QStringList() << name;
2916 } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) {
2917 QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node);
2919 QStringList rv = astNodeToStringList(expr->base);
2922 rv.append(expr->name.toString());
2925 return QStringList();
2928 bool QDeclarativeCompiler::compileAlias(QFastMetaBuilder &builder,
2930 QDeclarativeParser::Object *obj,
2931 int propIndex, int aliasIndex,
2932 Object::DynamicProperty &prop)
2934 if (!prop.defaultValue)
2935 COMPILE_EXCEPTION(obj, tr("No property alias location"));
2937 if (!prop.defaultValue->values.isOne() ||
2938 prop.defaultValue->values.first()->object ||
2939 !prop.defaultValue->values.first()->value.isScript())
2940 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2942 QDeclarativeJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST();
2944 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
2946 QStringList alias = astNodeToStringList(node);
2948 if (alias.count() < 1 || alias.count() > 3)
2949 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
2951 QDeclarativeParser::Object *idObject = compileState->ids.value(alias.at(0));
2953 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
2955 QByteArray typeName;
2960 bool writable = false;
2961 bool resettable = false;
2962 if (alias.count() == 2 || alias.count() == 3) {
2963 propIdx = indexOfProperty(idObject, alias.at(1));
2965 if (-1 == propIdx) {
2966 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2967 } else if (propIdx > 0xFFFF) {
2968 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
2971 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
2972 if (!aliasProperty.isScriptable())
2973 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2975 writable = aliasProperty.isWritable();
2976 resettable = aliasProperty.isResettable();
2978 if (aliasProperty.type() < QVariant::UserType)
2979 type = aliasProperty.type();
2981 if (alias.count() == 3) {
2982 QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
2984 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2986 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
2988 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
2989 if (valueTypeIndex == -1)
2990 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2991 Q_ASSERT(valueTypeIndex <= 0xFF);
2993 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
2994 propIdx |= (valueTypeIndex << 16);
2997 if (aliasProperty.isEnumType())
2998 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
3000 typeName = aliasProperty.typeName();
3002 Q_ASSERT(idObject->type != -1); // How else did it get an id?
3004 const QDeclarativeCompiledData::TypeReference &ref = output->types.at(idObject->type);
3006 typeName = ref.type->typeName();
3008 typeName = ref.component->root->className();
3013 if (typeName.endsWith('*'))
3014 flags |= QML_ALIAS_FLAG_PTR;
3016 QDeclarativeVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags };
3018 typedef QDeclarativeVMEMetaData VMD;
3019 VMD *vmd = (QDeclarativeVMEMetaData *)data.data();
3020 *(vmd->aliasData() + aliasIndex) = aliasData;
3022 prop.nameRef = builder.newString(prop.name.utf8length());
3023 prop.resolvedCustomTypeName = pool->NewByteArray(typeName);
3024 prop.typeRef = builder.newString(typeName.length());
3026 builder.setProperty(propIndex, prop.nameRef, prop.typeRef, (QMetaType::Type)type,
3027 (QFastMetaBuilder::PropertyFlag)(writable?int(QFastMetaBuilder::Writable):0),
3033 bool QDeclarativeCompiler::buildBinding(QDeclarativeParser::Value *value,
3034 QDeclarativeParser::Property *prop,
3035 const BindingContext &ctxt)
3037 Q_ASSERT(prop->index != -1);
3038 Q_ASSERT(prop->parent);
3039 Q_ASSERT(prop->parent->metaObject());
3041 if (!prop->core.isWritable() && !prop->core.isQList())
3042 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3044 BindingReference *reference = pool->New<BindingReference>();
3045 reference->expression = value->value;
3046 reference->property = prop;
3047 reference->value = value;
3048 reference->bindingContext = ctxt;
3049 addBindingReference(reference);
3054 void QDeclarativeCompiler::genBindingAssignment(QDeclarativeParser::Value *binding,
3055 QDeclarativeParser::Property *prop,
3056 QDeclarativeParser::Object *obj,
3057 QDeclarativeParser::Property *valueTypeProperty)
3060 Q_ASSERT(binding->bindingReference);
3062 const BindingReference &ref = *binding->bindingReference;
3063 if (ref.dataType == BindingReference::V4) {
3064 QDeclarativeInstruction store;
3065 store.setType(QDeclarativeInstruction::StoreV4Binding);
3066 store.assignBinding.value = ref.compiledIndex;
3067 store.assignBinding.context = ref.bindingContext.stack;
3068 store.assignBinding.owner = ref.bindingContext.owner;
3069 if (valueTypeProperty)
3070 store.assignBinding.property = (valueTypeProperty->index & 0xFFFF) |
3071 ((valueTypeProperty->type & 0xFF)) << 16 |
3072 ((prop->index & 0xFF) << 24);
3074 store.assignBinding.property = prop->index;
3075 store.assignBinding.line = binding->location.start.line;
3076 output->addInstruction(store);
3077 } else if (ref.dataType == BindingReference::V8) {
3078 QDeclarativeInstruction store;
3079 store.setType(QDeclarativeInstruction::StoreV8Binding);
3080 store.assignBinding.value = ref.compiledIndex;
3081 store.assignBinding.context = ref.bindingContext.stack;
3082 store.assignBinding.owner = ref.bindingContext.owner;
3083 store.assignBinding.line = binding->location.start.line;
3085 Q_ASSERT(ref.bindingContext.owner == 0 ||
3086 (ref.bindingContext.owner != 0 && valueTypeProperty));
3087 if (ref.bindingContext.owner) {
3088 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
3090 store.assignBinding.property = genPropertyData(prop);
3093 output->addInstruction(store);
3095 QDeclarativeInstruction store;
3097 store.setType(QDeclarativeInstruction::StoreBinding);
3099 store.setType(QDeclarativeInstruction::StoreBindingOnAlias);
3100 store.assignBinding.value = output->indexForString(ref.rewrittenExpression);
3101 store.assignBinding.context = ref.bindingContext.stack;
3102 store.assignBinding.owner = ref.bindingContext.owner;
3103 store.assignBinding.line = binding->location.start.line;
3105 Q_ASSERT(ref.bindingContext.owner == 0 ||
3106 (ref.bindingContext.owner != 0 && valueTypeProperty));
3107 if (ref.bindingContext.owner) {
3108 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
3110 store.assignBinding.property = genPropertyData(prop);
3112 output->addInstruction(store);
3116 int QDeclarativeCompiler::genContextCache()
3118 if (compileState->ids.count() == 0)
3121 QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache();
3122 cache->reserve(compileState->ids.count());
3123 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
3124 cache->add(o->id, o->idIndex);
3126 output->contextCaches.append(cache);
3127 return output->contextCaches.count() - 1;
3130 int QDeclarativeCompiler::genValueTypeData(QDeclarativeParser::Property *valueTypeProp,
3131 QDeclarativeParser::Property *prop)
3133 typedef QDeclarativePropertyPrivate QDPP;
3134 QByteArray data = QDPP::saveValueType(prop->parent->metaObject(), prop->index,
3135 enginePrivate->valueTypes[prop->type]->metaObject(),
3136 valueTypeProp->index, engine);
3138 return output->indexForByteArray(data);
3141 int QDeclarativeCompiler::genPropertyData(QDeclarativeParser::Property *prop)
3143 typedef QDeclarativePropertyPrivate QDPP;
3144 QByteArray data = QDPP::saveProperty(prop->parent->metaObject(), prop->index, engine);
3146 return output->indexForByteArray(data);
3149 bool QDeclarativeCompiler::completeComponentBuild()
3152 componentStats->componentStat.ids = compileState->ids.count();
3154 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
3155 aliasObject = compileState->aliasingObjects.next(aliasObject))
3156 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
3158 QDeclarativeV4Compiler::Expression expr(unit->imports());
3159 expr.component = compileState->root;
3160 expr.ids = &compileState->ids;
3161 expr.importCache = output->importCache;
3163 QDeclarativeV4Compiler bindingCompiler;
3165 QList<BindingReference*> sharedBindings;
3167 for (BindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3169 BindingReference &binding = *b;
3171 // ### We don't currently optimize for bindings on alias's - because
3172 // of the solution to QTBUG-13719
3173 if (!binding.property->isAlias) {
3174 expr.context = binding.bindingContext.object;
3175 expr.property = binding.property;
3176 expr.expression = binding.expression;
3178 int index = bindingCompiler.compile(expr, enginePrivate);
3180 binding.dataType = BindingReference::V4;
3181 binding.compiledIndex = index;
3183 componentStats->componentStat.optimizedBindings.append(b->value->location);
3188 // Pre-rewrite the expression
3189 QString expression = binding.expression.asScript();
3191 QDeclarativeRewrite::RewriteBinding rewriteBinding;
3192 rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3193 bool isSharable = false;
3194 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3196 if (isSharable && !binding.property->isAlias /* See above re alias */ &&
3197 binding.property->type != qMetaTypeId<QDeclarativeBinding*>()) {
3198 binding.dataType = BindingReference::V8;
3199 sharedBindings.append(b);
3201 binding.dataType = BindingReference::QtScript;
3205 componentStats->componentStat.scriptBindings.append(b->value->location);
3208 if (!sharedBindings.isEmpty()) {
3210 static bool lt(const BindingReference *lhs, const BindingReference *rhs)
3212 return lhs->value->location.start.line < rhs->value->location.start.line;
3216 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3218 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3219 int lineNumber = startLineNumber;
3221 QString functionArray(QLatin1String("["));
3222 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3223 BindingReference *reference = sharedBindings.at(ii);
3224 QDeclarativeParser::Value *value = reference->value;
3225 const QString &expression = reference->rewrittenExpression;
3227 if (ii != 0) functionArray += QLatin1String(",");
3229 while (lineNumber < value->location.start.line) {
3231 functionArray += QLatin1String("\n");
3234 functionArray += expression;
3235 reference->compiledIndex = ii;
3237 functionArray += QLatin1String("]");
3239 compileState->v8BindingProgram = functionArray;
3240 compileState->v8BindingProgramLine = startLineNumber;
3241 compileState->v8BindingProgramIndex = output->v8bindings.count();
3242 output->v8bindings.append(v8::Persistent<v8::Array>());
3245 if (bindingCompiler.isValid())
3246 compileState->compiledBindingData = bindingCompiler.program();
3248 saveComponentState();
3253 void QDeclarativeCompiler::dumpStats()
3255 Q_ASSERT(componentStats);
3256 qWarning().nospace() << "QML Document: " << output->url.toString();
3257 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3258 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3259 qWarning().nospace() << " Component Line " << stat.lineNumber;
3260 qWarning().nospace() << " Total Objects: " << stat.objects;
3261 qWarning().nospace() << " IDs Used: " << stat.ids;
3262 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3266 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3267 if (0 == (ii % 10)) {
3268 if (ii) output.append("\n");
3273 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3275 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3276 output.append(") ");
3278 if (!output.isEmpty())
3279 qWarning().nospace() << output.constData();
3282 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3285 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3286 if (0 == (ii % 10)) {
3287 if (ii) output.append("\n");
3292 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3294 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3295 output.append(") ");
3297 if (!output.isEmpty())
3298 qWarning().nospace() << output.constData();
3304 Returns true if from can be assigned to a (QObject) property of type
3307 bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeParser::Object *from)
3309 const QMetaObject *toMo =
3310 enginePrivate->rawMetaObjectForType(to);
3311 const QMetaObject *fromMo = from->metaObject();
3314 if (QDeclarativePropertyPrivate::equal(fromMo, toMo))
3316 fromMo = fromMo->superClass();
3322 Returns the element name, as written in the QML file, for o.
3324 QString QDeclarativeCompiler::elementName(QDeclarativeParser::Object *o)
3327 if (o->type != -1) {
3328 return output->types.at(o->type).className;
3334 QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeParser::Object *from)
3337 const QMetaObject *mo = from->metatype;
3338 QDeclarativeType *type = 0;
3339 while (!type && mo) {
3340 type = QDeclarativeMetaType::qmlType(mo);
3341 mo = mo->superClass();
3346 QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeParser::Object *obj)
3348 const QMetaObject *mo = obj->metatype;
3350 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3352 return QStringList();
3354 QMetaClassInfo classInfo = mo->classInfo(idx);
3355 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3359 QDeclarativePropertyCache::Data *
3360 QDeclarativeCompiler::property(QDeclarativeParser::Object *object, int index)
3362 QDeclarativePropertyCache *cache = 0;
3364 if (object->synthCache)
3365 cache = object->synthCache;
3366 else if (object->type != -1)
3367 cache = output->types[object->type].createPropertyCache(engine);
3369 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3371 return cache->property(index);
3374 QDeclarativePropertyCache::Data *
3375 QDeclarativeCompiler::property(QDeclarativeParser::Object *object, const QHashedStringRef &name, bool *notInRevision)
3377 if (notInRevision) *notInRevision = false;
3379 QDeclarativePropertyCache *cache = 0;
3381 if (object->synthCache)
3382 cache = object->synthCache;
3383 else if (object->type != -1)
3384 cache = output->types[object->type].createPropertyCache(engine);
3386 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3388 QDeclarativePropertyCache::Data *d = cache->property(name);
3390 // Find the first property
3391 while (d && d->isFunction())
3392 d = cache->overrideData(d);
3394 if (d && !cache->isAllowedInRevision(d)) {
3395 if (notInRevision) *notInRevision = true;
3402 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3403 QDeclarativePropertyCache::Data *
3404 QDeclarativeCompiler::signal(QDeclarativeParser::Object *object, const QHashedStringRef &name, bool *notInRevision)
3406 if (notInRevision) *notInRevision = false;
3408 QDeclarativePropertyCache *cache = 0;
3410 if (object->synthCache)
3411 cache = object->synthCache;
3412 else if (object->type != -1)
3413 cache = output->types[object->type].createPropertyCache(engine);
3415 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3418 QDeclarativePropertyCache::Data *d = cache->property(name);
3419 if (notInRevision) *notInRevision = false;
3421 while (d && !(d->isFunction()))
3422 d = cache->overrideData(d);
3424 if (d && !cache->isAllowedInRevision(d)) {
3425 if (notInRevision) *notInRevision = true;
3431 if (name.endsWith(Changed_string)) {
3432 QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3434 d = property(object, propName, notInRevision);
3436 return cache->method(d->notifyIndex);
3442 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3443 int QDeclarativeCompiler::indexOfSignal(QDeclarativeParser::Object *object, const QString &name,
3444 bool *notInRevision)
3446 QDeclarativePropertyCache::Data *d = signal(object, QStringRef(&name), notInRevision);
3447 return d?d->coreIndex:-1;
3450 int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QString &name,
3451 bool *notInRevision)
3453 return indexOfProperty(object, QStringRef(&name), notInRevision);
3456 int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QHashedStringRef &name,
3457 bool *notInRevision)
3459 QDeclarativePropertyCache::Data *d = property(object, name, notInRevision);
3460 return d?d->coreIndex:-1;