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);
852 QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
854 Property *explicitProperty = obj->getProperty(QString::fromUtf8(p.name()), false);
855 if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) {
857 skipProperty = explicitProperty; // We merge the values into defaultProperty
859 // Find the correct insertion point
860 Value *insertPos = 0;
862 for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) {
863 if (!(v->location.start < explicitProperty->values.first()->location.start))
868 defaultProperty->values.insertAfter(insertPos, explicitProperty->values);
874 QDeclarativeCustomParser *cp = 0;
876 cp = output->types.at(obj->type).type->customParser();
878 // Build all explicit properties specified
879 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
881 if (prop == skipProperty)
883 if (prop->name() == id_string)
886 bool canDefer = false;
887 if (isCustomParser) {
888 if (doesPropertyExist(prop, obj) &&
889 (!(cp->flags() & QDeclarativeCustomParser::AcceptsAttachedProperties) ||
890 !isAttachedPropertyName(prop->name()))) {
891 int ids = compileState->ids.count();
892 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
893 canDefer = ids == compileState->ids.count();
894 } else if (isSignalPropertyName(prop->name()) &&
895 (cp->flags() & QDeclarativeCustomParser::AcceptsSignalHandlers)) {
896 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
898 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
901 if (isSignalPropertyName(prop->name())) {
902 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
904 int ids = compileState->ids.count();
905 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
906 canDefer = ids == compileState->ids.count();
910 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
911 prop->isDeferred = true;
915 // Build the default property
916 if (defaultProperty) {
917 Property *prop = defaultProperty;
919 bool canDefer = false;
920 if (isCustomParser) {
921 if (doesPropertyExist(prop, obj)) {
922 int ids = compileState->ids.count();
923 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
924 canDefer = ids == compileState->ids.count();
926 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
929 int ids = compileState->ids.count();
930 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
931 canDefer = ids == compileState->ids.count();
934 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
935 prop->isDeferred = true;
938 // Compile custom parser parts
939 if (isCustomParser && !customProps.isEmpty()) {
943 obj->custom = cp->compile(customProps);
946 foreach (QDeclarativeError err, cp->errors()) {
947 err.setUrl(output->url);
955 void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj)
957 QDeclarativeCompiledData::TypeReference &tr = output->types[obj->type];
958 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
964 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
965 !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) {
967 QDeclarativeInstruction create;
968 create.setType(QDeclarativeInstruction::CreateSimpleObject);
969 create.createSimple.create = output->types.at(obj->type).type->createFunction();
970 create.createSimple.typeSize = output->types.at(obj->type).type->createSize();
971 create.createSimple.type = obj->type;
972 create.createSimple.line = obj->location.start.line;
973 create.createSimple.column = obj->location.start.column;
974 output->addInstruction(create);
978 QDeclarativeInstruction create;
979 create.setType(QDeclarativeInstruction::CreateObject);
980 create.create.line = obj->location.start.line;
981 create.create.column = obj->location.start.column;
982 create.create.data = -1;
983 if (!obj->custom.isEmpty())
984 create.create.data = output->indexForByteArray(obj->custom);
985 create.create.type = obj->type;
986 if (!output->types.at(create.create.type).type &&
987 !obj->bindingBitmask.isEmpty()) {
988 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
989 create.create.bindingBits =
990 output->indexForByteArray(obj->bindingBitmask);
992 create.create.bindingBits = -1;
994 output->addInstruction(create);
998 // Setup the synthesized meta object if necessary
999 if (!obj->metadata.isEmpty()) {
1000 QDeclarativeInstruction meta;
1001 meta.setType(QDeclarativeInstruction::StoreMetaObject);
1002 meta.storeMeta.data = output->indexForByteArray(obj->metadata);
1003 meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata);
1004 meta.storeMeta.propertyCache = output->propertyCaches.count();
1006 QDeclarativePropertyCache *propertyCache = obj->synthCache;
1007 Q_ASSERT(propertyCache);
1008 propertyCache->addref();
1010 // Add flag for alias properties
1011 if (!obj->synthdata.isEmpty()) {
1012 const QDeclarativeVMEMetaData *vmeMetaData =
1013 reinterpret_cast<const QDeclarativeVMEMetaData *>(obj->synthdata.constData());
1014 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
1015 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
1016 QDeclarativePropertyCache::Data *data = propertyCache->property(index);
1017 data->setFlags(data->getFlags() | QDeclarativePropertyCache::Data::IsAlias);
1021 if (obj == unitRoot) {
1022 propertyCache->addref();
1023 output->rootPropertyCache = propertyCache;
1026 output->propertyCaches << propertyCache;
1027 output->addInstruction(meta);
1028 } else if (obj == unitRoot) {
1029 output->rootPropertyCache = tr.createPropertyCache(engine);
1030 output->rootPropertyCache->addref();
1033 // Set the object id
1034 if (!obj->id.isEmpty()) {
1035 QDeclarativeInstruction id;
1036 id.setType(QDeclarativeInstruction::SetId);
1037 id.setId.value = output->indexForString(obj->id);
1038 id.setId.index = obj->idIndex;
1039 output->addInstruction(id);
1043 if (tr.type && obj->parserStatusCast != -1) {
1044 QDeclarativeInstruction begin;
1045 begin.setType(QDeclarativeInstruction::BeginObject);
1046 begin.begin.castValue = obj->parserStatusCast;
1047 output->addInstruction(begin);
1053 void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj)
1055 for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1056 Q_ASSERT(prop->scriptStringScope != -1);
1057 const QString &script = prop->values.first()->value.asScript();
1058 QDeclarativeInstruction ss;
1059 ss.setType(QDeclarativeInstruction::StoreScriptString);
1060 ss.storeScriptString.propertyIndex = prop->index;
1061 ss.storeScriptString.value = output->indexForString(script);
1062 ss.storeScriptString.scope = prop->scriptStringScope;
1063 // ss.storeScriptString.bindingId = rewriteBinding(script, prop->name());
1064 ss.storeScriptString.bindingId = rewriteBinding(script, QString()); // XXX
1065 ss.storeScriptString.line = prop->location.start.line;
1066 output->addInstruction(ss);
1069 bool seenDefer = false;
1070 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1071 if (prop->isDeferred) {
1076 genValueProperty(prop, obj);
1079 QDeclarativeInstruction defer;
1080 defer.setType(QDeclarativeInstruction::Defer);
1081 defer.defer.deferCount = 0;
1082 int deferIdx = output->addInstruction(defer);
1083 int nextInstructionIndex = output->nextInstructionIndex();
1085 QDeclarativeInstruction init;
1086 init.setType(QDeclarativeInstruction::Init);
1087 init.init.bindingsSize = compileState->bindings.count(); // XXX - bigger than necessary
1088 init.init.parserStatusSize = compileState->parserStatusCount; // XXX - bigger than necessary
1089 init.init.contextCache = -1;
1090 init.init.compiledBinding = -1;
1091 output->addInstruction(init);
1093 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1094 if (!prop->isDeferred)
1096 genValueProperty(prop, obj);
1099 QDeclarativeInstruction done;
1100 done.setType(QDeclarativeInstruction::Done);
1101 output->addInstruction(done);
1103 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1106 for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1108 QDeclarativeParser::Value *v = prop->values.first();
1110 if (v->type == Value::SignalObject) {
1112 genObject(v->object);
1114 QDeclarativeInstruction assign;
1115 assign.setType(QDeclarativeInstruction::AssignSignalObject);
1116 assign.assignSignalObject.line = v->location.start.line;
1117 assign.assignSignalObject.signal = output->indexForString(prop->name().toString());
1118 output->addInstruction(assign);
1120 } else if (v->type == Value::SignalExpression) {
1122 QDeclarativeInstruction store;
1123 store.setType(QDeclarativeInstruction::StoreSignal);
1124 store.storeSignal.signalIndex = prop->index;
1125 store.storeSignal.value =
1126 output->indexForString(v->value.asScript().trimmed());
1127 store.storeSignal.context = v->signalExpressionContextStack;
1128 store.storeSignal.name = output->indexForByteArray(prop->name().toUtf8());
1129 store.storeSignal.line = v->location.start.line;
1130 output->addInstruction(store);
1136 for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1137 QDeclarativeInstruction fetch;
1138 fetch.setType(QDeclarativeInstruction::FetchAttached);
1139 fetch.fetchAttached.id = prop->index;
1140 fetch.fetchAttached.line = prop->location.start.line;
1141 output->addInstruction(fetch);
1143 genObjectBody(prop->value);
1145 QDeclarativeInstruction pop;
1146 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1147 output->addInstruction(pop);
1150 for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1151 QDeclarativeInstruction fetch;
1152 fetch.setType(QDeclarativeInstruction::FetchObject);
1153 fetch.fetch.property = prop->index;
1154 fetch.fetch.line = prop->location.start.line;
1155 output->addInstruction(fetch);
1157 if (!prop->value->metadata.isEmpty()) {
1158 QDeclarativeInstruction meta;
1159 meta.setType(QDeclarativeInstruction::StoreMetaObject);
1160 meta.storeMeta.data = output->indexForByteArray(prop->value->metadata);
1161 meta.storeMeta.aliasData = output->indexForByteArray(prop->value->synthdata);
1162 meta.storeMeta.propertyCache = -1;
1163 output->addInstruction(meta);
1166 genObjectBody(prop->value);
1168 QDeclarativeInstruction pop;
1169 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1170 output->addInstruction(pop);
1173 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1175 genValueTypeProperty(obj, prop);
1178 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1179 if (prop->isDeferred)
1182 genValueProperty(prop, obj);
1185 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1187 genValueTypeProperty(obj, prop);
1191 void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeParser::Object *obj,QDeclarativeParser::Property *prop)
1193 QDeclarativeInstruction fetch;
1194 fetch.setType(QDeclarativeInstruction::FetchValueType);
1195 fetch.fetchValue.property = prop->index;
1196 fetch.fetchValue.type = prop->type;
1197 fetch.fetchValue.bindingSkipList = 0;
1199 if (obj->type == -1 || output->types.at(obj->type).component) {
1200 // We only have to do this if this is a composite type. If it is a builtin
1201 // type it can't possibly already have bindings that need to be cleared.
1202 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1203 if (!vprop->values.isEmpty()) {
1204 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1205 fetch.fetchValue.bindingSkipList |= (1 << vprop->index);
1210 output->addInstruction(fetch);
1212 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1213 genPropertyAssignment(vprop, prop->value, prop);
1216 QDeclarativeInstruction pop;
1217 pop.setType(QDeclarativeInstruction::PopValueType);
1218 pop.fetchValue.property = prop->index;
1219 pop.fetchValue.type = prop->type;
1220 pop.fetchValue.bindingSkipList = 0;
1221 output->addInstruction(pop);
1224 void QDeclarativeCompiler::genComponent(QDeclarativeParser::Object *obj)
1226 QDeclarativeParser::Object *root = obj->defaultProperty->values.first()->object;
1229 QDeclarativeInstruction create;
1230 create.setType(QDeclarativeInstruction::CreateComponent);
1231 create.createComponent.line = root->location.start.line;
1232 create.createComponent.column = root->location.start.column;
1233 create.createComponent.endLine = root->location.end.line;
1234 int createInstruction = output->addInstruction(create);
1235 int nextInstructionIndex = output->nextInstructionIndex();
1237 ComponentCompileState *oldCompileState = compileState;
1238 compileState = componentState(root);
1240 QDeclarativeInstruction init;
1241 init.setType(QDeclarativeInstruction::Init);
1242 init.init.bindingsSize = compileState->bindings.count();
1243 init.init.parserStatusSize = compileState->parserStatusCount;
1244 init.init.contextCache = genContextCache();
1245 if (compileState->compiledBindingData.isEmpty())
1246 init.init.compiledBinding = -1;
1248 init.init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
1249 output->addInstruction(init);
1251 if (!compileState->v8BindingProgram.isEmpty()) {
1252 QDeclarativeInstruction bindings;
1253 bindings.setType(QDeclarativeInstruction::InitV8Bindings);
1254 bindings.initV8Bindings.program = output->indexForString(compileState->v8BindingProgram);
1255 bindings.initV8Bindings.programIndex = compileState->v8BindingProgramIndex;
1256 bindings.initV8Bindings.line = compileState->v8BindingProgramLine;
1257 output->addInstruction(bindings);
1262 QDeclarativeInstruction def;
1263 def.setType(QDeclarativeInstruction::SetDefault);
1264 output->addInstruction(def);
1266 QDeclarativeInstruction done;
1267 done.setType(QDeclarativeInstruction::Done);
1268 output->addInstruction(done);
1270 output->instruction(createInstruction)->createComponent.count =
1271 output->nextInstructionIndex() - nextInstructionIndex;
1273 compileState = oldCompileState;
1275 if (!obj->id.isEmpty()) {
1276 QDeclarativeInstruction id;
1277 id.setType(QDeclarativeInstruction::SetId);
1278 id.setId.value = output->indexForString(obj->id);
1279 id.setId.index = obj->idIndex;
1280 output->addInstruction(id);
1283 if (obj == unitRoot) {
1284 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1285 output->rootPropertyCache->addref();
1289 bool QDeclarativeCompiler::buildComponent(QDeclarativeParser::Object *obj,
1290 const BindingContext &ctxt)
1292 // The special "Component" element can only have the id property and a
1293 // default property, that actually defines the component's tree
1295 // Find, check and set the "id" property (if any)
1296 Property *idProp = 0;
1297 if (obj->properties.isMany() ||
1298 (obj->properties.isOne() && obj->properties.first()->name() != id_string))
1299 COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
1301 if (!obj->properties.isEmpty())
1302 idProp = obj->properties.first();
1305 if (idProp->value || idProp->values.isMany() || idProp->values.first()->object)
1306 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1307 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1309 QString idVal = idProp->values.first()->primitive();
1311 if (compileState->ids.value(idVal))
1312 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1318 // Check the Component tree is well formed
1319 if (obj->defaultProperty &&
1320 (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
1321 (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
1322 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1324 if (!obj->dynamicProperties.isEmpty())
1325 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1326 if (!obj->dynamicSignals.isEmpty())
1327 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1328 if (!obj->dynamicSlots.isEmpty())
1329 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1331 QDeclarativeParser::Object *root = 0;
1332 if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
1333 root = obj->defaultProperty->values.first()->object;
1336 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1338 // Build the component tree
1339 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1344 bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeParser::Object *obj,
1345 const BindingContext &ctxt)
1347 ComponentCompileState *oldComponentCompileState = compileState;
1348 compileState = pool->New<ComponentCompileState>();
1349 compileState->root = obj;
1350 compileState->nested = true;
1352 if (componentStats) {
1353 ComponentStat oldComponentStat = componentStats->componentStat;
1355 componentStats->componentStat = ComponentStat();
1356 componentStats->componentStat.lineNumber = obj->location.start.line;
1359 COMPILE_CHECK(buildObject(obj, ctxt));
1361 COMPILE_CHECK(completeComponentBuild());
1363 componentStats->componentStat = oldComponentStat;
1366 COMPILE_CHECK(buildObject(obj, ctxt));
1368 COMPILE_CHECK(completeComponentBuild());
1371 compileState = oldComponentCompileState;
1377 // Build a sub-object. A sub-object is one that was not created directly by
1378 // QML - such as a grouped property object, or an attached object. Sub-object's
1379 // can't have an id, involve a custom parser, have attached properties etc.
1380 bool QDeclarativeCompiler::buildSubObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
1382 Q_ASSERT(obj->metatype);
1383 Q_ASSERT(!obj->defaultProperty);
1384 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1387 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1388 if (isSignalPropertyName(prop->name())) {
1389 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1391 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1398 int QDeclarativeCompiler::componentTypeRef()
1400 QDeclarativeType *t = QDeclarativeMetaType::qmlType("QtQuick/Component",2,0);
1401 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1402 if (output->types.at(ii).type == t)
1405 QDeclarativeCompiledData::TypeReference ref;
1406 ref.className = Component_string;
1408 output->types << ref;
1409 return output->types.count() - 1;
1412 bool QDeclarativeCompiler::buildSignal(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj,
1413 const BindingContext &ctxt)
1415 Q_ASSERT(obj->metaObject());
1417 const QHashedStringRef &propName = prop->name();
1419 Q_ASSERT(propName.startsWith(on_string));
1420 QString name = propName.mid(2, -1).toString();
1422 // Note that the property name could start with any alpha or '_' or '$' character,
1423 // so we need to do the lower-casing of the first alpha character.
1424 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1425 if (QDeclarativeUtils::isUpper(name.at(firstAlphaIndex))) {
1426 name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1431 bool notInRevision = false;
1433 QDeclarativePropertyCache::Data *sig = signal(obj, QStringRef(&name), ¬InRevision);
1437 if (notInRevision && 0 == property(obj, propName, 0)) {
1438 Q_ASSERT(obj->type != -1);
1439 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1440 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1442 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));
1444 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1448 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1450 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1454 if (prop->value || !prop->values.isOne())
1455 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1457 prop->index = sig->coreIndex;
1460 obj->addSignalProperty(prop);
1462 if (prop->values.first()->object) {
1463 COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1464 prop->values.first()->type = Value::SignalObject;
1466 prop->values.first()->type = Value::SignalExpression;
1468 if (!prop->values.first()->value.isScript())
1469 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1471 QString script = prop->values.first()->value.asScript().trimmed();
1472 if (script.isEmpty())
1473 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1475 prop->values.first()->signalExpressionContextStack = ctxt.stack;
1484 Returns true if (value) property \a prop exists on obj, false otherwise.
1486 bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeParser::Property *prop,
1487 QDeclarativeParser::Object *obj)
1489 if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1492 if (prop->isDefault) {
1493 const QMetaObject *mo = obj->metaObject();
1494 QMetaProperty p = QDeclarativeMetaType::defaultProperty(mo);
1495 return p.name() != 0;
1497 return property(obj, prop->name()) != 0;
1501 bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop,
1502 QDeclarativeParser::Object *obj,
1503 const BindingContext &ctxt)
1505 if (prop->isEmpty())
1506 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1508 const QMetaObject *metaObject = obj->metaObject();
1509 Q_ASSERT(metaObject);
1511 if (isAttachedPropertyName(prop->name())) {
1512 // Setup attached property data
1514 if (ctxt.isSubContext()) {
1515 // Attached properties cannot be used on sub-objects. Sub-objects
1516 // always exist in a binding sub-context, which is what we test
1518 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1521 QDeclarativeType *type = 0;
1522 QDeclarativeImportedNamespace *typeNamespace = 0;
1523 unit->imports().resolveType(prop->name().toUtf8(), &type, 0, 0, 0, &typeNamespace);
1525 if (typeNamespace) {
1526 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1529 } else if (!type || !type->attachedPropertiesType()) {
1530 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1534 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1536 Q_ASSERT(type->attachedPropertiesFunction());
1537 prop->index = type->attachedPropertiesId();
1538 prop->value->metatype = type->attachedPropertiesType();
1540 // Setup regular property data
1542 if (prop->isDefault) {
1543 QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
1546 prop->setName(QString::fromLatin1(p.name()));
1548 QDeclarativePropertyCache::Data *d = property(obj, p.propertyIndex());
1549 prop->index = d->coreIndex;
1554 bool notInRevision = false;
1555 QDeclarativePropertyCache::Data *d = property(obj, prop->name(), ¬InRevision);
1557 if (d == 0 && notInRevision) {
1558 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1559 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1561 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));
1563 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1566 prop->index = d->coreIndex;
1571 // We can't error here as the "id" property does not require a
1572 // successful index resolution
1573 if (prop->index != -1)
1574 prop->type = prop->core.propType;
1576 // Check if this is an alias
1577 if (prop->index != -1 &&
1579 prop->parent->type != -1 &&
1580 output->types.at(prop->parent->type).component) {
1582 QDeclarativePropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1583 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1584 prop->isAlias = true;
1587 if (prop->index != -1 && !prop->values.isEmpty())
1588 prop->parent->setBindingBit(prop->index);
1591 if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1593 // The magic "id" behavior doesn't apply when "id" is resolved as a
1594 // default property or to sub-objects (which are always in binding
1596 COMPILE_CHECK(buildIdProperty(prop, obj));
1597 if (prop->type == QVariant::String &&
1598 prop->values.first()->value.isString())
1599 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1601 } else if (isAttachedPropertyName(prop->name())) {
1603 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1605 } else if (prop->index == -1) {
1607 if (prop->isDefault) {
1608 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1610 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1613 } else if (prop->value) {
1615 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1617 } else if (prop->core.isQList()) {
1619 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1621 } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) {
1623 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1627 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1634 bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
1635 QDeclarativeParser::Property *nsProp,
1636 QDeclarativeParser::Object *obj,
1637 const BindingContext &ctxt)
1640 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1642 for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1644 if (!isAttachedPropertyName(prop->name()))
1645 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1647 // Setup attached property data
1649 QDeclarativeType *type = 0;
1650 unit->imports().resolveType(ns, prop->name().toUtf8(), &type, 0, 0, 0);
1652 if (!type || !type->attachedPropertiesType())
1653 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1656 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1658 Q_ASSERT(type->attachedPropertiesFunction());
1659 prop->index = type->index();
1660 prop->value->metatype = type->attachedPropertiesType();
1662 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1668 void QDeclarativeCompiler::genValueProperty(QDeclarativeParser::Property *prop,
1669 QDeclarativeParser::Object *obj)
1671 if (prop->core.isQList()) {
1672 genListProperty(prop, obj);
1674 genPropertyAssignment(prop, obj);
1678 void QDeclarativeCompiler::genListProperty(QDeclarativeParser::Property *prop,
1679 QDeclarativeParser::Object *obj)
1681 int listType = enginePrivate->listType(prop->type);
1683 QDeclarativeInstruction fetch;
1684 fetch.setType(QDeclarativeInstruction::FetchQList);
1685 fetch.fetchQmlList.property = prop->index;
1686 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1687 fetch.fetchQmlList.type = listType;
1688 output->addInstruction(fetch);
1690 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1692 if (v->type == Value::CreatedObject) {
1694 genObject(v->object);
1695 if (listTypeIsInterface) {
1696 QDeclarativeInstruction assign;
1697 assign.setType(QDeclarativeInstruction::AssignObjectList);
1698 assign.assignObjectList.line = prop->location.start.line;
1699 output->addInstruction(assign);
1701 QDeclarativeInstruction store;
1702 store.setType(QDeclarativeInstruction::StoreObjectQList);
1703 output->addInstruction(store);
1706 } else if (v->type == Value::PropertyBinding) {
1708 genBindingAssignment(v, prop, obj);
1714 QDeclarativeInstruction pop;
1715 pop.setType(QDeclarativeInstruction::PopQList);
1716 output->addInstruction(pop);
1719 void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *prop,
1720 QDeclarativeParser::Object *obj,
1721 QDeclarativeParser::Property *valueTypeProperty)
1723 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1725 Q_ASSERT(v->type == Value::CreatedObject ||
1726 v->type == Value::PropertyBinding ||
1727 v->type == Value::Literal);
1729 if (v->type == Value::CreatedObject) {
1731 genObject(v->object);
1733 if (QDeclarativeMetaType::isInterface(prop->type)) {
1735 QDeclarativeInstruction store;
1736 store.setType(QDeclarativeInstruction::StoreInterface);
1737 store.storeObject.line = v->object->location.start.line;
1738 store.storeObject.propertyIndex = prop->index;
1739 output->addInstruction(store);
1741 } else if (prop->type == QMetaType::QVariant) {
1743 QDeclarativeInstruction store;
1744 store.setType(QDeclarativeInstruction::StoreVariantObject);
1745 store.storeObject.line = v->object->location.start.line;
1746 store.storeObject.propertyIndex = prop->index;
1747 output->addInstruction(store);
1751 QDeclarativeInstruction store;
1752 store.setType(QDeclarativeInstruction::StoreObject);
1753 store.storeObject.line = v->object->location.start.line;
1754 store.storeObject.propertyIndex = prop->index;
1755 output->addInstruction(store);
1758 } else if (v->type == Value::PropertyBinding) {
1760 genBindingAssignment(v, prop, obj, valueTypeProperty);
1762 } else if (v->type == Value::Literal) {
1764 genLiteralAssignment(prop, v);
1770 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
1772 Q_ASSERT(v->type == Value::ValueSource ||
1773 v->type == Value::ValueInterceptor);
1775 if (v->type == Value::ValueSource) {
1776 genObject(v->object);
1778 QDeclarativeInstruction store;
1779 store.setType(QDeclarativeInstruction::StoreValueSource);
1780 if (valueTypeProperty) {
1781 store.assignValueSource.property = genValueTypeData(prop, valueTypeProperty);
1782 store.assignValueSource.owner = 1;
1784 store.assignValueSource.property = genPropertyData(prop);
1785 store.assignValueSource.owner = 0;
1787 QDeclarativeType *valueType = toQmlType(v->object);
1788 store.assignValueSource.castValue = valueType->propertyValueSourceCast();
1789 output->addInstruction(store);
1791 } else if (v->type == Value::ValueInterceptor) {
1792 genObject(v->object);
1794 QDeclarativeInstruction store;
1795 store.setType(QDeclarativeInstruction::StoreValueInterceptor);
1796 if (valueTypeProperty) {
1797 store.assignValueInterceptor.property = genValueTypeData(prop, valueTypeProperty);
1798 store.assignValueInterceptor.owner = 1;
1800 store.assignValueInterceptor.property = genPropertyData(prop);
1801 store.assignValueInterceptor.owner = 0;
1803 QDeclarativeType *valueType = toQmlType(v->object);
1804 store.assignValueInterceptor.castValue = valueType->propertyValueInterceptorCast();
1805 output->addInstruction(store);
1811 bool QDeclarativeCompiler::buildIdProperty(QDeclarativeParser::Property *prop,
1812 QDeclarativeParser::Object *obj)
1815 prop->values.isMany() ||
1816 prop->values.first()->object)
1817 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
1819 QDeclarativeParser::Value *idValue = prop->values.first();
1820 QString val = idValue->primitive();
1822 COMPILE_CHECK(checkValidId(idValue, val));
1824 if (compileState->ids.value(val))
1825 COMPILE_EXCEPTION(prop, tr("id is not unique"));
1827 prop->values.first()->type = Value::Id;
1835 void QDeclarativeCompiler::addId(const QString &id, QDeclarativeParser::Object *obj)
1837 Q_ASSERT(!compileState->ids.value(id));
1838 Q_ASSERT(obj->id == id);
1839 obj->idIndex = compileState->ids.count();
1840 compileState->ids.append(obj);
1843 void QDeclarativeCompiler::addBindingReference(BindingReference *ref)
1845 Q_ASSERT(ref->value && !ref->value->bindingReference);
1846 ref->value->bindingReference = ref;
1847 compileState->bindings.prepend(ref);
1850 void QDeclarativeCompiler::saveComponentState()
1852 Q_ASSERT(compileState->root);
1853 Q_ASSERT(compileState->root->componentCompileState == 0);
1855 compileState->root->componentCompileState = compileState;
1858 componentStats->savedComponentStats.append(componentStats->componentStat);
1861 QDeclarativeCompilerTypes::ComponentCompileState *
1862 QDeclarativeCompiler::componentState(QDeclarativeParser::Object *obj)
1864 Q_ASSERT(obj->componentCompileState);
1865 return obj->componentCompileState;
1868 // Build attached property object. In this example,
1872 // GridView is an attached property object.
1873 bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeParser::Property *prop,
1874 QDeclarativeParser::Object *obj,
1875 const BindingContext &ctxt)
1877 Q_ASSERT(prop->value);
1878 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
1880 obj->addAttachedProperty(prop);
1882 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1888 // Build "grouped" properties. In this example:
1890 // font.pointSize: 12
1891 // font.family: "Helvetica"
1893 // font is a nested property. pointSize and family are not.
1894 bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeParser::Property *prop,
1895 QDeclarativeParser::Object *obj,
1896 const BindingContext &ctxt)
1898 Q_ASSERT(prop->type != 0);
1899 Q_ASSERT(prop->index != -1);
1901 if (QDeclarativeValueTypeFactory::isValueType(prop->type)) {
1902 if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
1904 if (!prop->values.isEmpty()) {
1905 if (prop->values.first()->location < prop->value->location) {
1906 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
1908 COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
1912 if (!obj->metaObject()->property(prop->index).isWritable()) {
1913 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
1917 if (prop->isAlias) {
1918 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
1919 vtProp->isAlias = true;
1923 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
1924 prop->value, obj, ctxt.incr()));
1925 obj->addValueTypeProperty(prop);
1927 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1931 // Load the nested property's meta type
1932 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
1933 if (!prop->value->metatype)
1934 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1936 if (!prop->values.isEmpty())
1937 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
1939 obj->addGroupedProperty(prop);
1941 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1947 bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
1948 QDeclarativeParser::Object *obj,
1949 QDeclarativeParser::Object *baseObj,
1950 const BindingContext &ctxt)
1952 if (obj->defaultProperty)
1953 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
1954 obj->metatype = type->metaObject();
1956 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1958 QDeclarativePropertyCache::Data *d = property(obj, prop->name());
1960 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1962 prop->index = d->coreIndex;
1963 prop->type = d->propType;
1965 prop->isValueTypeSubProperty = true;
1968 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
1970 if (prop->values.isMany()) {
1971 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
1972 } else if (!prop->values.isEmpty()) {
1973 QDeclarativeParser::Value *value = prop->values.first();
1975 if (value->object) {
1976 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
1977 } else if (value->value.isScript()) {
1978 // ### Check for writability
1980 //optimization for <Type>.<EnumValue> enum assignments
1981 bool isEnumAssignment = false;
1983 if (prop->core.isEnum())
1984 COMPILE_CHECK(testQualifiedEnumAssignment(obj->metatype->property(prop->index), obj,
1985 value, &isEnumAssignment));
1987 if (isEnumAssignment) {
1988 value->type = Value::Literal;
1990 BindingReference *reference = pool->New<BindingReference>();
1991 reference->expression = value->value;
1992 reference->property = prop;
1993 reference->value = value;
1994 reference->bindingContext = ctxt;
1995 reference->bindingContext.owner++;
1996 addBindingReference(reference);
1997 value->type = Value::PropertyBinding;
2000 COMPILE_CHECK(testLiteralAssignment(prop, value));
2001 value->type = Value::Literal;
2005 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2006 Q_ASSERT(v->object);
2008 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
2011 obj->addValueProperty(prop);
2017 // Build assignments to QML lists. QML lists are properties of type
2018 // QDeclarativeListProperty<T>. List properties can accept a list of
2019 // objects, or a single binding.
2020 bool QDeclarativeCompiler::buildListProperty(QDeclarativeParser::Property *prop,
2021 QDeclarativeParser::Object *obj,
2022 const BindingContext &ctxt)
2024 Q_ASSERT(prop->core.isQList());
2028 obj->addValueProperty(prop);
2030 int listType = enginePrivate->listType(t);
2031 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
2033 bool assignedBinding = false;
2034 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2036 v->type = Value::CreatedObject;
2037 COMPILE_CHECK(buildObject(v->object, ctxt));
2039 // We check object coercian here. We check interface assignment
2041 if (!listTypeIsInterface) {
2042 if (!canCoerce(listType, v->object)) {
2043 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2047 } else if (v->value.isScript()) {
2048 if (assignedBinding)
2049 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2051 assignedBinding = true;
2052 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2053 v->type = Value::PropertyBinding;
2055 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2062 // Compiles an assignment to a QDeclarativeScriptString property
2063 bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeParser::Property *prop,
2064 QDeclarativeParser::Object *obj,
2065 const BindingContext &ctxt)
2067 if (prop->values.isMany())
2068 COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2070 if (prop->values.first()->object)
2071 COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2073 prop->scriptStringScope = ctxt.stack;
2074 obj->addScriptStringProperty(prop);
2079 // Compile regular property assignments of the form "property: <value>"
2080 bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeParser::Property *prop,
2081 QDeclarativeParser::Object *obj,
2082 const BindingContext &ctxt)
2084 obj->addValueProperty(prop);
2086 if (prop->values.isMany())
2087 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2089 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2092 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2096 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2101 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2102 Q_ASSERT(v->object);
2103 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2109 // Compile assigning a single object instance to a regular property
2110 bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeParser::Property *prop,
2111 QDeclarativeParser::Object *obj,
2112 QDeclarativeParser::Value *v,
2113 const BindingContext &ctxt)
2115 Q_ASSERT(prop->index != -1);
2116 Q_ASSERT(v->object->type != -1);
2118 if (!obj->metaObject()->property(prop->index).isWritable())
2119 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2121 if (QDeclarativeMetaType::isInterface(prop->type)) {
2123 // Assigning an object to an interface ptr property
2124 COMPILE_CHECK(buildObject(v->object, ctxt));
2126 v->type = Value::CreatedObject;
2128 } else if (prop->type == QMetaType::QVariant) {
2130 // Assigning an object to a QVariant
2131 COMPILE_CHECK(buildObject(v->object, ctxt));
2133 v->type = Value::CreatedObject;
2135 // Normally buildObject() will set this up, but we need the static
2136 // meta object earlier to test for assignability. It doesn't matter
2137 // that there may still be outstanding synthesized meta object changes
2138 // on this type, as they are not relevant for assignability testing
2139 v->object->metatype = output->types.at(v->object->type).metaObject();
2140 Q_ASSERT(v->object->metaObject());
2142 // We want to raw metaObject here as the raw metaobject is the
2143 // actual property type before we applied any extensions that might
2144 // effect the properties on the type, but don't effect assignability
2145 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2147 // Will be true if the assgned type inherits propertyMetaObject
2148 bool isAssignable = false;
2149 // Determine isAssignable value
2150 if (propertyMetaObject) {
2151 const QMetaObject *c = v->object->metatype;
2153 isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject));
2154 c = c->superClass();
2159 // Simple assignment
2160 COMPILE_CHECK(buildObject(v->object, ctxt));
2162 v->type = Value::CreatedObject;
2163 } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) {
2164 // Automatic "Component" insertion
2165 QDeclarativeParser::Object *root = v->object;
2166 QDeclarativeParser::Object *component = pool->New<Object>();
2167 component->type = componentTypeRef();
2168 component->typeName = "Qt/Component";
2169 component->metatype = &QDeclarativeComponent::staticMetaObject;
2170 component->location = root->location;
2171 QDeclarativeParser::Value *componentValue = pool->New<Value>();
2172 componentValue->object = root;
2173 component->getDefaultProperty()->addValue(componentValue);
2174 v->object = component;
2175 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2177 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2184 // Compile assigning a single object instance to a regular property using the "on" syntax.
2188 // NumberAnimation on x { }
2190 bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeParser::Property *prop,
2191 QDeclarativeParser::Object *obj,
2192 QDeclarativeParser::Object *baseObj,
2193 QDeclarativeParser::Value *v,
2194 const BindingContext &ctxt)
2196 Q_ASSERT(prop->index != -1);
2197 Q_ASSERT(v->object->type != -1);
2199 if (!obj->metaObject()->property(prop->index).isWritable())
2200 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2203 // Normally buildObject() will set this up, but we need the static
2204 // meta object earlier to test for assignability. It doesn't matter
2205 // that there may still be outstanding synthesized meta object changes
2206 // on this type, as they are not relevant for assignability testing
2207 v->object->metatype = output->types.at(v->object->type).metaObject();
2208 Q_ASSERT(v->object->metaObject());
2210 // Will be true if the assigned type inherits QDeclarativePropertyValueSource
2211 bool isPropertyValue = false;
2212 // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor
2213 bool isPropertyInterceptor = false;
2214 if (QDeclarativeType *valueType = toQmlType(v->object)) {
2215 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2216 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2219 if (isPropertyValue || isPropertyInterceptor) {
2220 // Assign as a property value source
2221 COMPILE_CHECK(buildObject(v->object, ctxt));
2223 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2224 buildDynamicMeta(baseObj, ForceCreation);
2225 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2227 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(QString::fromUtf8(v->object->typeName)).arg(prop->name().toString()));
2233 // Compile assigning a literal or binding to a regular property
2234 bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeParser::Property *prop,
2235 QDeclarativeParser::Object *obj,
2236 QDeclarativeParser::Value *v,
2237 const BindingContext &ctxt)
2239 Q_ASSERT(prop->index != -1);
2241 if (v->value.isScript()) {
2243 //optimization for <Type>.<EnumValue> enum assignments
2244 if (prop->core.isEnum()) {
2245 bool isEnumAssignment = false;
2246 COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj,
2247 v, &isEnumAssignment));
2248 if (isEnumAssignment) {
2249 v->type = Value::Literal;
2254 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2256 v->type = Value::PropertyBinding;
2260 COMPILE_CHECK(testLiteralAssignment(prop, v));
2262 v->type = Value::Literal;
2268 bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop,
2269 QDeclarativeParser::Object *obj,
2270 QDeclarativeParser::Value *v,
2273 *isAssignment = false;
2274 if (!prop.isEnumType())
2277 if (!prop.isWritable())
2278 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
2280 QString string = v->value.asString();
2281 if (!QDeclarativeUtils::isUpper(string.at(0)))
2284 QStringList parts = string.split(QLatin1Char('.'));
2285 if (parts.count() != 2)
2288 QString typeName = parts.at(0);
2289 QDeclarativeType *type = 0;
2290 unit->imports().resolveType(typeName.toUtf8(), &type, 0, 0, 0, 0);
2292 //handle enums on value types (where obj->typeName is empty)
2293 QByteArray objTypeName = obj->typeName;
2294 if (objTypeName.isEmpty()) {
2295 QDeclarativeType *objType = toQmlType(obj);
2297 objTypeName = objType->qmlTypeName();
2303 QString enumValue = parts.at(1);
2306 if (objTypeName == type->qmlTypeName()) {
2307 // When these two match, we can short cut the search
2308 if (prop.isFlagType()) {
2309 value = prop.enumerator().keysToValue(enumValue.toUtf8().constData());
2311 value = prop.enumerator().keyToValue(enumValue.toUtf8().constData());
2314 // Otherwise we have to search the whole type
2315 // This matches the logic in QV8TypeWrapper
2316 QByteArray enumName = enumValue.toUtf8();
2317 const QMetaObject *metaObject = type->baseMetaObject();
2318 for (int ii = metaObject->enumeratorCount() - 1; value == -1 && ii >= 0; --ii) {
2319 QMetaEnum e = metaObject->enumerator(ii);
2320 value = e.keyToValue(enumName.constData());
2327 v->type = Value::Literal;
2328 v->value = QDeclarativeParser::Variant((double)value);
2329 *isAssignment = true;
2334 struct StaticQtMetaObject : public QObject
2336 static const QMetaObject *get()
2337 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2340 // Similar logic to above, but not knowing target property.
2341 int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const
2343 int dot = script.indexOf('.');
2345 const QByteArray &scope = script.left(dot);
2346 QDeclarativeType *type = 0;
2347 unit->imports().resolveType(scope, &type, 0, 0, 0, 0);
2348 if (!type && scope != "Qt")
2350 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2351 const char *key = script.constData() + dot+1;
2352 int i = mo->enumeratorCount();
2354 int v = mo->enumerator(i).keyToValue(key);
2362 const QMetaObject *QDeclarativeCompiler::resolveType(const QByteArray& name) const
2364 QDeclarativeType *qmltype = 0;
2365 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2369 return qmltype->metaObject();
2372 // similar to logic of completeComponentBuild, but also sticks data
2373 // into primitives at the end
2374 int QDeclarativeCompiler::rewriteBinding(const QString& expression, const QString& name)
2376 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2377 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf('.') + 1));
2379 QString rewrite = rewriteBinding(expression, 0, 0);
2381 return output->indexForString(rewrite);
2384 // Ensures that the dynamic meta specification on obj is valid
2385 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj)
2387 bool seenDefaultProperty = false;
2389 // We use a coarse grain, 31 bit hash to check if there are duplicates.
2390 // Calculating the hash for the names is not a waste as we have to test
2391 // them against the illegalNames set anyway.
2392 QHashField propNames;
2393 QHashField methodNames;
2396 int dpCount = obj->dynamicProperties.count();
2397 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2398 const QDeclarativeParser::Object::DynamicProperty &prop = *p;
2400 if (prop.isDefaultProperty) {
2401 if (seenDefaultProperty)
2402 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2403 seenDefaultProperty = true;
2406 if (propNames.testAndSet(prop.name.hash())) {
2407 for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p;
2408 p2 = obj->dynamicProperties.next(p2)) {
2409 if (p2->name == prop.name)
2410 COMPILE_EXCEPTION(&prop, tr("Duplicate property name"));
2414 if (QDeclarativeUtils::isUpper(prop.name.at(0)))
2415 COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
2417 if (enginePrivate->v8engine()->illegalNames().contains(prop.name))
2418 COMPILE_EXCEPTION(&prop, tr("Illegal property name"));
2421 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2422 const QDeclarativeScript::Object::DynamicSignal &currSig = *s;
2424 if (methodNames.testAndSet(currSig.name.hash())) {
2425 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2426 s2 = obj->dynamicSignals.next(s2)) {
2427 if (s2->name == currSig.name)
2428 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2432 if (currSig.name.at(0).isUpper())
2433 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2434 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2435 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2438 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2439 const QDeclarativeScript::Object::DynamicSlot &currSlot = *s;
2441 if (methodNames.testAndSet(currSlot.name.hash())) {
2442 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2443 s2 = obj->dynamicSignals.next(s2)) {
2444 if (s2->name == currSlot.name)
2445 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2447 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2448 s2 = obj->dynamicSlots.next(s2)) {
2449 if (s2->name == currSlot.name)
2450 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2454 if (currSlot.name.at(0).isUpper())
2455 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2456 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2457 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2463 bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeParser::Object *obj)
2465 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2467 if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2470 Property *property = 0;
2471 if (p->isDefaultProperty) {
2472 property = obj->getDefaultProperty();
2474 property = obj->getProperty(p->name);
2475 if (!property->values.isEmpty())
2476 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2479 if (property->value)
2480 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2482 property->values.append(p->defaultValue->values);
2487 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2489 bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, DynamicMetaMode mode)
2492 Q_ASSERT(obj->metatype);
2494 if (mode != ForceCreation &&
2495 obj->dynamicProperties.isEmpty() &&
2496 obj->dynamicSignals.isEmpty() &&
2497 obj->dynamicSlots.isEmpty())
2500 bool resolveAlias = (mode == ResolveAliases);
2502 const Object::DynamicProperty *defaultProperty = 0;
2505 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2507 if (p->type == Object::DynamicProperty::Alias)
2510 if (p->isDefaultProperty &&
2511 (resolveAlias || p->type != Object::DynamicProperty::Alias))
2512 defaultProperty = p;
2514 if (!resolveAlias) {
2515 // No point doing this for both the alias and non alias cases
2516 QDeclarativePropertyCache::Data *d = property(obj, p->name);
2517 if (d && d->isFinal())
2518 COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2522 bool buildData = resolveAlias || aliasCount == 0;
2524 QByteArray dynamicData;
2526 typedef QDeclarativeVMEMetaData VMD;
2528 dynamicData = QByteArray(sizeof(QDeclarativeVMEMetaData) +
2529 (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) +
2530 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2531 aliasCount * sizeof(VMD::AliasData), 0);
2534 int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1);
2536 QByteArray newClassName = obj->metatype->className();
2537 newClassName.append("_QML_");
2538 newClassName.append(QByteArray::number(uniqueClassId));
2540 if (compileState->root == obj && !compileState->nested) {
2541 QString path = output->url.path();
2542 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2543 if (lastSlash > -1) {
2544 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2545 if (!nameBase.isEmpty() && QDeclarativeUtils::isUpper(nameBase.at(0)))
2546 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId);
2550 QFastMetaBuilder builder;
2551 QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(),
2552 obj->dynamicProperties.count() - (resolveAlias?0:aliasCount),
2553 obj->dynamicSlots.count(),
2554 obj->dynamicSignals.count() + obj->dynamicProperties.count(),
2555 defaultProperty?1:0);
2558 Object::DynamicProperty::Type dtype;
2560 const char *cppType;
2561 } builtinTypes[] = {
2562 { Object::DynamicProperty::Variant, 0, "QVariant" },
2563 { Object::DynamicProperty::Int, QMetaType::Int, "int" },
2564 { Object::DynamicProperty::Bool, QMetaType::Bool, "bool" },
2565 { Object::DynamicProperty::Real, QMetaType::Double, "double" },
2566 { Object::DynamicProperty::String, QMetaType::QString, "QString" },
2567 { Object::DynamicProperty::Url, QMetaType::QUrl, "QUrl" },
2568 { Object::DynamicProperty::Color, QMetaType::QColor, "QColor" },
2569 { Object::DynamicProperty::Time, QMetaType::QTime, "QTime" },
2570 { Object::DynamicProperty::Date, QMetaType::QDate, "QDate" },
2571 { Object::DynamicProperty::DateTime, QMetaType::QDateTime, "QDateTime" },
2573 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2574 QFastMetaBuilder::StringRef typeRefs[builtinTypeCount];
2576 // Reserve dynamic properties
2577 if (obj->dynamicProperties.count()) {
2578 typedef QDeclarativeVMEMetaData VMD;
2580 int effectivePropertyIndex = 0;
2581 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2583 // Reserve space for name
2584 p->nameRef = builder.newString(p->name.utf8length());
2586 int propertyType = 0;
2587 bool readonly = false;
2588 QFastMetaBuilder::StringRef typeRef;
2590 if (p->type == Object::DynamicProperty::Alias) {
2592 } else if (p->type < builtinTypeCount) {
2593 Q_ASSERT(builtinTypes[p->type].dtype == p->type);
2594 propertyType = builtinTypes[p->type].metaType;
2595 if (typeRefs[p->type].isEmpty())
2596 typeRefs[p->type] = builder.newString(strlen(builtinTypes[p->type].cppType));
2597 typeRef = typeRefs[p->type];
2598 if (p->type == Object::DynamicProperty::Variant)
2599 propertyType = qMetaTypeId<QVariant>();
2602 Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
2603 p->type == Object::DynamicProperty::Custom);
2605 // XXX don't double resolve this in the case of an alias run
2607 QByteArray customTypeName;
2608 QDeclarativeType *qmltype = 0;
2610 if (!unit->imports().resolveType(p->customType.toUtf8(), &qmltype, &url, 0, 0, 0))
2611 COMPILE_EXCEPTION(p, tr("Invalid property type"));
2614 QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(QUrl(url));
2616 Q_ASSERT(tdata->isComplete());
2618 QDeclarativeCompiledData *data = tdata->compiledData();
2619 customTypeName = data->root->className();
2623 customTypeName = qmltype->typeName();
2626 if (p->type == Object::DynamicProperty::Custom) {
2627 customTypeName += '*';
2628 propertyType = QMetaType::QObjectStar;
2631 customTypeName = QByteArray("QDeclarativeListProperty<") + customTypeName + QByteArray(">");
2632 propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
2635 p->resolvedCustomTypeName = pool->NewByteArray(customTypeName);
2636 p->typeRef = builder.newString(customTypeName.length());
2637 typeRef = p->typeRef;
2641 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2642 vmd->propertyCount++;
2643 (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType;
2646 if (p->type < builtinTypeCount)
2647 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef, (QMetaType::Type)propertyType,
2648 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2649 effectivePropertyIndex);
2651 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef,
2652 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2653 effectivePropertyIndex);
2655 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2656 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2658 effectivePropertyIndex++;
2663 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2664 if (p->type == Object::DynamicProperty::Alias) {
2666 Q_ASSERT(buildData);
2667 ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++;
2668 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex,
2671 // Even if we aren't resolving the alias, we need a fake signal so that the
2672 // metaobject remains consistent across the resolve and non-resolve alias runs
2673 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2674 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2675 effectivePropertyIndex++;
2682 // Reserve default property
2683 QFastMetaBuilder::StringRef defPropRef;
2684 if (defaultProperty) {
2685 defPropRef = builder.newString(strlen("DefaultProperty"));
2686 builder.setClassInfo(0, defPropRef, defaultProperty->nameRef);
2689 // Reserve dynamic signals
2690 int signalIndex = 0;
2691 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2693 int paramCount = s->parameterNames.count();
2695 int signatureSize = s->name.utf8length() + 2 /* paren */;
2697 if (paramCount) signatureSize += s->parameterTypesLength() + (paramCount - 1) /* commas */;
2698 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1) /* commas */;
2700 s->signatureRef = builder.newString(signatureSize);
2701 if (namesSize) s->parameterNamesRef = builder.newString(namesSize);
2704 ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++;
2706 builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->signatureRef, s->parameterNamesRef);
2710 // Reserve dynamic slots
2711 if (obj->dynamicSlots.count()) {
2713 // Allocate QVariant string
2714 if (typeRefs[0].isEmpty())
2715 typeRefs[0] = builder.newString(strlen(builtinTypes[0].cppType));
2717 typedef QDeclarativeVMEMetaData VMD;
2719 int methodIndex = 0;
2720 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2721 int paramCount = s->parameterNames.count();
2723 int signatureSize = s->name.utf8length() + 2 /* paren */;
2725 if (paramCount) signatureSize += (paramCount * strlen("QVariant") + (paramCount - 1));
2726 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
2728 s->signatureRef = builder.newString(signatureSize);
2729 if (namesSize) s->parameterNamesRef = builder.newString(namesSize);
2731 builder.setMethod(methodIndex, s->signatureRef, s->parameterNamesRef, typeRefs[0]);
2735 funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ +
2736 namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
2737 funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
2738 for (int jj = 0; jj < paramCount; ++jj) {
2739 if (jj) funcScript.append(QLatin1Char(','));
2740 funcScript.append(QLatin1String(s->parameterNames.at(jj)));
2742 funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
2744 VMD::MethodData methodData = { s->parameterNames.count(), 0,
2745 funcScript.length(),
2746 s->location.start.line };
2748 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2751 VMD::MethodData &md = *(vmd->methodData() + methodIndex);
2753 md.bodyOffset = dynamicData.size();
2755 dynamicData.append((const char *)funcScript.constData(),
2756 (funcScript.length() * sizeof(QChar)));
2763 // Now allocate used builtin types
2764 for (int ii = 0; ii < builtinTypeCount; ++ii) {
2765 if (!typeRefs[ii].isEmpty())
2766 typeRefs[ii].load(builtinTypes[ii].cppType);
2769 // Now allocate properties
2770 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2772 char *d = p->changedSignatureRef.data();
2773 p->name.writeUtf8(d);
2774 strcpy(d + p->name.utf8length(), "Changed()");
2776 if (p->type == Object::DynamicProperty::Alias && !resolveAlias)
2779 p->nameRef.load(p->name);
2781 if (p->type >= builtinTypeCount) {
2782 Q_ASSERT(p->resolvedCustomTypeName);
2783 p->typeRef.load(*p->resolvedCustomTypeName);
2787 // Allocate default property if necessary
2788 if (defaultProperty)
2789 strcpy(defPropRef.data(), "DefaultProperty");
2791 // Now allocate signals
2792 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2794 char *d = s->signatureRef.data();
2795 char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data();
2796 s->name.writeUtf8(d); d += s->name.utf8length();
2799 for (int jj = 0; jj < s->parameterNames.count(); ++jj) {
2800 if (jj != 0) { *d++ = ','; *d2++ = ','; }
2801 strcpy(d, s->parameterTypes.at(jj).constData());
2802 d += s->parameterTypes.at(jj).length();
2803 strcpy(d2, s->parameterNames.at(jj).constData());
2804 d2 += s->parameterNames.at(jj).length();
2811 // Now allocate methods
2812 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2813 char *d = s->signatureRef.data();
2814 char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data();
2815 s->name.writeUtf8(d); d += s->name.utf8length();
2817 for (int jj = 0; jj < s->parameterNames.count(); ++jj) {
2818 if (jj != 0) { *d++ = ','; *d2++ = ','; }
2819 strcpy(d, "QVariant");
2820 d += strlen("QVariant");
2821 strcpy(d2, s->parameterNames.at(jj).constData());
2822 d2 += s->parameterNames.at(jj).length();
2829 // Now allocate class name
2830 classNameRef.load(newClassName);
2832 obj->metadata = builder.toData();
2833 builder.fromData(&obj->extObject, obj->metatype, obj->metadata);
2835 if (mode == IgnoreAliases && aliasCount)
2836 compileState->aliasingObjects.append(obj);
2838 obj->synthdata = dynamicData;
2840 if (obj->synthCache) {
2841 obj->synthCache->release();
2842 obj->synthCache = 0;
2845 if (obj->type != -1) {
2846 QDeclarativePropertyCache *cache = output->types[obj->type].createPropertyCache(engine)->copy();
2847 cache->append(engine, &obj->extObject, QDeclarativePropertyCache::Data::NoFlags,
2848 QDeclarativePropertyCache::Data::IsVMEFunction,
2849 QDeclarativePropertyCache::Data::IsVMESignal);
2850 obj->synthCache = cache;
2856 bool QDeclarativeCompiler::checkValidId(QDeclarativeParser::Value *v, const QString &val)
2859 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
2861 QChar ch = val.at(0);
2862 if (QDeclarativeUtils::isLetter(ch) && !QDeclarativeUtils::isLower(ch))
2863 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
2865 QChar u(QLatin1Char('_'));
2866 if (!QDeclarativeUtils::isLetter(ch) && ch != u)
2867 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
2869 for (int ii = 1; ii < val.count(); ++ii) {
2871 if (!QDeclarativeUtils::isLetterOrNumber(ch) && ch != u)
2872 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
2875 if (enginePrivate->v8engine()->illegalNames().contains(val))
2876 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
2881 #include <qdeclarativejsparser_p.h>
2883 static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node)
2885 if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) {
2887 static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name.toString();
2888 return QStringList() << name;
2889 } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) {
2890 QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node);
2892 QStringList rv = astNodeToStringList(expr->base);
2895 rv.append(expr->name.toString());
2898 return QStringList();
2901 bool QDeclarativeCompiler::compileAlias(QFastMetaBuilder &builder,
2903 QDeclarativeParser::Object *obj,
2904 int propIndex, int aliasIndex,
2905 Object::DynamicProperty &prop)
2907 if (!prop.defaultValue)
2908 COMPILE_EXCEPTION(obj, tr("No property alias location"));
2910 if (!prop.defaultValue->values.isOne() ||
2911 prop.defaultValue->values.first()->object ||
2912 !prop.defaultValue->values.first()->value.isScript())
2913 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2915 QDeclarativeJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST();
2917 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
2919 QStringList alias = astNodeToStringList(node);
2921 if (alias.count() < 1 || alias.count() > 3)
2922 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
2924 QDeclarativeParser::Object *idObject = compileState->ids.value(alias.at(0));
2926 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
2928 QByteArray typeName;
2933 bool writable = false;
2934 bool resettable = false;
2935 if (alias.count() == 2 || alias.count() == 3) {
2936 propIdx = indexOfProperty(idObject, alias.at(1));
2938 if (-1 == propIdx) {
2939 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2940 } else if (propIdx > 0xFFFF) {
2941 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
2944 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
2945 if (!aliasProperty.isScriptable())
2946 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2948 writable = aliasProperty.isWritable();
2949 resettable = aliasProperty.isResettable();
2951 if (aliasProperty.type() < QVariant::UserType)
2952 type = aliasProperty.type();
2954 if (alias.count() == 3) {
2955 QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
2957 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2959 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
2961 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
2962 if (valueTypeIndex == -1)
2963 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2964 Q_ASSERT(valueTypeIndex <= 0xFF);
2966 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
2967 propIdx |= (valueTypeIndex << 16);
2970 if (aliasProperty.isEnumType())
2971 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
2973 typeName = aliasProperty.typeName();
2975 Q_ASSERT(idObject->type != -1); // How else did it get an id?
2977 const QDeclarativeCompiledData::TypeReference &ref = output->types.at(idObject->type);
2979 typeName = ref.type->typeName();
2981 typeName = ref.component->root->className();
2986 if (typeName.endsWith('*'))
2987 flags |= QML_ALIAS_FLAG_PTR;
2989 QDeclarativeVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags };
2991 typedef QDeclarativeVMEMetaData VMD;
2992 VMD *vmd = (QDeclarativeVMEMetaData *)data.data();
2993 *(vmd->aliasData() + aliasIndex) = aliasData;
2995 prop.nameRef = builder.newString(prop.name.utf8length());
2996 prop.resolvedCustomTypeName = pool->NewByteArray(typeName);
2997 prop.typeRef = builder.newString(typeName.length());
2999 builder.setProperty(propIndex, prop.nameRef, prop.typeRef, (QMetaType::Type)type,
3000 (QFastMetaBuilder::PropertyFlag)(writable?int(QFastMetaBuilder::Writable):0),
3006 bool QDeclarativeCompiler::buildBinding(QDeclarativeParser::Value *value,
3007 QDeclarativeParser::Property *prop,
3008 const BindingContext &ctxt)
3010 Q_ASSERT(prop->index != -1);
3011 Q_ASSERT(prop->parent);
3012 Q_ASSERT(prop->parent->metaObject());
3014 if (!prop->core.isWritable() && !prop->core.isQList())
3015 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3017 BindingReference *reference = pool->New<BindingReference>();
3018 reference->expression = value->value;
3019 reference->property = prop;
3020 reference->value = value;
3021 reference->bindingContext = ctxt;
3022 addBindingReference(reference);
3027 void QDeclarativeCompiler::genBindingAssignment(QDeclarativeParser::Value *binding,
3028 QDeclarativeParser::Property *prop,
3029 QDeclarativeParser::Object *obj,
3030 QDeclarativeParser::Property *valueTypeProperty)
3033 Q_ASSERT(binding->bindingReference);
3035 const BindingReference &ref = *binding->bindingReference;
3036 if (ref.dataType == BindingReference::V4) {
3037 QDeclarativeInstruction store;
3038 store.setType(QDeclarativeInstruction::StoreV4Binding);
3039 store.assignBinding.value = ref.compiledIndex;
3040 store.assignBinding.context = ref.bindingContext.stack;
3041 store.assignBinding.owner = ref.bindingContext.owner;
3042 if (valueTypeProperty)
3043 store.assignBinding.property = (valueTypeProperty->index & 0xFFFF) |
3044 ((valueTypeProperty->type & 0xFF)) << 16 |
3045 ((prop->index & 0xFF) << 24);
3047 store.assignBinding.property = prop->index;
3048 store.assignBinding.line = binding->location.start.line;
3049 output->addInstruction(store);
3050 } else if (ref.dataType == BindingReference::V8) {
3051 QDeclarativeInstruction store;
3052 store.setType(QDeclarativeInstruction::StoreV8Binding);
3053 store.assignBinding.value = ref.compiledIndex;
3054 store.assignBinding.context = ref.bindingContext.stack;
3055 store.assignBinding.owner = ref.bindingContext.owner;
3056 store.assignBinding.line = binding->location.start.line;
3058 Q_ASSERT(ref.bindingContext.owner == 0 ||
3059 (ref.bindingContext.owner != 0 && valueTypeProperty));
3060 if (ref.bindingContext.owner) {
3061 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
3063 store.assignBinding.property = genPropertyData(prop);
3066 output->addInstruction(store);
3068 QDeclarativeInstruction store;
3070 store.setType(QDeclarativeInstruction::StoreBinding);
3072 store.setType(QDeclarativeInstruction::StoreBindingOnAlias);
3073 store.assignBinding.value = output->indexForString(ref.rewrittenExpression);
3074 store.assignBinding.context = ref.bindingContext.stack;
3075 store.assignBinding.owner = ref.bindingContext.owner;
3076 store.assignBinding.line = binding->location.start.line;
3078 Q_ASSERT(ref.bindingContext.owner == 0 ||
3079 (ref.bindingContext.owner != 0 && valueTypeProperty));
3080 if (ref.bindingContext.owner) {
3081 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
3083 store.assignBinding.property = genPropertyData(prop);
3085 output->addInstruction(store);
3089 int QDeclarativeCompiler::genContextCache()
3091 if (compileState->ids.count() == 0)
3094 QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache();
3095 cache->reserve(compileState->ids.count());
3096 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
3097 cache->add(o->id, o->idIndex);
3099 output->contextCaches.append(cache);
3100 return output->contextCaches.count() - 1;
3103 int QDeclarativeCompiler::genValueTypeData(QDeclarativeParser::Property *valueTypeProp,
3104 QDeclarativeParser::Property *prop)
3106 typedef QDeclarativePropertyPrivate QDPP;
3107 QByteArray data = QDPP::saveValueType(prop->parent->metaObject(), prop->index,
3108 enginePrivate->valueTypes[prop->type]->metaObject(),
3109 valueTypeProp->index, engine);
3111 return output->indexForByteArray(data);
3114 int QDeclarativeCompiler::genPropertyData(QDeclarativeParser::Property *prop)
3116 typedef QDeclarativePropertyPrivate QDPP;
3117 QByteArray data = QDPP::saveProperty(prop->parent->metaObject(), prop->index, engine);
3119 return output->indexForByteArray(data);
3122 bool QDeclarativeCompiler::completeComponentBuild()
3125 componentStats->componentStat.ids = compileState->ids.count();
3127 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
3128 aliasObject = compileState->aliasingObjects.next(aliasObject))
3129 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
3131 QDeclarativeV4Compiler::Expression expr(unit->imports());
3132 expr.component = compileState->root;
3133 expr.ids = &compileState->ids;
3134 expr.importCache = output->importCache;
3136 QDeclarativeV4Compiler bindingCompiler;
3138 QList<BindingReference*> sharedBindings;
3140 for (BindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3142 BindingReference &binding = *b;
3144 // ### We don't currently optimize for bindings on alias's - because
3145 // of the solution to QTBUG-13719
3146 if (!binding.property->isAlias) {
3147 expr.context = binding.bindingContext.object;
3148 expr.property = binding.property;
3149 expr.expression = binding.expression;
3151 int index = bindingCompiler.compile(expr, enginePrivate);
3153 binding.dataType = BindingReference::V4;
3154 binding.compiledIndex = index;
3156 componentStats->componentStat.optimizedBindings.append(b->value->location);
3161 // Pre-rewrite the expression
3162 QString expression = binding.expression.asScript();
3164 QDeclarativeRewrite::RewriteBinding rewriteBinding;
3165 rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3166 bool isSharable = false;
3167 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3169 if (isSharable && !binding.property->isAlias /* See above re alias */ &&
3170 binding.property->type != qMetaTypeId<QDeclarativeBinding*>()) {
3171 binding.dataType = BindingReference::V8;
3172 sharedBindings.append(b);
3174 binding.dataType = BindingReference::QtScript;
3178 componentStats->componentStat.scriptBindings.append(b->value->location);
3181 if (!sharedBindings.isEmpty()) {
3183 static bool lt(const BindingReference *lhs, const BindingReference *rhs)
3185 return lhs->value->location.start.line < rhs->value->location.start.line;
3189 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3191 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3192 int lineNumber = startLineNumber;
3194 QString functionArray(QLatin1String("["));
3195 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3196 BindingReference *reference = sharedBindings.at(ii);
3197 QDeclarativeParser::Value *value = reference->value;
3198 const QString &expression = reference->rewrittenExpression;
3200 if (ii != 0) functionArray += QLatin1String(",");
3202 while (lineNumber < value->location.start.line) {
3204 functionArray += QLatin1String("\n");
3207 functionArray += expression;
3208 reference->compiledIndex = ii;
3210 functionArray += QLatin1String("]");
3212 compileState->v8BindingProgram = functionArray;
3213 compileState->v8BindingProgramLine = startLineNumber;
3214 compileState->v8BindingProgramIndex = output->v8bindings.count();
3215 output->v8bindings.append(v8::Persistent<v8::Array>());
3218 if (bindingCompiler.isValid())
3219 compileState->compiledBindingData = bindingCompiler.program();
3221 saveComponentState();
3226 void QDeclarativeCompiler::dumpStats()
3228 Q_ASSERT(componentStats);
3229 qWarning().nospace() << "QML Document: " << output->url.toString();
3230 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3231 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3232 qWarning().nospace() << " Component Line " << stat.lineNumber;
3233 qWarning().nospace() << " Total Objects: " << stat.objects;
3234 qWarning().nospace() << " IDs Used: " << stat.ids;
3235 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3239 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3240 if (0 == (ii % 10)) {
3241 if (ii) output.append("\n");
3246 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3248 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3249 output.append(") ");
3251 if (!output.isEmpty())
3252 qWarning().nospace() << output.constData();
3255 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3258 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3259 if (0 == (ii % 10)) {
3260 if (ii) output.append("\n");
3265 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3267 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3268 output.append(") ");
3270 if (!output.isEmpty())
3271 qWarning().nospace() << output.constData();
3277 Returns true if from can be assigned to a (QObject) property of type
3280 bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeParser::Object *from)
3282 const QMetaObject *toMo =
3283 enginePrivate->rawMetaObjectForType(to);
3284 const QMetaObject *fromMo = from->metaObject();
3287 if (QDeclarativePropertyPrivate::equal(fromMo, toMo))
3289 fromMo = fromMo->superClass();
3295 Returns the element name, as written in the QML file, for o.
3297 QString QDeclarativeCompiler::elementName(QDeclarativeParser::Object *o)
3300 if (o->type != -1) {
3301 return output->types.at(o->type).className;
3307 QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeParser::Object *from)
3310 const QMetaObject *mo = from->metatype;
3311 QDeclarativeType *type = 0;
3312 while (!type && mo) {
3313 type = QDeclarativeMetaType::qmlType(mo);
3314 mo = mo->superClass();
3319 QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeParser::Object *obj)
3321 const QMetaObject *mo = obj->metatype;
3323 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3325 return QStringList();
3327 QMetaClassInfo classInfo = mo->classInfo(idx);
3328 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3332 QDeclarativePropertyCache::Data *
3333 QDeclarativeCompiler::property(QDeclarativeParser::Object *object, int index)
3335 QDeclarativePropertyCache *cache = 0;
3337 if (object->synthCache)
3338 cache = object->synthCache;
3339 else if (object->type != -1)
3340 cache = output->types[object->type].createPropertyCache(engine);
3342 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3344 return cache->property(index);
3347 QDeclarativePropertyCache::Data *
3348 QDeclarativeCompiler::property(QDeclarativeParser::Object *object, const QHashedStringRef &name, bool *notInRevision)
3350 if (notInRevision) *notInRevision = false;
3352 QDeclarativePropertyCache *cache = 0;
3354 if (object->synthCache)
3355 cache = object->synthCache;
3356 else if (object->type != -1)
3357 cache = output->types[object->type].createPropertyCache(engine);
3359 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3361 QDeclarativePropertyCache::Data *d = cache->property(name);
3363 // Find the first property
3364 while (d && d->isFunction())
3365 d = cache->overrideData(d);
3367 if (d && !cache->isAllowedInRevision(d)) {
3368 if (notInRevision) *notInRevision = true;
3375 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3376 QDeclarativePropertyCache::Data *
3377 QDeclarativeCompiler::signal(QDeclarativeParser::Object *object, const QHashedStringRef &name, bool *notInRevision)
3379 if (notInRevision) *notInRevision = false;
3381 QDeclarativePropertyCache *cache = 0;
3383 if (object->synthCache)
3384 cache = object->synthCache;
3385 else if (object->type != -1)
3386 cache = output->types[object->type].createPropertyCache(engine);
3388 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3391 QDeclarativePropertyCache::Data *d = cache->property(name);
3392 if (notInRevision) *notInRevision = false;
3394 while (d && !(d->isFunction()))
3395 d = cache->overrideData(d);
3397 if (d && !cache->isAllowedInRevision(d)) {
3398 if (notInRevision) *notInRevision = true;
3404 if (name.endsWith(Changed_string)) {
3405 QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3407 d = property(object, propName, notInRevision);
3409 return cache->method(d->notifyIndex);
3415 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3416 int QDeclarativeCompiler::indexOfSignal(QDeclarativeParser::Object *object, const QString &name,
3417 bool *notInRevision)
3419 QDeclarativePropertyCache::Data *d = signal(object, QStringRef(&name), notInRevision);
3420 return d?d->coreIndex:-1;
3423 int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QString &name,
3424 bool *notInRevision)
3426 return indexOfProperty(object, QStringRef(&name), notInRevision);
3429 int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QHashedStringRef &name,
3430 bool *notInRevision)
3432 QDeclarativePropertyCache::Data *d = property(object, name, notInRevision);
3433 return d?d->coreIndex:-1;