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 const QMetaObject *metaObject = obj->metaObject();
850 Q_ASSERT(metaObject);
851 QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
853 Property *explicitProperty = obj->getProperty(QString::fromUtf8(p.name()), false);
854 if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) {
856 skipProperty = explicitProperty; // We merge the values into defaultProperty
858 // Find the correct insertion point
859 Value *insertPos = 0;
861 for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) {
862 if (!(v->location.start < explicitProperty->values.first()->location.start))
867 defaultProperty->values.insertAfter(insertPos, explicitProperty->values);
873 QDeclarativeCustomParser *cp = 0;
875 cp = output->types.at(obj->type).type->customParser();
877 // Build all explicit properties specified
878 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
880 if (prop == skipProperty)
882 if (prop->name() == id_string)
885 bool canDefer = false;
886 if (isCustomParser) {
887 if (doesPropertyExist(prop, obj) &&
888 (!(cp->flags() & QDeclarativeCustomParser::AcceptsAttachedProperties) ||
889 !isAttachedPropertyName(prop->name()))) {
890 int ids = compileState->ids.count();
891 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
892 canDefer = ids == compileState->ids.count();
893 } else if (isSignalPropertyName(prop->name()) &&
894 (cp->flags() & QDeclarativeCustomParser::AcceptsSignalHandlers)) {
895 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
897 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
900 if (isSignalPropertyName(prop->name())) {
901 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
903 int ids = compileState->ids.count();
904 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
905 canDefer = ids == compileState->ids.count();
909 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
910 prop->isDeferred = true;
914 // Build the default property
915 if (defaultProperty) {
916 Property *prop = defaultProperty;
918 bool canDefer = false;
919 if (isCustomParser) {
920 if (doesPropertyExist(prop, obj)) {
921 int ids = compileState->ids.count();
922 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
923 canDefer = ids == compileState->ids.count();
925 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
928 int ids = compileState->ids.count();
929 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
930 canDefer = ids == compileState->ids.count();
933 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
934 prop->isDeferred = true;
937 // Compile custom parser parts
938 if (isCustomParser && !customProps.isEmpty()) {
942 obj->custom = cp->compile(customProps);
945 foreach (QDeclarativeError err, cp->errors()) {
946 err.setUrl(output->url);
954 void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj)
956 QDeclarativeCompiledData::TypeReference &tr = output->types[obj->type];
957 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
963 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
964 !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) {
966 QDeclarativeInstruction create;
967 create.setType(QDeclarativeInstruction::CreateSimpleObject);
968 create.createSimple.create = output->types.at(obj->type).type->createFunction();
969 create.createSimple.typeSize = output->types.at(obj->type).type->createSize();
970 create.createSimple.type = obj->type;
971 create.createSimple.line = obj->location.start.line;
972 create.createSimple.column = obj->location.start.column;
973 output->addInstruction(create);
977 QDeclarativeInstruction create;
978 create.setType(QDeclarativeInstruction::CreateObject);
979 create.create.line = obj->location.start.line;
980 create.create.column = obj->location.start.column;
981 create.create.data = -1;
982 if (!obj->custom.isEmpty())
983 create.create.data = output->indexForByteArray(obj->custom);
984 create.create.type = obj->type;
985 if (!output->types.at(create.create.type).type &&
986 !obj->bindingBitmask.isEmpty()) {
987 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
988 create.create.bindingBits =
989 output->indexForByteArray(obj->bindingBitmask);
991 create.create.bindingBits = -1;
993 output->addInstruction(create);
997 // Setup the synthesized meta object if necessary
998 if (!obj->metadata.isEmpty()) {
999 QDeclarativeInstruction meta;
1000 meta.setType(QDeclarativeInstruction::StoreMetaObject);
1001 meta.storeMeta.data = output->indexForByteArray(obj->metadata);
1002 meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata);
1003 meta.storeMeta.propertyCache = output->propertyCaches.count();
1005 QDeclarativePropertyCache *propertyCache = obj->synthCache;
1006 Q_ASSERT(propertyCache);
1007 propertyCache->addref();
1009 // Add flag for alias properties
1010 if (!obj->synthdata.isEmpty()) {
1011 const QDeclarativeVMEMetaData *vmeMetaData =
1012 reinterpret_cast<const QDeclarativeVMEMetaData *>(obj->synthdata.constData());
1013 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
1014 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
1015 QDeclarativePropertyCache::Data *data = propertyCache->property(index);
1016 data->setFlags(data->getFlags() | QDeclarativePropertyCache::Data::IsAlias);
1020 if (obj == unitRoot) {
1021 propertyCache->addref();
1022 output->rootPropertyCache = propertyCache;
1025 output->propertyCaches << propertyCache;
1026 output->addInstruction(meta);
1027 } else if (obj == unitRoot) {
1028 output->rootPropertyCache = tr.createPropertyCache(engine);
1029 output->rootPropertyCache->addref();
1032 // Set the object id
1033 if (!obj->id.isEmpty()) {
1034 QDeclarativeInstruction id;
1035 id.setType(QDeclarativeInstruction::SetId);
1036 id.setId.value = output->indexForString(obj->id);
1037 id.setId.index = obj->idIndex;
1038 output->addInstruction(id);
1042 if (tr.type && obj->parserStatusCast != -1) {
1043 QDeclarativeInstruction begin;
1044 begin.setType(QDeclarativeInstruction::BeginObject);
1045 begin.begin.castValue = obj->parserStatusCast;
1046 output->addInstruction(begin);
1052 void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj)
1054 for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1055 Q_ASSERT(prop->scriptStringScope != -1);
1056 const QString &script = prop->values.first()->value.asScript();
1057 QDeclarativeInstruction ss;
1058 ss.setType(QDeclarativeInstruction::StoreScriptString);
1059 ss.storeScriptString.propertyIndex = prop->index;
1060 ss.storeScriptString.value = output->indexForString(script);
1061 ss.storeScriptString.scope = prop->scriptStringScope;
1062 // ss.storeScriptString.bindingId = rewriteBinding(script, prop->name());
1063 ss.storeScriptString.bindingId = rewriteBinding(script, QString()); // XXX
1064 ss.storeScriptString.line = prop->location.start.line;
1065 output->addInstruction(ss);
1068 bool seenDefer = false;
1069 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1070 if (prop->isDeferred) {
1075 genValueProperty(prop, obj);
1078 QDeclarativeInstruction defer;
1079 defer.setType(QDeclarativeInstruction::Defer);
1080 defer.defer.deferCount = 0;
1081 int deferIdx = output->addInstruction(defer);
1082 int nextInstructionIndex = output->nextInstructionIndex();
1084 QDeclarativeInstruction init;
1085 init.setType(QDeclarativeInstruction::Init);
1086 init.init.bindingsSize = compileState->bindings.count(); // XXX - bigger than necessary
1087 init.init.parserStatusSize = compileState->parserStatusCount; // XXX - bigger than necessary
1088 init.init.contextCache = -1;
1089 init.init.compiledBinding = -1;
1090 output->addInstruction(init);
1092 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1093 if (!prop->isDeferred)
1095 genValueProperty(prop, obj);
1098 QDeclarativeInstruction done;
1099 done.setType(QDeclarativeInstruction::Done);
1100 output->addInstruction(done);
1102 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1105 for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1107 QDeclarativeParser::Value *v = prop->values.first();
1109 if (v->type == Value::SignalObject) {
1111 genObject(v->object);
1113 QDeclarativeInstruction assign;
1114 assign.setType(QDeclarativeInstruction::AssignSignalObject);
1115 assign.assignSignalObject.line = v->location.start.line;
1116 assign.assignSignalObject.signal = output->indexForString(prop->name().toString());
1117 output->addInstruction(assign);
1119 } else if (v->type == Value::SignalExpression) {
1121 QDeclarativeInstruction store;
1122 store.setType(QDeclarativeInstruction::StoreSignal);
1123 store.storeSignal.signalIndex = prop->index;
1124 store.storeSignal.value =
1125 output->indexForString(v->value.asScript().trimmed());
1126 store.storeSignal.context = v->signalExpressionContextStack;
1127 store.storeSignal.name = output->indexForByteArray(prop->name().toUtf8());
1128 store.storeSignal.line = v->location.start.line;
1129 output->addInstruction(store);
1135 for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1136 QDeclarativeInstruction fetch;
1137 fetch.setType(QDeclarativeInstruction::FetchAttached);
1138 fetch.fetchAttached.id = prop->index;
1139 fetch.fetchAttached.line = prop->location.start.line;
1140 output->addInstruction(fetch);
1142 genObjectBody(prop->value);
1144 QDeclarativeInstruction pop;
1145 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1146 output->addInstruction(pop);
1149 for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1150 QDeclarativeInstruction fetch;
1151 fetch.setType(QDeclarativeInstruction::FetchObject);
1152 fetch.fetch.property = prop->index;
1153 fetch.fetch.line = prop->location.start.line;
1154 output->addInstruction(fetch);
1156 if (!prop->value->metadata.isEmpty()) {
1157 QDeclarativeInstruction meta;
1158 meta.setType(QDeclarativeInstruction::StoreMetaObject);
1159 meta.storeMeta.data = output->indexForByteArray(prop->value->metadata);
1160 meta.storeMeta.aliasData = output->indexForByteArray(prop->value->synthdata);
1161 meta.storeMeta.propertyCache = -1;
1162 output->addInstruction(meta);
1165 genObjectBody(prop->value);
1167 QDeclarativeInstruction pop;
1168 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1169 output->addInstruction(pop);
1172 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1174 genValueTypeProperty(obj, prop);
1177 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1178 if (prop->isDeferred)
1181 genValueProperty(prop, obj);
1184 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1186 genValueTypeProperty(obj, prop);
1190 void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeParser::Object *obj,QDeclarativeParser::Property *prop)
1192 QDeclarativeInstruction fetch;
1193 fetch.setType(QDeclarativeInstruction::FetchValueType);
1194 fetch.fetchValue.property = prop->index;
1195 fetch.fetchValue.type = prop->type;
1196 fetch.fetchValue.bindingSkipList = 0;
1198 if (obj->type == -1 || output->types.at(obj->type).component) {
1199 // We only have to do this if this is a composite type. If it is a builtin
1200 // type it can't possibly already have bindings that need to be cleared.
1201 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1202 if (!vprop->values.isEmpty()) {
1203 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1204 fetch.fetchValue.bindingSkipList |= (1 << vprop->index);
1209 output->addInstruction(fetch);
1211 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1212 genPropertyAssignment(vprop, prop->value, prop);
1215 QDeclarativeInstruction pop;
1216 pop.setType(QDeclarativeInstruction::PopValueType);
1217 pop.fetchValue.property = prop->index;
1218 pop.fetchValue.type = prop->type;
1219 pop.fetchValue.bindingSkipList = 0;
1220 output->addInstruction(pop);
1223 void QDeclarativeCompiler::genComponent(QDeclarativeParser::Object *obj)
1225 QDeclarativeParser::Object *root = obj->defaultProperty->values.first()->object;
1228 QDeclarativeInstruction create;
1229 create.setType(QDeclarativeInstruction::CreateComponent);
1230 create.createComponent.line = root->location.start.line;
1231 create.createComponent.column = root->location.start.column;
1232 create.createComponent.endLine = root->location.end.line;
1233 int createInstruction = output->addInstruction(create);
1234 int nextInstructionIndex = output->nextInstructionIndex();
1236 ComponentCompileState *oldCompileState = compileState;
1237 compileState = componentState(root);
1239 QDeclarativeInstruction init;
1240 init.setType(QDeclarativeInstruction::Init);
1241 init.init.bindingsSize = compileState->bindings.count();
1242 init.init.parserStatusSize = compileState->parserStatusCount;
1243 init.init.contextCache = genContextCache();
1244 if (compileState->compiledBindingData.isEmpty())
1245 init.init.compiledBinding = -1;
1247 init.init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
1248 output->addInstruction(init);
1250 if (!compileState->v8BindingProgram.isEmpty()) {
1251 QDeclarativeInstruction bindings;
1252 bindings.setType(QDeclarativeInstruction::InitV8Bindings);
1253 bindings.initV8Bindings.program = output->indexForString(compileState->v8BindingProgram);
1254 bindings.initV8Bindings.programIndex = compileState->v8BindingProgramIndex;
1255 bindings.initV8Bindings.line = compileState->v8BindingProgramLine;
1256 output->addInstruction(bindings);
1261 QDeclarativeInstruction def;
1262 def.setType(QDeclarativeInstruction::SetDefault);
1263 output->addInstruction(def);
1265 QDeclarativeInstruction done;
1266 done.setType(QDeclarativeInstruction::Done);
1267 output->addInstruction(done);
1269 output->instruction(createInstruction)->createComponent.count =
1270 output->nextInstructionIndex() - nextInstructionIndex;
1272 compileState = oldCompileState;
1274 if (!obj->id.isEmpty()) {
1275 QDeclarativeInstruction id;
1276 id.setType(QDeclarativeInstruction::SetId);
1277 id.setId.value = output->indexForString(obj->id);
1278 id.setId.index = obj->idIndex;
1279 output->addInstruction(id);
1282 if (obj == unitRoot) {
1283 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1284 output->rootPropertyCache->addref();
1288 bool QDeclarativeCompiler::buildComponent(QDeclarativeParser::Object *obj,
1289 const BindingContext &ctxt)
1291 // The special "Component" element can only have the id property and a
1292 // default property, that actually defines the component's tree
1294 // Find, check and set the "id" property (if any)
1295 Property *idProp = 0;
1296 if (obj->properties.isMany() ||
1297 (obj->properties.isOne() && obj->properties.first()->name() != id_string))
1298 COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
1300 if (!obj->properties.isEmpty())
1301 idProp = obj->properties.first();
1304 if (idProp->value || idProp->values.isMany() || idProp->values.first()->object)
1305 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1306 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1308 QString idVal = idProp->values.first()->primitive();
1310 if (compileState->ids.value(idVal))
1311 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1317 // Check the Component tree is well formed
1318 if (obj->defaultProperty &&
1319 (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
1320 (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
1321 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1323 if (!obj->dynamicProperties.isEmpty())
1324 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1325 if (!obj->dynamicSignals.isEmpty())
1326 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1327 if (!obj->dynamicSlots.isEmpty())
1328 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1330 QDeclarativeParser::Object *root = 0;
1331 if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
1332 root = obj->defaultProperty->values.first()->object;
1335 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1337 // Build the component tree
1338 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1343 bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeParser::Object *obj,
1344 const BindingContext &ctxt)
1346 ComponentCompileState *oldComponentCompileState = compileState;
1347 compileState = pool->New<ComponentCompileState>();
1348 compileState->root = obj;
1349 compileState->nested = true;
1351 if (componentStats) {
1352 ComponentStat oldComponentStat = componentStats->componentStat;
1354 componentStats->componentStat = ComponentStat();
1355 componentStats->componentStat.lineNumber = obj->location.start.line;
1358 COMPILE_CHECK(buildObject(obj, ctxt));
1360 COMPILE_CHECK(completeComponentBuild());
1362 componentStats->componentStat = oldComponentStat;
1365 COMPILE_CHECK(buildObject(obj, ctxt));
1367 COMPILE_CHECK(completeComponentBuild());
1370 compileState = oldComponentCompileState;
1376 // Build a sub-object. A sub-object is one that was not created directly by
1377 // QML - such as a grouped property object, or an attached object. Sub-object's
1378 // can't have an id, involve a custom parser, have attached properties etc.
1379 bool QDeclarativeCompiler::buildSubObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
1381 Q_ASSERT(obj->metatype);
1382 Q_ASSERT(!obj->defaultProperty);
1383 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1386 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1387 if (isSignalPropertyName(prop->name())) {
1388 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1390 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1397 int QDeclarativeCompiler::componentTypeRef()
1399 QDeclarativeType *t = QDeclarativeMetaType::qmlType("QtQuick/Component",2,0);
1400 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1401 if (output->types.at(ii).type == t)
1404 QDeclarativeCompiledData::TypeReference ref;
1405 ref.className = Component_string;
1407 output->types << ref;
1408 return output->types.count() - 1;
1411 bool QDeclarativeCompiler::buildSignal(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj,
1412 const BindingContext &ctxt)
1414 Q_ASSERT(obj->metaObject());
1416 const QHashedStringRef &propName = prop->name();
1418 Q_ASSERT(propName.startsWith(on_string));
1419 QString name = propName.mid(2, -1).toString();
1421 // Note that the property name could start with any alpha or '_' or '$' character,
1422 // so we need to do the lower-casing of the first alpha character.
1423 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1424 if (QDeclarativeUtils::isUpper(name.at(firstAlphaIndex))) {
1425 name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1430 bool notInRevision = false;
1432 QDeclarativePropertyCache::Data *sig = signal(obj, QStringRef(&name), ¬InRevision);
1436 if (notInRevision && 0 == property(obj, propName, 0)) {
1437 Q_ASSERT(obj->type != -1);
1438 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1439 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1441 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(elementName(obj)).arg(prop->name().toString()).arg(QString::fromUtf8(type.type->module())).arg(type.majorVersion).arg(type.minorVersion));
1443 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1447 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1449 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1453 if (prop->value || !prop->values.isOne())
1454 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1456 prop->index = sig->coreIndex;
1459 obj->addSignalProperty(prop);
1461 if (prop->values.first()->object) {
1462 COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1463 prop->values.first()->type = Value::SignalObject;
1465 prop->values.first()->type = Value::SignalExpression;
1467 if (!prop->values.first()->value.isScript())
1468 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1470 QString script = prop->values.first()->value.asScript().trimmed();
1471 if (script.isEmpty())
1472 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1474 prop->values.first()->signalExpressionContextStack = ctxt.stack;
1483 Returns true if (value) property \a prop exists on obj, false otherwise.
1485 bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeParser::Property *prop,
1486 QDeclarativeParser::Object *obj)
1488 if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1491 if (prop->isDefault) {
1492 const QMetaObject *mo = obj->metaObject();
1493 QMetaProperty p = QDeclarativeMetaType::defaultProperty(mo);
1494 return p.name() != 0;
1496 return property(obj, prop->name()) != 0;
1500 bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop,
1501 QDeclarativeParser::Object *obj,
1502 const BindingContext &ctxt)
1504 if (prop->isEmpty())
1505 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1507 const QMetaObject *metaObject = obj->metaObject();
1508 Q_ASSERT(metaObject);
1510 if (isAttachedPropertyName(prop->name())) {
1511 // Setup attached property data
1513 if (ctxt.isSubContext()) {
1514 // Attached properties cannot be used on sub-objects. Sub-objects
1515 // always exist in a binding sub-context, which is what we test
1517 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1520 QDeclarativeType *type = 0;
1521 QDeclarativeImportedNamespace *typeNamespace = 0;
1522 unit->imports().resolveType(prop->name().toUtf8(), &type, 0, 0, 0, &typeNamespace);
1524 if (typeNamespace) {
1525 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1528 } else if (!type || !type->attachedPropertiesType()) {
1529 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1533 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1535 Q_ASSERT(type->attachedPropertiesFunction());
1536 prop->index = type->attachedPropertiesId();
1537 prop->value->metatype = type->attachedPropertiesType();
1539 // Setup regular property data
1541 if (prop->isDefault) {
1542 QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
1545 prop->setName(QString::fromLatin1(p.name()));
1547 QDeclarativePropertyCache::Data *d = property(obj, p.propertyIndex());
1548 prop->index = d->coreIndex;
1553 bool notInRevision = false;
1554 QDeclarativePropertyCache::Data *d = property(obj, prop->name(), ¬InRevision);
1556 if (d == 0 && notInRevision) {
1557 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1558 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1560 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(elementName(obj)).arg(prop->name().toString()).arg(QString::fromUtf8(type.type->module())).arg(type.majorVersion).arg(type.minorVersion));
1562 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1565 prop->index = d->coreIndex;
1570 // We can't error here as the "id" property does not require a
1571 // successful index resolution
1572 if (prop->index != -1)
1573 prop->type = prop->core.propType;
1575 // Check if this is an alias
1576 if (prop->index != -1 &&
1578 prop->parent->type != -1 &&
1579 output->types.at(prop->parent->type).component) {
1581 QDeclarativePropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1582 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1583 prop->isAlias = true;
1586 if (prop->index != -1 && !prop->values.isEmpty())
1587 prop->parent->setBindingBit(prop->index);
1590 if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1592 // The magic "id" behavior doesn't apply when "id" is resolved as a
1593 // default property or to sub-objects (which are always in binding
1595 COMPILE_CHECK(buildIdProperty(prop, obj));
1596 if (prop->type == QVariant::String &&
1597 prop->values.first()->value.isString())
1598 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1600 } else if (isAttachedPropertyName(prop->name())) {
1602 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1604 } else if (prop->index == -1) {
1606 if (prop->isDefault) {
1607 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1609 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1612 } else if (prop->value) {
1614 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1616 } else if (enginePrivate->isList(prop->type)) {
1618 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1620 } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) {
1622 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1626 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1633 bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
1634 QDeclarativeParser::Property *nsProp,
1635 QDeclarativeParser::Object *obj,
1636 const BindingContext &ctxt)
1639 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1641 for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1643 if (!isAttachedPropertyName(prop->name()))
1644 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1646 // Setup attached property data
1648 QDeclarativeType *type = 0;
1649 unit->imports().resolveType(ns, prop->name().toUtf8(), &type, 0, 0, 0);
1651 if (!type || !type->attachedPropertiesType())
1652 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1655 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1657 Q_ASSERT(type->attachedPropertiesFunction());
1658 prop->index = type->index();
1659 prop->value->metatype = type->attachedPropertiesType();
1661 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1667 void QDeclarativeCompiler::genValueProperty(QDeclarativeParser::Property *prop,
1668 QDeclarativeParser::Object *obj)
1670 if (enginePrivate->isList(prop->type)) {
1671 genListProperty(prop, obj);
1673 genPropertyAssignment(prop, obj);
1677 void QDeclarativeCompiler::genListProperty(QDeclarativeParser::Property *prop,
1678 QDeclarativeParser::Object *obj)
1680 int listType = enginePrivate->listType(prop->type);
1682 QDeclarativeInstruction fetch;
1683 fetch.setType(QDeclarativeInstruction::FetchQList);
1684 fetch.fetchQmlList.property = prop->index;
1685 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1686 fetch.fetchQmlList.type = listType;
1687 output->addInstruction(fetch);
1689 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1691 if (v->type == Value::CreatedObject) {
1693 genObject(v->object);
1694 if (listTypeIsInterface) {
1695 QDeclarativeInstruction assign;
1696 assign.setType(QDeclarativeInstruction::AssignObjectList);
1697 assign.assignObjectList.line = prop->location.start.line;
1698 output->addInstruction(assign);
1700 QDeclarativeInstruction store;
1701 store.setType(QDeclarativeInstruction::StoreObjectQList);
1702 output->addInstruction(store);
1705 } else if (v->type == Value::PropertyBinding) {
1707 genBindingAssignment(v, prop, obj);
1713 QDeclarativeInstruction pop;
1714 pop.setType(QDeclarativeInstruction::PopQList);
1715 output->addInstruction(pop);
1718 void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *prop,
1719 QDeclarativeParser::Object *obj,
1720 QDeclarativeParser::Property *valueTypeProperty)
1722 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1724 Q_ASSERT(v->type == Value::CreatedObject ||
1725 v->type == Value::PropertyBinding ||
1726 v->type == Value::Literal);
1728 if (v->type == Value::CreatedObject) {
1730 genObject(v->object);
1732 if (QDeclarativeMetaType::isInterface(prop->type)) {
1734 QDeclarativeInstruction store;
1735 store.setType(QDeclarativeInstruction::StoreInterface);
1736 store.storeObject.line = v->object->location.start.line;
1737 store.storeObject.propertyIndex = prop->index;
1738 output->addInstruction(store);
1740 } else if (prop->type == QMetaType::QVariant) {
1742 QDeclarativeInstruction store;
1743 store.setType(QDeclarativeInstruction::StoreVariantObject);
1744 store.storeObject.line = v->object->location.start.line;
1745 store.storeObject.propertyIndex = prop->index;
1746 output->addInstruction(store);
1750 QDeclarativeInstruction store;
1751 store.setType(QDeclarativeInstruction::StoreObject);
1752 store.storeObject.line = v->object->location.start.line;
1753 store.storeObject.propertyIndex = prop->index;
1754 output->addInstruction(store);
1757 } else if (v->type == Value::PropertyBinding) {
1759 genBindingAssignment(v, prop, obj, valueTypeProperty);
1761 } else if (v->type == Value::Literal) {
1763 genLiteralAssignment(prop, v);
1769 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
1771 Q_ASSERT(v->type == Value::ValueSource ||
1772 v->type == Value::ValueInterceptor);
1774 if (v->type == Value::ValueSource) {
1775 genObject(v->object);
1777 QDeclarativeInstruction store;
1778 store.setType(QDeclarativeInstruction::StoreValueSource);
1779 if (valueTypeProperty) {
1780 store.assignValueSource.property = genValueTypeData(prop, valueTypeProperty);
1781 store.assignValueSource.owner = 1;
1783 store.assignValueSource.property = genPropertyData(prop);
1784 store.assignValueSource.owner = 0;
1786 QDeclarativeType *valueType = toQmlType(v->object);
1787 store.assignValueSource.castValue = valueType->propertyValueSourceCast();
1788 output->addInstruction(store);
1790 } else if (v->type == Value::ValueInterceptor) {
1791 genObject(v->object);
1793 QDeclarativeInstruction store;
1794 store.setType(QDeclarativeInstruction::StoreValueInterceptor);
1795 if (valueTypeProperty) {
1796 store.assignValueInterceptor.property = genValueTypeData(prop, valueTypeProperty);
1797 store.assignValueInterceptor.owner = 1;
1799 store.assignValueInterceptor.property = genPropertyData(prop);
1800 store.assignValueInterceptor.owner = 0;
1802 QDeclarativeType *valueType = toQmlType(v->object);
1803 store.assignValueInterceptor.castValue = valueType->propertyValueInterceptorCast();
1804 output->addInstruction(store);
1810 bool QDeclarativeCompiler::buildIdProperty(QDeclarativeParser::Property *prop,
1811 QDeclarativeParser::Object *obj)
1814 prop->values.isMany() ||
1815 prop->values.first()->object)
1816 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
1818 QDeclarativeParser::Value *idValue = prop->values.first();
1819 QString val = idValue->primitive();
1821 COMPILE_CHECK(checkValidId(idValue, val));
1823 if (compileState->ids.value(val))
1824 COMPILE_EXCEPTION(prop, tr("id is not unique"));
1826 prop->values.first()->type = Value::Id;
1834 void QDeclarativeCompiler::addId(const QString &id, QDeclarativeParser::Object *obj)
1836 Q_ASSERT(!compileState->ids.value(id));
1837 Q_ASSERT(obj->id == id);
1838 obj->idIndex = compileState->ids.count();
1839 compileState->ids.append(obj);
1842 void QDeclarativeCompiler::addBindingReference(BindingReference *ref)
1844 Q_ASSERT(ref->value && !ref->value->bindingReference);
1845 ref->value->bindingReference = ref;
1846 compileState->bindings.prepend(ref);
1849 void QDeclarativeCompiler::saveComponentState()
1851 Q_ASSERT(compileState->root);
1852 Q_ASSERT(compileState->root->componentCompileState == 0);
1854 compileState->root->componentCompileState = compileState;
1857 componentStats->savedComponentStats.append(componentStats->componentStat);
1860 QDeclarativeCompilerTypes::ComponentCompileState *
1861 QDeclarativeCompiler::componentState(QDeclarativeParser::Object *obj)
1863 Q_ASSERT(obj->componentCompileState);
1864 return obj->componentCompileState;
1867 // Build attached property object. In this example,
1871 // GridView is an attached property object.
1872 bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeParser::Property *prop,
1873 QDeclarativeParser::Object *obj,
1874 const BindingContext &ctxt)
1876 Q_ASSERT(prop->value);
1877 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
1879 obj->addAttachedProperty(prop);
1881 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1887 // Build "grouped" properties. In this example:
1889 // font.pointSize: 12
1890 // font.family: "Helvetica"
1892 // font is a nested property. pointSize and family are not.
1893 bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeParser::Property *prop,
1894 QDeclarativeParser::Object *obj,
1895 const BindingContext &ctxt)
1897 Q_ASSERT(prop->type != 0);
1898 Q_ASSERT(prop->index != -1);
1900 if (QDeclarativeValueTypeFactory::isValueType(prop->type)) {
1901 if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
1903 if (!prop->values.isEmpty()) {
1904 if (prop->values.first()->location < prop->value->location) {
1905 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
1907 COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
1911 if (!obj->metaObject()->property(prop->index).isWritable()) {
1912 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
1916 if (prop->isAlias) {
1917 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
1918 vtProp->isAlias = true;
1922 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
1923 prop->value, obj, ctxt.incr()));
1924 obj->addValueTypeProperty(prop);
1926 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1930 // Load the nested property's meta type
1931 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
1932 if (!prop->value->metatype)
1933 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1935 if (!prop->values.isEmpty())
1936 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
1938 obj->addGroupedProperty(prop);
1940 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1946 bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
1947 QDeclarativeParser::Object *obj,
1948 QDeclarativeParser::Object *baseObj,
1949 const BindingContext &ctxt)
1951 if (obj->defaultProperty)
1952 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
1953 obj->metatype = type->metaObject();
1955 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1957 QDeclarativePropertyCache::Data *d = property(obj, prop->name());
1959 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1961 prop->index = d->coreIndex;
1962 prop->type = d->propType;
1964 prop->isValueTypeSubProperty = true;
1967 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
1969 if (prop->values.isMany()) {
1970 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
1971 } else if (!prop->values.isEmpty()) {
1972 QDeclarativeParser::Value *value = prop->values.first();
1974 if (value->object) {
1975 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
1976 } else if (value->value.isScript()) {
1977 // ### Check for writability
1979 //optimization for <Type>.<EnumValue> enum assignments
1980 bool isEnumAssignment = false;
1982 if (prop->core.isEnum())
1983 COMPILE_CHECK(testQualifiedEnumAssignment(obj->metatype->property(prop->index), obj,
1984 value, &isEnumAssignment));
1986 if (isEnumAssignment) {
1987 value->type = Value::Literal;
1989 BindingReference *reference = pool->New<BindingReference>();
1990 reference->expression = value->value;
1991 reference->property = prop;
1992 reference->value = value;
1993 reference->bindingContext = ctxt;
1994 reference->bindingContext.owner++;
1995 addBindingReference(reference);
1996 value->type = Value::PropertyBinding;
1999 COMPILE_CHECK(testLiteralAssignment(prop, value));
2000 value->type = Value::Literal;
2004 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2005 Q_ASSERT(v->object);
2007 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
2010 obj->addValueProperty(prop);
2016 // Build assignments to QML lists. QML lists are properties of type
2017 // QDeclarativeListProperty<T>. List properties can accept a list of
2018 // objects, or a single binding.
2019 bool QDeclarativeCompiler::buildListProperty(QDeclarativeParser::Property *prop,
2020 QDeclarativeParser::Object *obj,
2021 const BindingContext &ctxt)
2023 Q_ASSERT(enginePrivate->isList(prop->type));
2027 obj->addValueProperty(prop);
2029 int listType = enginePrivate->listType(t);
2030 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
2032 bool assignedBinding = false;
2033 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2035 v->type = Value::CreatedObject;
2036 COMPILE_CHECK(buildObject(v->object, ctxt));
2038 // We check object coercian here. We check interface assignment
2040 if (!listTypeIsInterface) {
2041 if (!canCoerce(listType, v->object)) {
2042 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2046 } else if (v->value.isScript()) {
2047 if (assignedBinding)
2048 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2050 assignedBinding = true;
2051 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2052 v->type = Value::PropertyBinding;
2054 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2061 // Compiles an assignment to a QDeclarativeScriptString property
2062 bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeParser::Property *prop,
2063 QDeclarativeParser::Object *obj,
2064 const BindingContext &ctxt)
2066 if (prop->values.isMany())
2067 COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2069 if (prop->values.first()->object)
2070 COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2072 prop->scriptStringScope = ctxt.stack;
2073 obj->addScriptStringProperty(prop);
2078 // Compile regular property assignments of the form "property: <value>"
2079 bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeParser::Property *prop,
2080 QDeclarativeParser::Object *obj,
2081 const BindingContext &ctxt)
2083 obj->addValueProperty(prop);
2085 if (prop->values.isMany())
2086 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2088 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2091 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2095 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2100 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2101 Q_ASSERT(v->object);
2102 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2108 // Compile assigning a single object instance to a regular property
2109 bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeParser::Property *prop,
2110 QDeclarativeParser::Object *obj,
2111 QDeclarativeParser::Value *v,
2112 const BindingContext &ctxt)
2114 Q_ASSERT(prop->index != -1);
2115 Q_ASSERT(v->object->type != -1);
2117 if (!obj->metaObject()->property(prop->index).isWritable())
2118 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2120 if (QDeclarativeMetaType::isInterface(prop->type)) {
2122 // Assigning an object to an interface ptr property
2123 COMPILE_CHECK(buildObject(v->object, ctxt));
2125 v->type = Value::CreatedObject;
2127 } else if (prop->type == QMetaType::QVariant) {
2129 // Assigning an object to a QVariant
2130 COMPILE_CHECK(buildObject(v->object, ctxt));
2132 v->type = Value::CreatedObject;
2134 // Normally buildObject() will set this up, but we need the static
2135 // meta object earlier to test for assignability. It doesn't matter
2136 // that there may still be outstanding synthesized meta object changes
2137 // on this type, as they are not relevant for assignability testing
2138 v->object->metatype = output->types.at(v->object->type).metaObject();
2139 Q_ASSERT(v->object->metaObject());
2141 // We want to raw metaObject here as the raw metaobject is the
2142 // actual property type before we applied any extensions that might
2143 // effect the properties on the type, but don't effect assignability
2144 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2146 // Will be true if the assgned type inherits propertyMetaObject
2147 bool isAssignable = false;
2148 // Determine isAssignable value
2149 if (propertyMetaObject) {
2150 const QMetaObject *c = v->object->metatype;
2152 isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject));
2153 c = c->superClass();
2158 // Simple assignment
2159 COMPILE_CHECK(buildObject(v->object, ctxt));
2161 v->type = Value::CreatedObject;
2162 } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) {
2163 // Automatic "Component" insertion
2164 QDeclarativeParser::Object *root = v->object;
2165 QDeclarativeParser::Object *component = pool->New<Object>();
2166 component->type = componentTypeRef();
2167 component->typeName = "Qt/Component";
2168 component->metatype = &QDeclarativeComponent::staticMetaObject;
2169 component->location = root->location;
2170 QDeclarativeParser::Value *componentValue = pool->New<Value>();
2171 componentValue->object = root;
2172 component->getDefaultProperty()->addValue(componentValue);
2173 v->object = component;
2174 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2176 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2183 // Compile assigning a single object instance to a regular property using the "on" syntax.
2187 // NumberAnimation on x { }
2189 bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeParser::Property *prop,
2190 QDeclarativeParser::Object *obj,
2191 QDeclarativeParser::Object *baseObj,
2192 QDeclarativeParser::Value *v,
2193 const BindingContext &ctxt)
2195 Q_ASSERT(prop->index != -1);
2196 Q_ASSERT(v->object->type != -1);
2198 if (!obj->metaObject()->property(prop->index).isWritable())
2199 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2202 // Normally buildObject() will set this up, but we need the static
2203 // meta object earlier to test for assignability. It doesn't matter
2204 // that there may still be outstanding synthesized meta object changes
2205 // on this type, as they are not relevant for assignability testing
2206 v->object->metatype = output->types.at(v->object->type).metaObject();
2207 Q_ASSERT(v->object->metaObject());
2209 // Will be true if the assigned type inherits QDeclarativePropertyValueSource
2210 bool isPropertyValue = false;
2211 // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor
2212 bool isPropertyInterceptor = false;
2213 if (QDeclarativeType *valueType = toQmlType(v->object)) {
2214 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2215 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2218 if (isPropertyValue || isPropertyInterceptor) {
2219 // Assign as a property value source
2220 COMPILE_CHECK(buildObject(v->object, ctxt));
2222 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2223 buildDynamicMeta(baseObj, ForceCreation);
2224 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2226 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(QString::fromUtf8(v->object->typeName)).arg(prop->name().toString()));
2232 // Compile assigning a literal or binding to a regular property
2233 bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeParser::Property *prop,
2234 QDeclarativeParser::Object *obj,
2235 QDeclarativeParser::Value *v,
2236 const BindingContext &ctxt)
2238 Q_ASSERT(prop->index != -1);
2240 if (v->value.isScript()) {
2242 //optimization for <Type>.<EnumValue> enum assignments
2243 if (prop->core.isEnum()) {
2244 bool isEnumAssignment = false;
2245 COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj,
2246 v, &isEnumAssignment));
2247 if (isEnumAssignment) {
2248 v->type = Value::Literal;
2253 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2255 v->type = Value::PropertyBinding;
2259 COMPILE_CHECK(testLiteralAssignment(prop, v));
2261 v->type = Value::Literal;
2267 bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop,
2268 QDeclarativeParser::Object *obj,
2269 QDeclarativeParser::Value *v,
2272 *isAssignment = false;
2273 if (!prop.isEnumType())
2276 if (!prop.isWritable())
2277 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
2279 QString string = v->value.asString();
2280 if (!QDeclarativeUtils::isUpper(string.at(0)))
2283 QStringList parts = string.split(QLatin1Char('.'));
2284 if (parts.count() != 2)
2287 QString typeName = parts.at(0);
2288 QDeclarativeType *type = 0;
2289 unit->imports().resolveType(typeName.toUtf8(), &type, 0, 0, 0, 0);
2291 //handle enums on value types (where obj->typeName is empty)
2292 QByteArray objTypeName = obj->typeName;
2293 if (objTypeName.isEmpty()) {
2294 QDeclarativeType *objType = toQmlType(obj);
2296 objTypeName = objType->qmlTypeName();
2302 QString enumValue = parts.at(1);
2305 if (objTypeName == type->qmlTypeName()) {
2306 // When these two match, we can short cut the search
2307 if (prop.isFlagType()) {
2308 value = prop.enumerator().keysToValue(enumValue.toUtf8().constData());
2310 value = prop.enumerator().keyToValue(enumValue.toUtf8().constData());
2313 // Otherwise we have to search the whole type
2314 // This matches the logic in QV8TypeWrapper
2315 QByteArray enumName = enumValue.toUtf8();
2316 const QMetaObject *metaObject = type->baseMetaObject();
2317 for (int ii = metaObject->enumeratorCount() - 1; value == -1 && ii >= 0; --ii) {
2318 QMetaEnum e = metaObject->enumerator(ii);
2319 value = e.keyToValue(enumName.constData());
2326 v->type = Value::Literal;
2327 v->value = QDeclarativeParser::Variant((double)value);
2328 *isAssignment = true;
2333 struct StaticQtMetaObject : public QObject
2335 static const QMetaObject *get()
2336 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2339 // Similar logic to above, but not knowing target property.
2340 int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const
2342 int dot = script.indexOf('.');
2344 const QByteArray &scope = script.left(dot);
2345 QDeclarativeType *type = 0;
2346 unit->imports().resolveType(scope, &type, 0, 0, 0, 0);
2347 if (!type && scope != "Qt")
2349 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2350 const char *key = script.constData() + dot+1;
2351 int i = mo->enumeratorCount();
2353 int v = mo->enumerator(i).keyToValue(key);
2361 const QMetaObject *QDeclarativeCompiler::resolveType(const QByteArray& name) const
2363 QDeclarativeType *qmltype = 0;
2364 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2368 return qmltype->metaObject();
2371 // similar to logic of completeComponentBuild, but also sticks data
2372 // into primitives at the end
2373 int QDeclarativeCompiler::rewriteBinding(const QString& expression, const QString& name)
2375 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2376 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf('.') + 1));
2378 QString rewrite = rewriteBinding(expression, 0, 0);
2380 return output->indexForString(rewrite);
2383 // Ensures that the dynamic meta specification on obj is valid
2384 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj)
2386 // XXX aakenned - inefficient copying of the string ref
2387 QStringHash<bool> propNames;
2388 QSet<QByteArray> methodNames;
2389 bool seenDefaultProperty = false;
2392 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2393 const QDeclarativeParser::Object::DynamicProperty &prop =
2394 obj->dynamicProperties.at(ii);
2396 if (prop.isDefaultProperty) {
2397 if (seenDefaultProperty)
2398 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2399 seenDefaultProperty = true;
2402 if (propNames.contains(prop.name))
2403 COMPILE_EXCEPTION(&prop, tr("Duplicate property name"));
2405 if (QDeclarativeUtils::isUpper(prop.name.at(0)))
2406 COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
2408 if (enginePrivate->v8engine()->illegalNames().contains(prop.name))
2409 COMPILE_EXCEPTION(&prop, tr("Illegal property name"));
2411 propNames.insert(prop.name.toString(), true);
2414 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2415 const QDeclarativeScript::Object::DynamicSignal &currSig = *s;
2417 if (methodNames.testAndSet(currSig.name.hash())) {
2418 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2419 s2 = obj->dynamicSignals.next(s2)) {
2420 if (s2->name == currSig.name)
2421 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2425 if (currSig.name.at(0).isUpper())
2426 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2427 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2428 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2431 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2432 const QDeclarativeScript::Object::DynamicSlot &currSlot = *s;
2434 if (methodNames.testAndSet(currSlot.name.hash())) {
2435 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2436 s2 = obj->dynamicSignals.next(s2)) {
2437 if (s2->name == currSlot.name)
2438 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2440 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2441 s2 = obj->dynamicSlots.next(s2)) {
2442 if (s2->name == currSlot.name)
2443 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2447 if (currSlot.name.at(0).isUpper())
2448 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2449 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2450 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2456 bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeParser::Object *obj)
2458 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2459 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2461 if (!p.defaultValue || p.type == Object::DynamicProperty::Alias)
2464 Property *property = 0;
2465 if (p.isDefaultProperty) {
2466 property = obj->getDefaultProperty();
2468 property = obj->getProperty(p.name);
2469 if (!property->values.isEmpty())
2470 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2473 if (property->value)
2474 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2476 property->values.append(p.defaultValue->values);
2481 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2483 bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, DynamicMetaMode mode)
2486 Q_ASSERT(obj->metatype);
2488 if (mode != ForceCreation &&
2489 obj->dynamicProperties.isEmpty() &&
2490 obj->dynamicSignals.isEmpty() &&
2491 obj->dynamicSlots.isEmpty())
2494 bool resolveAlias = (mode == ResolveAliases);
2496 const Object::DynamicProperty *defaultProperty = 0;
2499 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2500 const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2502 if (p.type == Object::DynamicProperty::Alias)
2505 if (p.isDefaultProperty &&
2506 (resolveAlias || p.type != Object::DynamicProperty::Alias))
2507 defaultProperty = &p;
2509 if (!resolveAlias) {
2510 // No point doing this for both the alias and non alias cases
2511 QDeclarativePropertyCache::Data *d = property(obj, p.name);
2512 if (d && d->isFinal())
2513 COMPILE_EXCEPTION(&p, tr("Cannot override FINAL property"));
2517 bool buildData = resolveAlias || aliasCount == 0;
2519 QByteArray dynamicData;
2521 typedef QDeclarativeVMEMetaData VMD;
2523 dynamicData = QByteArray(sizeof(QDeclarativeVMEMetaData) +
2524 (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) +
2525 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2526 aliasCount * sizeof(VMD::AliasData), 0);
2529 int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1);
2531 QByteArray newClassName = obj->metatype->className();
2532 newClassName.append("_QML_");
2533 newClassName.append(QByteArray::number(uniqueClassId));
2535 if (compileState->root == obj && !compileState->nested) {
2536 QString path = output->url.path();
2537 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2538 if (lastSlash > -1) {
2539 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2540 if (!nameBase.isEmpty() && QDeclarativeUtils::isUpper(nameBase.at(0)))
2541 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId);
2545 QFastMetaBuilder builder;
2546 QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(),
2547 obj->dynamicProperties.count() - (resolveAlias?0:aliasCount),
2548 obj->dynamicSlots.count(),
2549 obj->dynamicSignals.count() + obj->dynamicProperties.count(),
2550 defaultProperty?1:0);
2553 Object::DynamicProperty::Type dtype;
2555 const char *cppType;
2556 } builtinTypes[] = {
2557 { Object::DynamicProperty::Variant, 0, "QVariant" },
2558 { Object::DynamicProperty::Int, QMetaType::Int, "int" },
2559 { Object::DynamicProperty::Bool, QMetaType::Bool, "bool" },
2560 { Object::DynamicProperty::Real, QMetaType::Double, "double" },
2561 { Object::DynamicProperty::String, QMetaType::QString, "QString" },
2562 { Object::DynamicProperty::Url, QMetaType::QUrl, "QUrl" },
2563 { Object::DynamicProperty::Color, QMetaType::QColor, "QColor" },
2564 { Object::DynamicProperty::Time, QMetaType::QTime, "QTime" },
2565 { Object::DynamicProperty::Date, QMetaType::QDate, "QDate" },
2566 { Object::DynamicProperty::DateTime, QMetaType::QDateTime, "QDateTime" },
2568 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2569 QFastMetaBuilder::StringRef typeRefs[builtinTypeCount];
2571 // Reserve dynamic properties
2572 if (obj->dynamicProperties.count()) {
2573 typedef QDeclarativeVMEMetaData VMD;
2575 int effectivePropertyIndex = 0;
2576 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2577 Object::DynamicProperty &p = obj->dynamicProperties[ii];
2579 // Reserve space for name
2580 p.nameRef = builder.newString(p.name.utf8length());
2582 int propertyType = 0;
2583 bool readonly = false;
2584 QFastMetaBuilder::StringRef typeRef;
2586 if (p.type == Object::DynamicProperty::Alias) {
2588 } else if (p.type < builtinTypeCount) {
2589 Q_ASSERT(builtinTypes[p.type].dtype == p.type);
2590 propertyType = builtinTypes[p.type].metaType;
2591 if (typeRefs[p.type].isEmpty())
2592 typeRefs[p.type] = builder.newString(strlen(builtinTypes[p.type].cppType));
2593 typeRef = typeRefs[p.type];
2594 if (p.type == Object::DynamicProperty::Variant)
2595 propertyType = qMetaTypeId<QVariant>();
2598 Q_ASSERT(p.type == Object::DynamicProperty::CustomList ||
2599 p.type == Object::DynamicProperty::Custom);
2601 // XXX don't double resolve this in the case of an alias run
2603 QByteArray customTypeName;
2604 QDeclarativeType *qmltype = 0;
2606 if (!unit->imports().resolveType(p.customType.toUtf8(), &qmltype, &url, 0, 0, 0))
2607 COMPILE_EXCEPTION(&p, tr("Invalid property type"));
2610 QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(QUrl(url));
2612 Q_ASSERT(tdata->isComplete());
2614 QDeclarativeCompiledData *data = tdata->compiledData();
2615 customTypeName = data->root->className();
2619 customTypeName = qmltype->typeName();
2622 if (p.type == Object::DynamicProperty::Custom) {
2623 customTypeName += '*';
2624 propertyType = QMetaType::QObjectStar;
2627 customTypeName = QByteArray("QDeclarativeListProperty<") + customTypeName + QByteArray(">");
2628 propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
2631 p.resolvedCustomTypeName = pool->NewByteArray(customTypeName);
2632 p.typeRef = builder.newString(customTypeName.length());
2633 typeRef = p.typeRef;
2637 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2638 vmd->propertyCount++;
2639 (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType;
2642 if (p.type < builtinTypeCount)
2643 builder.setProperty(effectivePropertyIndex, p.nameRef, typeRef, (QMetaType::Type)propertyType,
2644 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2645 effectivePropertyIndex);
2647 builder.setProperty(effectivePropertyIndex, p.nameRef, typeRef,
2648 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2649 effectivePropertyIndex);
2651 p.changedSignatureRef = builder.newString(p.name.utf8length() + strlen("Changed()"));
2652 builder.setSignal(effectivePropertyIndex, p.changedSignatureRef);
2654 effectivePropertyIndex++;
2659 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2660 Object::DynamicProperty &p = obj->dynamicProperties[ii];
2661 if (p.type == Object::DynamicProperty::Alias) {
2663 Q_ASSERT(buildData);
2664 ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++;
2665 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex, aliasIndex, p));
2667 // Even if we aren't resolving the alias, we need a fake signal so that the
2668 // metaobject remains consistent across the resolve and non-resolve alias runs
2669 p.changedSignatureRef = builder.newString(p.name.utf8length() + strlen("Changed()"));
2670 builder.setSignal(effectivePropertyIndex, p.changedSignatureRef);
2671 effectivePropertyIndex++;
2678 // Reserve default property
2679 QFastMetaBuilder::StringRef defPropRef;
2680 if (defaultProperty) {
2681 defPropRef = builder.newString(strlen("DefaultProperty"));
2682 builder.setClassInfo(0, defPropRef, defaultProperty->nameRef);
2685 // Reserve dynamic signals
2686 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2687 Object::DynamicSignal &s = obj->dynamicSignals[ii];
2689 int paramCount = s.parameterNames.count();
2691 int signatureSize = s.name.length() + 2 /* paren */;
2693 if (paramCount) signatureSize += s.parameterTypesLength() + (paramCount - 1) /* commas */;
2694 if (paramCount) namesSize += s.parameterNamesLength() + (paramCount - 1) /* commas */;
2696 s.signatureRef = builder.newString(signatureSize);
2697 if (namesSize) s.parameterNamesRef = builder.newString(namesSize);
2700 ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++;
2702 builder.setSignal(ii + obj->dynamicProperties.count(), s.signatureRef, s.parameterNamesRef);
2705 // Reserve dynamic slots
2706 if (obj->dynamicSlots.count()) {
2708 // Allocate QVariant string
2709 if (typeRefs[0].isEmpty())
2710 typeRefs[0] = builder.newString(strlen(builtinTypes[0].cppType));
2712 typedef QDeclarativeVMEMetaData VMD;
2714 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2715 Object::DynamicSlot &s = obj->dynamicSlots[ii];
2716 int paramCount = s.parameterNames.count();
2718 int signatureSize = s.name.length() + 2 /* paren */;
2720 if (paramCount) signatureSize += (paramCount * strlen("QVariant") + (paramCount - 1));
2721 if (paramCount) namesSize += s.parameterNamesLength() + (paramCount - 1 /* commas */);
2723 s.signatureRef = builder.newString(signatureSize);
2724 if (namesSize) s.parameterNamesRef = builder.newString(namesSize);
2726 builder.setMethod(ii, s.signatureRef, s.parameterNamesRef, typeRefs[0]);
2730 funcScript.reserve(strlen("(function ") + s.name.length() + 1 /* lparen */ +
2731 namesSize + 1 /* rparen */ + s.body.length() + 1 /* rparen */);
2732 funcScript = QLatin1String("(function ") + s.name + QLatin1Char('(');
2733 for (int jj = 0; jj < paramCount; ++jj) {
2734 if (jj) funcScript.append(QLatin1Char(','));
2735 funcScript.append(QLatin1String(s.parameterNames.at(jj)));
2737 funcScript += QLatin1Char(')') + s.body + QLatin1Char(')');
2739 VMD::MethodData methodData = { s.parameterNames.count(), 0,
2740 funcScript.length(),
2741 s.location.start.line };
2743 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2746 VMD::MethodData &md = *(vmd->methodData() + ii);
2748 md.bodyOffset = dynamicData.size();
2750 dynamicData.append((const char *)funcScript.constData(),
2751 (funcScript.length() * sizeof(QChar)));
2757 // Now allocate used builtin types
2758 for (int ii = 0; ii < builtinTypeCount; ++ii) {
2759 if (!typeRefs[ii].isEmpty())
2760 typeRefs[ii].load(builtinTypes[ii].cppType);
2763 // Now allocate properties
2764 for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2765 Object::DynamicProperty &p = obj->dynamicProperties[ii];
2767 char *d = p.changedSignatureRef.data();
2768 p.name.writeUtf8(d);
2769 strcpy(d + p.name.utf8length(), "Changed()");
2771 if (p.type == Object::DynamicProperty::Alias && !resolveAlias)
2774 p.nameRef.load(p.name);
2776 if (p.type >= builtinTypeCount) {
2777 Q_ASSERT(p.resolvedCustomTypeName);
2778 p.typeRef.load(*p.resolvedCustomTypeName);
2782 // Allocate default property if necessary
2783 if (defaultProperty)
2784 strcpy(defPropRef.data(), "DefaultProperty");
2786 // Now allocate signals
2787 for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2788 Object::DynamicSignal &s = obj->dynamicSignals[ii];
2790 char *d = s.signatureRef.data();
2791 char *d2 = s.parameterNamesRef.isEmpty()?0:s.parameterNamesRef.data();
2792 strcpy(d, s.name.constData());
2793 d += s.name.length();
2796 for (int jj = 0; jj < s.parameterNames.count(); ++jj) {
2797 if (jj != 0) { *d++ = ','; *d2++ = ','; }
2798 strcpy(d, s.parameterTypes.at(jj).constData());
2799 d += s.parameterTypes.at(jj).length();
2800 strcpy(d2, s.parameterNames.at(jj).constData());
2801 d2 += s.parameterNames.at(jj).length();
2808 // Now allocate methods
2809 for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2810 Object::DynamicSlot &s = obj->dynamicSlots[ii];
2811 char *d = s.signatureRef.data();
2812 char *d2 = s.parameterNamesRef.isEmpty()?0:s.parameterNamesRef.data();
2813 strcpy(d, s.name.constData());
2814 d += s.name.length();
2816 for (int jj = 0; jj < s.parameterNames.count(); ++jj) {
2817 if (jj != 0) { *d++ = ','; *d2++ = ','; }
2818 strcpy(d, "QVariant");
2819 d += strlen("QVariant");
2820 strcpy(d2, s.parameterNames.at(jj).constData());
2821 d2 += s.parameterNames.at(jj).length();
2828 // Now allocate class name
2829 classNameRef.load(newClassName);
2831 obj->metadata = builder.toData();
2832 builder.fromData(&obj->extObject, obj->metatype, obj->metadata);
2834 if (mode == IgnoreAliases && aliasCount)
2835 compileState->aliasingObjects.append(obj);
2837 obj->synthdata = dynamicData;
2839 if (obj->synthCache) {
2840 obj->synthCache->release();
2841 obj->synthCache = 0;
2844 if (obj->type != -1) {
2845 QDeclarativePropertyCache *cache = output->types[obj->type].createPropertyCache(engine)->copy();
2846 cache->append(engine, &obj->extObject, QDeclarativePropertyCache::Data::NoFlags,
2847 QDeclarativePropertyCache::Data::IsVMEFunction,
2848 QDeclarativePropertyCache::Data::IsVMESignal);
2849 obj->synthCache = cache;
2855 bool QDeclarativeCompiler::checkValidId(QDeclarativeParser::Value *v, const QString &val)
2858 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
2860 QChar ch = val.at(0);
2861 if (QDeclarativeUtils::isLetter(ch) && !QDeclarativeUtils::isLower(ch))
2862 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
2864 QChar u(QLatin1Char('_'));
2865 if (!QDeclarativeUtils::isLetter(ch) && ch != u)
2866 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
2868 for (int ii = 1; ii < val.count(); ++ii) {
2870 if (!QDeclarativeUtils::isLetterOrNumber(ch) && ch != u)
2871 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
2874 if (enginePrivate->v8engine()->illegalNames().contains(val))
2875 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
2880 #include <qdeclarativejsparser_p.h>
2882 static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node)
2884 if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) {
2886 static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name.toString();
2887 return QStringList() << name;
2888 } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) {
2889 QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node);
2891 QStringList rv = astNodeToStringList(expr->base);
2894 rv.append(expr->name.toString());
2897 return QStringList();
2900 bool QDeclarativeCompiler::compileAlias(QFastMetaBuilder &builder,
2902 QDeclarativeParser::Object *obj,
2903 int propIndex, int aliasIndex,
2904 Object::DynamicProperty &prop)
2906 if (!prop.defaultValue)
2907 COMPILE_EXCEPTION(obj, tr("No property alias location"));
2909 if (!prop.defaultValue->values.isOne() ||
2910 prop.defaultValue->values.first()->object ||
2911 !prop.defaultValue->values.first()->value.isScript())
2912 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2914 QDeclarativeJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST();
2916 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
2918 QStringList alias = astNodeToStringList(node);
2920 if (alias.count() < 1 || alias.count() > 3)
2921 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
2923 QDeclarativeParser::Object *idObject = compileState->ids.value(alias.at(0));
2925 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
2927 QByteArray typeName;
2932 bool writable = false;
2933 bool resettable = false;
2934 if (alias.count() == 2 || alias.count() == 3) {
2935 propIdx = indexOfProperty(idObject, alias.at(1));
2937 if (-1 == propIdx) {
2938 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2939 } else if (propIdx > 0xFFFF) {
2940 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
2943 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
2944 if (!aliasProperty.isScriptable())
2945 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2947 writable = aliasProperty.isWritable();
2948 resettable = aliasProperty.isResettable();
2950 if (aliasProperty.type() < QVariant::UserType)
2951 type = aliasProperty.type();
2953 if (alias.count() == 3) {
2954 QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
2956 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2958 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
2960 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
2961 if (valueTypeIndex == -1)
2962 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2963 Q_ASSERT(valueTypeIndex <= 0xFF);
2965 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
2966 propIdx |= (valueTypeIndex << 16);
2969 if (aliasProperty.isEnumType())
2970 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
2972 typeName = aliasProperty.typeName();
2974 Q_ASSERT(idObject->type != -1); // How else did it get an id?
2976 const QDeclarativeCompiledData::TypeReference &ref = output->types.at(idObject->type);
2978 typeName = ref.type->typeName();
2980 typeName = ref.component->root->className();
2985 if (typeName.endsWith('*'))
2986 flags |= QML_ALIAS_FLAG_PTR;
2988 QDeclarativeVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags };
2990 typedef QDeclarativeVMEMetaData VMD;
2991 VMD *vmd = (QDeclarativeVMEMetaData *)data.data();
2992 *(vmd->aliasData() + aliasIndex) = aliasData;
2994 prop.nameRef = builder.newString(prop.name.length());
2995 prop.resolvedCustomTypeName = pool->NewByteArray(typeName);
2996 prop.typeRef = builder.newString(typeName.length());
2998 builder.setProperty(propIndex, prop.nameRef, prop.typeRef, (QMetaType::Type)type,
2999 (QFastMetaBuilder::PropertyFlag)(writable?int(QFastMetaBuilder::Writable):0),
3005 bool QDeclarativeCompiler::buildBinding(QDeclarativeParser::Value *value,
3006 QDeclarativeParser::Property *prop,
3007 const BindingContext &ctxt)
3009 Q_ASSERT(prop->index != -1);
3010 Q_ASSERT(prop->parent);
3011 Q_ASSERT(prop->parent->metaObject());
3014 QMetaProperty mp = prop->parent->metaObject()->property(prop->index);
3015 if (!mp.isWritable() && !QDeclarativeMetaType::isList(prop->type))
3016 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3018 BindingReference *reference = pool->New<BindingReference>();
3019 reference->expression = value->value;
3020 reference->property = prop;
3021 reference->value = value;
3022 reference->bindingContext = ctxt;
3023 addBindingReference(reference);
3028 void QDeclarativeCompiler::genBindingAssignment(QDeclarativeParser::Value *binding,
3029 QDeclarativeParser::Property *prop,
3030 QDeclarativeParser::Object *obj,
3031 QDeclarativeParser::Property *valueTypeProperty)
3034 Q_ASSERT(binding->bindingReference);
3036 const BindingReference &ref = *binding->bindingReference;
3037 if (ref.dataType == BindingReference::V4) {
3038 QDeclarativeInstruction store;
3039 store.setType(QDeclarativeInstruction::StoreV4Binding);
3040 store.assignBinding.value = ref.compiledIndex;
3041 store.assignBinding.context = ref.bindingContext.stack;
3042 store.assignBinding.owner = ref.bindingContext.owner;
3043 if (valueTypeProperty)
3044 store.assignBinding.property = (valueTypeProperty->index & 0xFFFF) |
3045 ((valueTypeProperty->type & 0xFF)) << 16 |
3046 ((prop->index & 0xFF) << 24);
3048 store.assignBinding.property = prop->index;
3049 store.assignBinding.line = binding->location.start.line;
3050 output->addInstruction(store);
3051 } else if (ref.dataType == BindingReference::V8) {
3052 QDeclarativeInstruction store;
3053 store.setType(QDeclarativeInstruction::StoreV8Binding);
3054 store.assignBinding.value = ref.compiledIndex;
3055 store.assignBinding.context = ref.bindingContext.stack;
3056 store.assignBinding.owner = ref.bindingContext.owner;
3057 store.assignBinding.line = binding->location.start.line;
3059 Q_ASSERT(ref.bindingContext.owner == 0 ||
3060 (ref.bindingContext.owner != 0 && valueTypeProperty));
3061 if (ref.bindingContext.owner) {
3062 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
3064 store.assignBinding.property = genPropertyData(prop);
3067 output->addInstruction(store);
3069 QDeclarativeInstruction store;
3071 store.setType(QDeclarativeInstruction::StoreBinding);
3073 store.setType(QDeclarativeInstruction::StoreBindingOnAlias);
3074 store.assignBinding.value = output->indexForString(ref.rewrittenExpression);
3075 store.assignBinding.context = ref.bindingContext.stack;
3076 store.assignBinding.owner = ref.bindingContext.owner;
3077 store.assignBinding.line = binding->location.start.line;
3079 Q_ASSERT(ref.bindingContext.owner == 0 ||
3080 (ref.bindingContext.owner != 0 && valueTypeProperty));
3081 if (ref.bindingContext.owner) {
3082 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
3084 store.assignBinding.property = genPropertyData(prop);
3086 output->addInstruction(store);
3090 int QDeclarativeCompiler::genContextCache()
3092 if (compileState->ids.count() == 0)
3095 QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache();
3096 cache->reserve(compileState->ids.count());
3097 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
3098 cache->add(o->id, o->idIndex);
3100 output->contextCaches.append(cache);
3101 return output->contextCaches.count() - 1;
3104 int QDeclarativeCompiler::genValueTypeData(QDeclarativeParser::Property *valueTypeProp,
3105 QDeclarativeParser::Property *prop)
3107 typedef QDeclarativePropertyPrivate QDPP;
3108 QByteArray data = QDPP::saveValueType(prop->parent->metaObject(), prop->index,
3109 enginePrivate->valueTypes[prop->type]->metaObject(),
3110 valueTypeProp->index, engine);
3112 return output->indexForByteArray(data);
3115 int QDeclarativeCompiler::genPropertyData(QDeclarativeParser::Property *prop)
3117 typedef QDeclarativePropertyPrivate QDPP;
3118 QByteArray data = QDPP::saveProperty(prop->parent->metaObject(), prop->index, engine);
3120 return output->indexForByteArray(data);
3123 bool QDeclarativeCompiler::completeComponentBuild()
3126 componentStats->componentStat.ids = compileState->ids.count();
3128 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
3129 aliasObject = compileState->aliasingObjects.next(aliasObject))
3130 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
3132 QDeclarativeV4Compiler::Expression expr(unit->imports());
3133 expr.component = compileState->root;
3134 expr.ids = &compileState->ids;
3135 expr.importCache = output->importCache;
3137 QDeclarativeV4Compiler bindingCompiler;
3139 QList<BindingReference*> sharedBindings;
3141 for (BindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3143 BindingReference &binding = *b;
3145 // ### We don't currently optimize for bindings on alias's - because
3146 // of the solution to QTBUG-13719
3147 if (!binding.property->isAlias) {
3148 expr.context = binding.bindingContext.object;
3149 expr.property = binding.property;
3150 expr.expression = binding.expression;
3152 int index = bindingCompiler.compile(expr, enginePrivate);
3154 binding.dataType = BindingReference::V4;
3155 binding.compiledIndex = index;
3157 componentStats->componentStat.optimizedBindings.append(b->value->location);
3162 // Pre-rewrite the expression
3163 QString expression = binding.expression.asScript();
3165 QDeclarativeRewrite::RewriteBinding rewriteBinding;
3166 rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3167 bool isSharable = false;
3168 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3170 if (isSharable && !binding.property->isAlias /* See above re alias */ &&
3171 binding.property->type != qMetaTypeId<QDeclarativeBinding*>()) {
3172 binding.dataType = BindingReference::V8;
3173 sharedBindings.append(b);
3175 binding.dataType = BindingReference::QtScript;
3179 componentStats->componentStat.scriptBindings.append(b->value->location);
3182 if (!sharedBindings.isEmpty()) {
3184 static bool lt(const BindingReference *lhs, const BindingReference *rhs)
3186 return lhs->value->location.start.line < rhs->value->location.start.line;
3190 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3192 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3193 int lineNumber = startLineNumber;
3195 QString functionArray(QLatin1String("["));
3196 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3197 BindingReference *reference = sharedBindings.at(ii);
3198 QDeclarativeParser::Value *value = reference->value;
3199 const QString &expression = reference->rewrittenExpression;
3201 if (ii != 0) functionArray += QLatin1String(",");
3203 while (lineNumber < value->location.start.line) {
3205 functionArray += QLatin1String("\n");
3208 functionArray += expression;
3209 reference->compiledIndex = ii;
3211 functionArray += QLatin1String("]");
3213 compileState->v8BindingProgram = functionArray;
3214 compileState->v8BindingProgramLine = startLineNumber;
3215 compileState->v8BindingProgramIndex = output->v8bindings.count();
3216 output->v8bindings.append(v8::Persistent<v8::Array>());
3219 if (bindingCompiler.isValid())
3220 compileState->compiledBindingData = bindingCompiler.program();
3222 saveComponentState();
3227 void QDeclarativeCompiler::dumpStats()
3229 Q_ASSERT(componentStats);
3230 qWarning().nospace() << "QML Document: " << output->url.toString();
3231 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3232 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3233 qWarning().nospace() << " Component Line " << stat.lineNumber;
3234 qWarning().nospace() << " Total Objects: " << stat.objects;
3235 qWarning().nospace() << " IDs Used: " << stat.ids;
3236 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3240 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3241 if (0 == (ii % 10)) {
3242 if (ii) output.append("\n");
3247 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3249 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3250 output.append(") ");
3252 if (!output.isEmpty())
3253 qWarning().nospace() << output.constData();
3256 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3259 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3260 if (0 == (ii % 10)) {
3261 if (ii) output.append("\n");
3266 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3268 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3269 output.append(") ");
3271 if (!output.isEmpty())
3272 qWarning().nospace() << output.constData();
3278 Returns true if from can be assigned to a (QObject) property of type
3281 bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeParser::Object *from)
3283 const QMetaObject *toMo =
3284 enginePrivate->rawMetaObjectForType(to);
3285 const QMetaObject *fromMo = from->metaObject();
3288 if (QDeclarativePropertyPrivate::equal(fromMo, toMo))
3290 fromMo = fromMo->superClass();
3296 Returns the element name, as written in the QML file, for o.
3298 QString QDeclarativeCompiler::elementName(QDeclarativeParser::Object *o)
3301 if (o->type != -1) {
3302 return output->types.at(o->type).className;
3308 QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeParser::Object *from)
3311 const QMetaObject *mo = from->metatype;
3312 QDeclarativeType *type = 0;
3313 while (!type && mo) {
3314 type = QDeclarativeMetaType::qmlType(mo);
3315 mo = mo->superClass();
3320 QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeParser::Object *obj)
3322 const QMetaObject *mo = obj->metatype;
3324 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3326 return QStringList();
3328 QMetaClassInfo classInfo = mo->classInfo(idx);
3329 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3333 QDeclarativePropertyCache::Data *
3334 QDeclarativeCompiler::property(QDeclarativeParser::Object *object, int index)
3336 QDeclarativePropertyCache *cache = 0;
3338 if (object->synthCache)
3339 cache = object->synthCache;
3340 else if (object->type != -1)
3341 cache = output->types[object->type].createPropertyCache(engine);
3343 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3345 return cache->property(index);
3348 QDeclarativePropertyCache::Data *
3349 QDeclarativeCompiler::property(QDeclarativeParser::Object *object, const QHashedStringRef &name, bool *notInRevision)
3351 if (notInRevision) *notInRevision = false;
3353 QDeclarativePropertyCache *cache = 0;
3355 if (object->synthCache)
3356 cache = object->synthCache;
3357 else if (object->type != -1)
3358 cache = output->types[object->type].createPropertyCache(engine);
3360 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3362 QDeclarativePropertyCache::Data *d = cache->property(name);
3364 // Find the first property
3365 while (d && d->isFunction())
3366 d = cache->overrideData(d);
3368 if (d && !cache->isAllowedInRevision(d)) {
3369 if (notInRevision) *notInRevision = true;
3376 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3377 QDeclarativePropertyCache::Data *
3378 QDeclarativeCompiler::signal(QDeclarativeParser::Object *object, const QHashedStringRef &name, bool *notInRevision)
3380 if (notInRevision) *notInRevision = false;
3382 QDeclarativePropertyCache *cache = 0;
3384 if (object->synthCache)
3385 cache = object->synthCache;
3386 else if (object->type != -1)
3387 cache = output->types[object->type].createPropertyCache(engine);
3389 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3392 QDeclarativePropertyCache::Data *d = cache->property(name);
3393 if (notInRevision) *notInRevision = false;
3395 while (d && !(d->isFunction()))
3396 d = cache->overrideData(d);
3398 if (d && !cache->isAllowedInRevision(d)) {
3399 if (notInRevision) *notInRevision = true;
3405 if (name.endsWith(Changed_string)) {
3406 QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3408 d = property(object, propName, notInRevision);
3410 return cache->method(d->notifyIndex);
3416 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3417 int QDeclarativeCompiler::indexOfSignal(QDeclarativeParser::Object *object, const QString &name,
3418 bool *notInRevision)
3420 QDeclarativePropertyCache::Data *d = signal(object, QStringRef(&name), notInRevision);
3421 return d?d->coreIndex:-1;
3424 int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QString &name,
3425 bool *notInRevision)
3427 return indexOfProperty(object, QStringRef(&name), notInRevision);
3430 int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QHashedStringRef &name,
3431 bool *notInRevision)
3433 QDeclarativePropertyCache::Data *d = property(object, name, notInRevision);
3434 return d?d->coreIndex:-1;