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 "qdeclarativecompiler_p.h"
44 #include "qdeclarativepropertyvaluesource.h"
45 #include "qdeclarativecomponent.h"
46 #include <private/qmetaobjectbuilder_p.h>
47 #include <private/qfastmetabuilder_p.h>
48 #include "qdeclarativestringconverters_p.h"
49 #include "qdeclarativeengine_p.h"
50 #include "qdeclarativeengine.h"
51 #include "qdeclarativecontext.h"
52 #include "qdeclarativemetatype_p.h"
53 #include "qdeclarativecustomparser_p_p.h"
54 #include "qdeclarativecontext_p.h"
55 #include "qdeclarativecomponent_p.h"
56 #include <private/qdeclarativejsast_p.h>
57 #include "qdeclarativevmemetaobject_p.h"
58 #include "qdeclarativeexpression_p.h"
59 #include "qdeclarativeproperty_p.h"
60 #include "qdeclarativerewrite_p.h"
61 #include "qdeclarativescriptstring.h"
62 #include "qdeclarativeglobal_p.h"
63 #include "qdeclarativebinding_p.h"
64 #include <private/qv4compiler_p.h>
72 #include <QtCore/qdebug.h>
73 #include <QtCore/qdatetime.h>
75 Q_DECLARE_METATYPE(QList<int>)
76 Q_DECLARE_METATYPE(QList<qreal>)
77 Q_DECLARE_METATYPE(QList<bool>)
78 Q_DECLARE_METATYPE(QList<QString>)
79 Q_DECLARE_METATYPE(QList<QUrl>)
83 DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP);
84 DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS);
86 using namespace QDeclarativeScript;
87 using namespace QDeclarativeCompilerTypes;
89 static QString id_string(QLatin1String("id"));
90 static QString on_string(QLatin1String("on"));
91 static QString Changed_string(QLatin1String("Changed"));
92 static QString Component_string(QLatin1String("Component"));
93 static QString Component_import_string(QLatin1String("QML/Component"));
96 Instantiate a new QDeclarativeCompiler.
98 QDeclarativeCompiler::QDeclarativeCompiler(QDeclarativePool *pool)
99 : pool(pool), output(0), engine(0), unitRoot(0), unit(0), cachedComponentTypeRef(-1),
102 if (compilerStatDump())
103 componentStats = pool->New<ComponentStats>();
107 Returns true if the last call to compile() caused errors.
111 bool QDeclarativeCompiler::isError() const
113 return !exceptions.isEmpty();
117 Return the list of errors from the last call to compile(), or an empty list
118 if there were no errors.
120 QList<QDeclarativeError> QDeclarativeCompiler::errors() const
126 Returns true if \a name refers to an attached property, false otherwise.
128 Attached property names are those that start with a capital letter.
130 bool QDeclarativeCompiler::isAttachedPropertyName(const QString &name)
132 return isAttachedPropertyName(QHashedStringRef(&name));
135 bool QDeclarativeCompiler::isAttachedPropertyName(const QHashedStringRef &name)
137 return !name.isEmpty() && name.at(0).isUpper();
141 Returns true if \a name refers to a signal property, false otherwise.
143 Signal property names are those that start with "on", followed by a first
144 character which is either a capital letter or one or more underscores followed
145 by a capital letter, which is then followed by other allowed characters.
147 Note that although ECMA-262r3 supports dollarsigns and escaped unicode
148 character codes in property names, for simplicity and performance reasons
149 QML only supports letters, numbers and underscores.
151 bool QDeclarativeCompiler::isSignalPropertyName(const QString &name)
153 return isSignalPropertyName(QStringRef(&name));
156 bool QDeclarativeCompiler::isSignalPropertyName(const QHashedStringRef &name)
158 if (name.length() < 3) return false;
159 if (!name.startsWith(on_string)) return false;
160 int ns = name.length();
161 for (int i = 2; i < ns; ++i) {
162 const QChar curr = name.at(i);
163 if (curr.unicode() == '_') continue;
164 if (curr.isUpper()) return true;
167 return false; // consists solely of underscores - invalid.
171 \macro COMPILE_EXCEPTION
173 Inserts an error into the QDeclarativeCompiler error list, and returns false
176 \a token is used to source the error line and column, and \a desc is the
177 error itself. \a desc can be an expression that can be piped into QDebug.
182 COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(property->name));
185 #define COMPILE_EXCEPTION(token, desc) \
187 QString exceptionDescription; \
188 QDeclarativeError error; \
189 error.setUrl(output->url); \
190 error.setLine((token)->location.start.line); \
191 error.setColumn((token)->location.start.column); \
192 error.setDescription(desc.trimmed()); \
193 exceptions << error; \
200 Returns false if \a is false, otherwise does nothing.
202 #define COMPILE_CHECK(a) \
204 if (!a) return false; \
208 Returns true if literal \a v can be assigned to property \a prop, otherwise
211 This test corresponds to action taken by genLiteralAssignment(). Any change
212 made here, must have a corresponding action in genLiteralAssigment().
214 bool QDeclarativeCompiler::testLiteralAssignment(QDeclarativeScript::Property *prop,
215 QDeclarativeScript::Value *v)
217 const QDeclarativeScript::Variant &value = v->value;
219 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
220 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
222 if (prop->core.isEnum()) {
223 QMetaProperty p = prop->parent->metaObject()->property(prop->index);
226 if (p.isFlagType()) {
227 enumValue = p.enumerator().keysToValue(value.asString().toUtf8().constData(), &ok);
229 enumValue = p.enumerator().keyToValue(value.asString().toUtf8().constData(), &ok);
232 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration"));
234 v->value = QDeclarativeScript::Variant((double)enumValue);
238 int type = prop->type;
241 case QMetaType::QVariant:
243 case QVariant::String:
244 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
246 case QVariant::StringList: // we expect a string literal. A string list is not a literal assignment.
247 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or string list expected"));
249 case QVariant::ByteArray:
250 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected"));
253 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected"));
257 bool ok = v->value.isNumber();
259 double n = v->value.asNumber();
260 if (double(uint(n)) != n)
263 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected"));
268 bool ok = v->value.isNumber();
270 double n = v->value.asNumber();
271 if (double(int(n)) != n)
274 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected"));
277 case QMetaType::Float:
278 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
280 case QVariant::Double:
281 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
283 case QVariant::Color:
286 QDeclarativeStringConverters::colorFromString(value.asString(), &ok);
287 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected"));
290 #ifndef QT_NO_DATESTRING
294 QDeclarativeStringConverters::dateFromString(value.asString(), &ok);
295 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected"));
301 QDeclarativeStringConverters::timeFromString(value.asString(), &ok);
302 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected"));
305 case QVariant::DateTime:
308 QDeclarativeStringConverters::dateTimeFromString(value.asString(), &ok);
309 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected"));
312 #endif // QT_NO_DATESTRING
313 case QVariant::Point:
314 case QVariant::PointF:
317 QDeclarativeStringConverters::pointFFromString(value.asString(), &ok);
318 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected"));
322 case QVariant::SizeF:
325 QDeclarativeStringConverters::sizeFFromString(value.asString(), &ok);
326 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected"));
330 case QVariant::RectF:
333 QDeclarativeStringConverters::rectFFromString(value.asString(), &ok);
334 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected"));
339 if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected"));
342 case QVariant::Vector3D:
345 QDeclarativeStringConverters::vector3DFromString(value.asString(), &ok);
346 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected"));
349 case QVariant::Vector4D:
352 QDeclarativeStringConverters::vector4DFromString(value.asString(), &ok);
353 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 4D vector expected"));
358 // check if assigning a literal value to a list property.
359 // in each case, check the singular, since an Array of the specified type
360 // will not go via this literal assignment codepath.
361 if (type == qMetaTypeId<QList<qreal> >()) {
362 if (!v->value.isNumber()) {
363 COMPILE_EXCEPTION(v, tr("Invalid property assignment: real or array of reals expected"));
366 } else if (type == qMetaTypeId<QList<int> >()) {
367 bool ok = v->value.isNumber();
369 double n = v->value.asNumber();
370 if (double(int(n)) != n)
373 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int or array of ints expected"));
375 } else if (type == qMetaTypeId<QList<bool> >()) {
376 if (!v->value.isBoolean()) {
377 COMPILE_EXCEPTION(v, tr("Invalid property assignment: bool or array of bools expected"));
380 } else if (type == qMetaTypeId<QList<QString> >()) { // we expect a string literal. A string list is not a literal assignment.
381 if (!v->value.isString()) {
382 COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or array of strings expected"));
385 } else if (type == qMetaTypeId<QList<QUrl> >()) {
386 if (!v->value.isString()) {
387 COMPILE_EXCEPTION(v, tr("Invalid property assignment: url or array of urls expected"));
392 // otherwise, check for existence of string converter to custom type
393 QDeclarativeMetaType::StringConverter converter = QDeclarativeMetaType::customStringConverter(type);
395 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName((QVariant::Type)type))));
403 Generate a store instruction for assigning literal \a v to property \a prop.
405 Any literal assignment that is approved in testLiteralAssignment() must have
406 a corresponding action in this method.
408 void QDeclarativeCompiler::genLiteralAssignment(QDeclarativeScript::Property *prop,
409 QDeclarativeScript::Value *v)
411 if (prop->core.isEnum()) {
412 Q_ASSERT(v->value.isNumber());
414 int value = (int)v->value.asNumber();
416 Instruction::StoreInteger instr;
417 instr.propertyIndex = prop->index;
419 output->addInstruction(instr);
423 int type = prop->type;
425 case QMetaType::QVariant:
427 if (v->value.isNumber()) {
428 double n = v->value.asNumber();
429 if (double(int(n)) == n) {
430 if (prop->core.isVMEProperty()) {
431 Instruction::StoreVarInteger instr;
432 instr.propertyIndex = prop->index;
433 instr.value = int(n);
434 output->addInstruction(instr);
436 Instruction::StoreVariantInteger instr;
437 instr.propertyIndex = prop->index;
438 instr.value = int(n);
439 output->addInstruction(instr);
442 if (prop->core.isVMEProperty()) {
443 Instruction::StoreVarDouble instr;
444 instr.propertyIndex = prop->index;
446 output->addInstruction(instr);
448 Instruction::StoreVariantDouble instr;
449 instr.propertyIndex = prop->index;
451 output->addInstruction(instr);
454 } else if (v->value.isBoolean()) {
455 if (prop->core.isVMEProperty()) {
456 Instruction::StoreVarBool instr;
457 instr.propertyIndex = prop->index;
458 instr.value = v->value.asBoolean();
459 output->addInstruction(instr);
461 Instruction::StoreVariantBool instr;
462 instr.propertyIndex = prop->index;
463 instr.value = v->value.asBoolean();
464 output->addInstruction(instr);
467 if (prop->core.isVMEProperty()) {
468 Instruction::StoreVar instr;
469 instr.propertyIndex = prop->index;
470 instr.value = output->indexForString(v->value.asString());
471 output->addInstruction(instr);
473 Instruction::StoreVariant instr;
474 instr.propertyIndex = prop->index;
475 instr.value = output->indexForString(v->value.asString());
476 output->addInstruction(instr);
481 case QVariant::String:
483 Instruction::StoreString instr;
484 instr.propertyIndex = prop->index;
485 instr.value = output->indexForString(v->value.asString());
486 output->addInstruction(instr);
489 case QVariant::StringList:
491 Instruction::StoreStringList instr;
492 instr.propertyIndex = prop->index;
493 instr.value = output->indexForString(v->value.asString());
494 output->addInstruction(instr);
497 case QVariant::ByteArray:
499 Instruction::StoreByteArray instr;
500 instr.propertyIndex = prop->index;
501 instr.value = output->indexForByteArray(v->value.asString().toLatin1());
502 output->addInstruction(instr);
507 Instruction::StoreUrl instr;
508 QString string = v->value.asString();
509 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
510 instr.propertyIndex = prop->index;
511 instr.value = output->indexForUrl(u);
512 output->addInstruction(instr);
517 Instruction::StoreInteger instr;
518 instr.propertyIndex = prop->index;
519 instr.value = uint(v->value.asNumber());
520 output->addInstruction(instr);
525 Instruction::StoreInteger instr;
526 instr.propertyIndex = prop->index;
527 instr.value = int(v->value.asNumber());
528 output->addInstruction(instr);
531 case QMetaType::Float:
533 Instruction::StoreFloat instr;
534 instr.propertyIndex = prop->index;
535 instr.value = float(v->value.asNumber());
536 output->addInstruction(instr);
539 case QVariant::Double:
541 Instruction::StoreDouble instr;
542 instr.propertyIndex = prop->index;
543 instr.value = v->value.asNumber();
544 output->addInstruction(instr);
547 case QVariant::Color:
549 Instruction::StoreColor instr;
550 QColor c = QDeclarativeStringConverters::colorFromString(v->value.asString());
551 instr.propertyIndex = prop->index;
552 instr.value = c.rgba();
553 output->addInstruction(instr);
556 #ifndef QT_NO_DATESTRING
559 Instruction::StoreDate instr;
560 QDate d = QDeclarativeStringConverters::dateFromString(v->value.asString());
561 instr.propertyIndex = prop->index;
562 instr.value = d.toJulianDay();
563 output->addInstruction(instr);
568 Instruction::StoreTime instr;
569 QTime time = QDeclarativeStringConverters::timeFromString(v->value.asString());
570 instr.propertyIndex = prop->index;
571 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
572 ::memcpy(&instr.time, &time, sizeof(QTime));
573 output->addInstruction(instr);
576 case QVariant::DateTime:
578 Instruction::StoreDateTime instr;
579 QDateTime dateTime = QDeclarativeStringConverters::dateTimeFromString(v->value.asString());
580 QTime time = dateTime.time();
581 instr.propertyIndex = prop->index;
582 instr.date = dateTime.date().toJulianDay();
583 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
584 ::memcpy(&instr.time, &time, sizeof(QTime));
585 output->addInstruction(instr);
588 #endif // QT_NO_DATESTRING
589 case QVariant::Point:
591 Instruction::StorePoint instr;
593 QPoint point = QDeclarativeStringConverters::pointFFromString(v->value.asString(), &ok).toPoint();
594 instr.propertyIndex = prop->index;
595 instr.point.xp = point.x();
596 instr.point.yp = point.y();
597 output->addInstruction(instr);
600 case QVariant::PointF:
602 Instruction::StorePointF instr;
604 QPointF point = QDeclarativeStringConverters::pointFFromString(v->value.asString(), &ok);
605 instr.propertyIndex = prop->index;
606 instr.point.xp = point.x();
607 instr.point.yp = point.y();
608 output->addInstruction(instr);
613 Instruction::StoreSize instr;
615 QSize size = QDeclarativeStringConverters::sizeFFromString(v->value.asString(), &ok).toSize();
616 instr.propertyIndex = prop->index;
617 instr.size.wd = size.width();
618 instr.size.ht = size.height();
619 output->addInstruction(instr);
622 case QVariant::SizeF:
624 Instruction::StoreSizeF instr;
626 QSizeF size = QDeclarativeStringConverters::sizeFFromString(v->value.asString(), &ok);
627 instr.propertyIndex = prop->index;
628 instr.size.wd = size.width();
629 instr.size.ht = size.height();
630 output->addInstruction(instr);
635 Instruction::StoreRect instr;
637 QRect rect = QDeclarativeStringConverters::rectFFromString(v->value.asString(), &ok).toRect();
638 instr.propertyIndex = prop->index;
639 instr.rect.x1 = rect.left();
640 instr.rect.y1 = rect.top();
641 instr.rect.x2 = rect.right();
642 instr.rect.y2 = rect.bottom();
643 output->addInstruction(instr);
646 case QVariant::RectF:
648 Instruction::StoreRectF instr;
650 QRectF rect = QDeclarativeStringConverters::rectFFromString(v->value.asString(), &ok);
651 instr.propertyIndex = prop->index;
652 instr.rect.xp = rect.left();
653 instr.rect.yp = rect.top();
654 instr.rect.w = rect.width();
655 instr.rect.h = rect.height();
656 output->addInstruction(instr);
661 Instruction::StoreBool instr;
662 bool b = v->value.asBoolean();
663 instr.propertyIndex = prop->index;
665 output->addInstruction(instr);
668 case QVariant::Vector3D:
670 Instruction::StoreVector3D instr;
672 QVector3D vector = QDeclarativeStringConverters::vector3DFromString(v->value.asString(), &ok);
673 instr.propertyIndex = prop->index;
674 instr.vector.xp = vector.x();
675 instr.vector.yp = vector.y();
676 instr.vector.zp = vector.z();
677 output->addInstruction(instr);
680 case QVariant::Vector4D:
682 Instruction::StoreVector4D instr;
684 QVector4D vector = QDeclarativeStringConverters::vector4DFromString(v->value.asString(), &ok);
685 instr.propertyIndex = prop->index;
686 instr.vector.xp = vector.x();
687 instr.vector.yp = vector.y();
688 instr.vector.zp = vector.z();
689 instr.vector.wp = vector.w();
690 output->addInstruction(instr);
695 // generate single literal value assignment to a list property if required
696 if (type == qMetaTypeId<QList<qreal> >()) {
697 Instruction::StoreDoubleQList instr;
698 instr.propertyIndex = prop->index;
699 instr.value = v->value.asNumber();
700 output->addInstruction(instr);
702 } else if (type == qMetaTypeId<QList<int> >()) {
703 Instruction::StoreIntegerQList instr;
704 instr.propertyIndex = prop->index;
705 instr.value = int(v->value.asNumber());
706 output->addInstruction(instr);
708 } else if (type == qMetaTypeId<QList<bool> >()) {
709 Instruction::StoreBoolQList instr;
710 bool b = v->value.asBoolean();
711 instr.propertyIndex = prop->index;
713 output->addInstruction(instr);
715 } else if (type == qMetaTypeId<QList<QUrl> >()) {
716 Instruction::StoreUrlQList instr;
717 QString string = v->value.asString();
718 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
719 instr.propertyIndex = prop->index;
720 instr.value = output->indexForUrl(u);
721 output->addInstruction(instr);
723 } else if (type == qMetaTypeId<QList<QString> >()) {
724 Instruction::StoreStringQList instr;
725 instr.propertyIndex = prop->index;
726 instr.value = output->indexForString(v->value.asString());
727 output->addInstruction(instr);
731 // otherwise, generate custom type literal assignment
732 Instruction::AssignCustomType instr;
733 instr.propertyIndex = prop->index;
734 instr.primitive = output->indexForString(v->value.asString());
736 output->addInstruction(instr);
743 Resets data by clearing the lists that the QDeclarativeCompiler modifies.
745 void QDeclarativeCompiler::reset(QDeclarativeCompiledData *data)
748 data->primitives.clear();
750 data->bytecode.resize(0);
754 Compile \a unit, and store the output in \a out. \a engine is the QDeclarativeEngine
755 with which the QDeclarativeCompiledData will be associated.
757 Returns true on success, false on failure. On failure, the compile errors
758 are available from errors().
760 If the environment variant QML_COMPILER_DUMP is set
761 (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
762 on a successful compiler.
764 bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine,
765 QDeclarativeTypeData *unit,
766 QDeclarativeCompiledData *out)
773 QDeclarativeScript::Object *root = unit->parser().tree();
776 this->engine = engine;
777 this->enginePrivate = QDeclarativeEnginePrivate::get(engine);
779 this->unitRoot = root;
783 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
784 QList<QDeclarativeScript::TypeReference *> referencedTypes = unit->parser().referencedTypes();
786 for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
787 QDeclarativeCompiledData::TypeReference ref;
789 const QDeclarativeTypeData::TypeReference &tref = resolvedTypes.at(ii);
790 QDeclarativeScript::TypeReference *parserRef = referencedTypes.at(ii);
793 ref.type = tref.type;
794 if (!ref.type->isCreatable()) {
795 QString err = ref.type->noCreationReason();
797 err = tr( "Element is not creatable.");
798 COMPILE_EXCEPTION(parserRef->refObjects.first(), err);
801 if (ref.type->containsRevisionedAttributes()) {
802 QDeclarativeError cacheError;
803 ref.typePropertyCache = enginePrivate->cache(ref.type, resolvedTypes.at(ii).minorVersion,
805 if (!ref.typePropertyCache)
806 COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description());
807 ref.typePropertyCache->addref();
810 } else if (tref.typeData) {
811 ref.component = tref.typeData->compiledData();
813 ref.className = parserRef->name;
821 out->dumpInstructions();
824 Q_ASSERT(out->rootPropertyCache);
832 this->enginePrivate = 0;
834 this->cachedComponentTypeRef = -1;
840 void QDeclarativeCompiler::compileTree(QDeclarativeScript::Object *tree)
842 compileState = pool->New<ComponentCompileState>();
844 compileState->root = tree;
846 componentStats->componentStat.lineNumber = tree->location.start.line;
848 // Build global import scripts
849 QStringList importedScriptIndexes;
851 foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
852 importedScriptIndexes.append(script.qualifier);
855 // We generate the importCache before we build the tree so that
856 // it can be used in the binding compiler. Given we "expect" the
857 // QML compilation to succeed, this isn't a waste.
858 output->importCache = new QDeclarativeTypeNameCache();
859 for (int ii = 0; ii < importedScriptIndexes.count(); ++ii)
860 output->importCache->add(importedScriptIndexes.at(ii), ii);
861 unit->imports().populateCache(output->importCache, engine);
863 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
866 Instruction::Init init;
867 init.bindingsSize = compileState->totalBindingsCount;
868 init.parserStatusSize = compileState->parserStatusCount;
869 init.contextCache = genContextCache();
870 init.objectStackSize = compileState->objectDepth.maxDepth();
871 init.listStackSize = compileState->listDepth.maxDepth();
872 if (compileState->compiledBindingData.isEmpty())
873 init.compiledBinding = -1;
875 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
876 output->addInstruction(init);
878 foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
879 Instruction::StoreImportedScript import;
880 import.value = output->scripts.count();
882 QDeclarativeScriptData *scriptData = script.script->scriptData();
883 scriptData->addref();
884 output->scripts << scriptData;
885 output->addInstruction(import);
888 if (!compileState->v8BindingProgram.isEmpty()) {
889 Instruction::InitV8Bindings bindings;
890 bindings.program = output->indexForString(compileState->v8BindingProgram);
891 bindings.programIndex = compileState->v8BindingProgramIndex;
892 bindings.line = compileState->v8BindingProgramLine;
893 output->addInstruction(bindings);
898 Instruction::SetDefault def;
899 output->addInstruction(def);
901 Instruction::Done done;
902 output->addInstruction(done);
904 Q_ASSERT(tree->metatype);
906 if (tree->metadata.isEmpty()) {
907 output->root = tree->metatype;
909 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
910 output->root = &output->rootData;
912 if (!tree->metadata.isEmpty())
913 enginePrivate->registerCompositeType(output);
916 static bool QStringList_contains(const QStringList &list, const QHashedStringRef &string)
918 for (int ii = 0; ii < list.count(); ++ii)
919 if (string == list.at(ii))
925 bool QDeclarativeCompiler::buildObject(QDeclarativeScript::Object *obj, const BindingContext &ctxt)
928 componentStats->componentStat.objects++;
930 Q_ASSERT (obj->type != -1);
931 const QDeclarativeCompiledData::TypeReference &tr = output->types.at(obj->type);
932 obj->metatype = tr.metaObject();
935 obj->typeName = tr.type->qmlTypeName();
937 // This object is a "Component" element
938 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
939 COMPILE_CHECK(buildComponent(obj, ctxt));
944 typedef QDeclarativeInstruction I;
945 const I *init = ((const I *)tr.component->bytecode.constData());
946 Q_ASSERT(init && tr.component->instructionType(init) == QDeclarativeInstruction::Init);
948 // Adjust stack depths to include nested components
949 compileState->objectDepth.pushPop(init->init.objectStackSize);
950 compileState->listDepth.pushPop(init->init.listStackSize);
951 compileState->parserStatusCount += init->init.parserStatusSize;
952 compileState->totalBindingsCount += init->init.bindingsSize;
955 compileState->objectDepth.push();
957 // Object instantiations reset the binding context
958 BindingContext objCtxt(obj);
960 // Create the synthesized meta object, ignoring aliases
961 COMPILE_CHECK(checkDynamicMeta(obj));
962 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
963 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
965 // Find the native type and check for the QDeclarativeParserStatus interface
966 QDeclarativeType *type = toQmlType(obj);
968 obj->parserStatusCast = type->parserStatusCast();
969 if (obj->parserStatusCast != -1)
970 compileState->parserStatusCount++;
972 // Check if this is a custom parser type. Custom parser types allow
973 // assignments to non-existent properties. These assignments are then
974 // compiled by the type.
975 bool isCustomParser = output->types.at(obj->type).type &&
976 output->types.at(obj->type).type->customParser() != 0;
977 QList<QDeclarativeCustomParserProperty> customProps;
979 // Fetch the list of deferred properties
980 QStringList deferredList = deferredProperties(obj);
982 // Must do id property first. This is to ensure that the id given to any
983 // id reference created matches the order in which the objects are
985 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
986 if (prop->name() == id_string) {
987 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
993 Property *defaultProperty = 0;
994 Property *skipProperty = 0;
995 if (obj->defaultProperty) {
996 defaultProperty = obj->defaultProperty;
998 Property *explicitProperty = 0;
1000 const QMetaObject *mo = obj->metatype;
1001 int idx = mo->indexOfClassInfo("DefaultProperty");
1003 QMetaClassInfo info = mo->classInfo(idx);
1004 const char *p = info.value();
1008 while (char c = p[plen++]) { ord |= c; };
1012 // Utf8 - unoptimal, but seldom hit
1013 QString *s = pool->NewString(QString::fromUtf8(p, plen));
1014 QHashedStringRef r(*s);
1016 if (obj->propertiesHashField.test(r.hash())) {
1017 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1018 if (ep->name() == r) {
1019 explicitProperty = ep;
1025 if (!explicitProperty)
1026 defaultProperty->setName(r);
1029 QHashedCStringRef r(p, plen);
1031 if (obj->propertiesHashField.test(r.hash())) {
1032 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1033 if (ep->name() == r) {
1034 explicitProperty = ep;
1040 if (!explicitProperty) {
1041 // Set the default property name
1042 QChar *buffer = pool->NewRawArray<QChar>(r.length());
1043 r.writeUtf16(buffer);
1044 defaultProperty->setName(QHashedStringRef(buffer, r.length(), r.hash()));
1050 if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) {
1052 skipProperty = explicitProperty; // We merge the values into defaultProperty
1054 // Find the correct insertion point
1055 Value *insertPos = 0;
1057 for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) {
1058 if (!(v->location.start < explicitProperty->values.first()->location.start))
1063 defaultProperty->values.insertAfter(insertPos, explicitProperty->values);
1067 QDeclarativeCustomParser *cp = 0;
1069 cp = output->types.at(obj->type).type->customParser();
1071 // Build all explicit properties specified
1072 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1074 if (prop == skipProperty)
1076 if (prop->name() == id_string)
1079 bool canDefer = false;
1080 if (isCustomParser) {
1081 if (doesPropertyExist(prop, obj) &&
1082 (!(cp->flags() & QDeclarativeCustomParser::AcceptsAttachedProperties) ||
1083 !isAttachedPropertyName(prop->name()))) {
1084 int ids = compileState->ids.count();
1085 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1086 canDefer = ids == compileState->ids.count();
1087 } else if (isSignalPropertyName(prop->name()) &&
1088 (cp->flags() & QDeclarativeCustomParser::AcceptsSignalHandlers)) {
1089 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1091 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
1094 if (isSignalPropertyName(prop->name())) {
1095 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1097 int ids = compileState->ids.count();
1098 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1099 canDefer = ids == compileState->ids.count();
1103 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1104 prop->isDeferred = true;
1108 // Build the default property
1109 if (defaultProperty) {
1110 Property *prop = defaultProperty;
1112 bool canDefer = false;
1113 if (isCustomParser) {
1114 if (doesPropertyExist(prop, obj)) {
1115 int ids = compileState->ids.count();
1116 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1117 canDefer = ids == compileState->ids.count();
1119 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
1122 int ids = compileState->ids.count();
1123 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1124 canDefer = ids == compileState->ids.count();
1127 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1128 prop->isDeferred = true;
1131 // Compile custom parser parts
1132 if (isCustomParser && !customProps.isEmpty()) {
1134 cp->compiler = this;
1136 obj->custom = cp->compile(customProps);
1139 foreach (QDeclarativeError err, cp->errors()) {
1140 err.setUrl(output->url);
1145 compileState->objectDepth.pop();
1150 void QDeclarativeCompiler::genObject(QDeclarativeScript::Object *obj)
1152 QDeclarativeCompiledData::TypeReference &tr = output->types[obj->type];
1153 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
1158 // Create the object
1159 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
1160 !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) {
1162 Instruction::CreateSimpleObject create;
1163 create.create = output->types.at(obj->type).type->createFunction();
1164 create.typeSize = output->types.at(obj->type).type->createSize();
1165 create.type = obj->type;
1166 create.line = obj->location.start.line;
1167 create.column = obj->location.start.column;
1168 output->addInstruction(create);
1172 if (output->types.at(obj->type).type) {
1173 Instruction::CreateCppObject create;
1174 create.line = obj->location.start.line;
1175 create.column = obj->location.start.column;
1177 if (!obj->custom.isEmpty())
1178 create.data = output->indexForByteArray(obj->custom);
1179 create.type = obj->type;
1180 create.isRoot = (compileState->root == obj);
1181 output->addInstruction(create);
1183 Instruction::CreateQMLObject create;
1184 create.type = obj->type;
1185 create.isRoot = (compileState->root == obj);
1187 if (!obj->bindingBitmask.isEmpty()) {
1188 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
1189 create.bindingBits = output->indexForByteArray(obj->bindingBitmask);
1191 create.bindingBits = -1;
1193 output->addInstruction(create);
1195 Instruction::CompleteQMLObject complete;
1196 complete.line = obj->location.start.line;
1197 complete.column = obj->location.start.column;
1198 complete.isRoot = (compileState->root == obj);
1199 output->addInstruction(complete);
1203 // Setup the synthesized meta object if necessary
1204 if (!obj->metadata.isEmpty()) {
1205 Instruction::StoreMetaObject meta;
1206 meta.data = output->indexForByteArray(obj->metadata);
1207 meta.aliasData = output->indexForByteArray(obj->synthdata);
1208 meta.propertyCache = output->propertyCaches.count();
1210 QDeclarativePropertyCache *propertyCache = obj->synthCache;
1211 Q_ASSERT(propertyCache);
1212 propertyCache->addref();
1214 // Add flag for alias properties
1215 if (!obj->synthdata.isEmpty()) {
1216 const QDeclarativeVMEMetaData *vmeMetaData =
1217 reinterpret_cast<const QDeclarativeVMEMetaData *>(obj->synthdata.constData());
1218 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
1219 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
1220 QDeclarativePropertyData *data = propertyCache->property(index);
1221 data->setFlags(data->getFlags() | QDeclarativePropertyData::IsAlias);
1225 if (obj == unitRoot) {
1226 propertyCache->addref();
1227 output->rootPropertyCache = propertyCache;
1230 output->propertyCaches << propertyCache;
1231 output->addInstruction(meta);
1232 } else if (obj == unitRoot) {
1233 output->rootPropertyCache = tr.createPropertyCache(engine);
1234 output->rootPropertyCache->addref();
1237 // Set the object id
1238 if (!obj->id.isEmpty()) {
1239 Instruction::SetId id;
1240 id.value = output->indexForString(obj->id);
1241 id.index = obj->idIndex;
1242 output->addInstruction(id);
1246 if (tr.type && obj->parserStatusCast != -1) {
1247 Instruction::BeginObject begin;
1248 begin.castValue = obj->parserStatusCast;
1249 output->addInstruction(begin);
1255 void QDeclarativeCompiler::genObjectBody(QDeclarativeScript::Object *obj)
1257 for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1258 Q_ASSERT(prop->scriptStringScope != -1);
1259 const QString &script = prop->values.first()->value.asScript();
1260 Instruction::StoreScriptString ss;
1261 ss.propertyIndex = prop->index;
1262 ss.value = output->indexForString(script);
1263 ss.scope = prop->scriptStringScope;
1264 // ss.bindingId = rewriteBinding(script, prop->name());
1265 ss.bindingId = rewriteBinding(prop->values.first()->value, QString()); // XXX
1266 ss.line = prop->location.start.line;
1267 output->addInstruction(ss);
1270 bool seenDefer = false;
1271 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1272 if (prop->isDeferred) {
1277 genValueProperty(prop, obj);
1280 Instruction::Defer defer;
1281 defer.deferCount = 0;
1282 int deferIdx = output->addInstruction(defer);
1283 int nextInstructionIndex = output->nextInstructionIndex();
1285 Instruction::DeferInit dinit;
1286 // XXX - these are now massive over allocations
1287 dinit.bindingsSize = compileState->totalBindingsCount;
1288 dinit.parserStatusSize = compileState->parserStatusCount;
1289 dinit.objectStackSize = compileState->objectDepth.maxDepth();
1290 dinit.listStackSize = compileState->listDepth.maxDepth();
1291 output->addInstruction(dinit);
1293 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1294 if (!prop->isDeferred)
1296 genValueProperty(prop, obj);
1299 Instruction::Done done;
1300 output->addInstruction(done);
1302 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1305 for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1307 QDeclarativeScript::Value *v = prop->values.first();
1309 if (v->type == Value::SignalObject) {
1311 genObject(v->object);
1313 Instruction::AssignSignalObject assign;
1314 assign.line = v->location.start.line;
1315 assign.signal = output->indexForString(prop->name().toString());
1316 output->addInstruction(assign);
1318 } else if (v->type == Value::SignalExpression) {
1320 Instruction::StoreSignal store;
1321 store.signalIndex = prop->index;
1322 QDeclarativeRewrite::RewriteSignalHandler rewriteSignalHandler;
1323 const QString &rewrite =
1324 rewriteSignalHandler(v->value.asScript().trimmed(), prop->name().toString());
1325 store.value = output->indexForString(rewrite);
1326 store.context = v->signalExpressionContextStack;
1327 store.line = v->location.start.line;
1328 output->addInstruction(store);
1334 for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1335 Instruction::FetchAttached fetch;
1336 fetch.id = prop->index;
1337 fetch.line = prop->location.start.line;
1338 output->addInstruction(fetch);
1340 genObjectBody(prop->value);
1342 Instruction::PopFetchedObject pop;
1343 output->addInstruction(pop);
1346 for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1347 Instruction::FetchObject fetch;
1348 fetch.property = prop->index;
1349 fetch.line = prop->location.start.line;
1350 output->addInstruction(fetch);
1352 if (!prop->value->metadata.isEmpty()) {
1353 Instruction::StoreMetaObject meta;
1354 meta.data = output->indexForByteArray(prop->value->metadata);
1355 meta.aliasData = output->indexForByteArray(prop->value->synthdata);
1356 meta.propertyCache = -1;
1357 output->addInstruction(meta);
1360 genObjectBody(prop->value);
1362 Instruction::PopFetchedObject pop;
1363 output->addInstruction(pop);
1366 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1368 genValueTypeProperty(obj, prop);
1371 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1372 if (prop->isDeferred)
1375 genValueProperty(prop, obj);
1378 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1380 genValueTypeProperty(obj, prop);
1384 void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeScript::Object *obj,QDeclarativeScript::Property *prop)
1386 Instruction::FetchValueType fetch;
1387 fetch.property = prop->index;
1388 fetch.type = prop->type;
1389 fetch.bindingSkipList = 0;
1391 if (obj->type == -1 || output->types.at(obj->type).component) {
1392 // We only have to do this if this is a composite type. If it is a builtin
1393 // type it can't possibly already have bindings that need to be cleared.
1394 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1395 if (!vprop->values.isEmpty()) {
1396 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1397 fetch.bindingSkipList |= (1 << vprop->index);
1402 output->addInstruction(fetch);
1404 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1405 genPropertyAssignment(vprop, prop->value, prop);
1408 Instruction::PopValueType pop;
1409 pop.property = prop->index;
1410 pop.type = prop->type;
1411 pop.bindingSkipList = 0;
1412 output->addInstruction(pop);
1415 void QDeclarativeCompiler::genComponent(QDeclarativeScript::Object *obj)
1417 QDeclarativeScript::Object *root = obj->defaultProperty->values.first()->object;
1420 Instruction::CreateComponent create;
1421 create.line = root->location.start.line;
1422 create.column = root->location.start.column;
1423 create.endLine = root->location.end.line;
1424 create.isRoot = (compileState->root == obj);
1425 int createInstruction = output->addInstruction(create);
1426 int nextInstructionIndex = output->nextInstructionIndex();
1428 ComponentCompileState *oldCompileState = compileState;
1429 compileState = componentState(root);
1431 Instruction::Init init;
1432 init.bindingsSize = compileState->totalBindingsCount;
1433 init.parserStatusSize = compileState->parserStatusCount;
1434 init.contextCache = genContextCache();
1435 init.objectStackSize = compileState->objectDepth.maxDepth();
1436 init.listStackSize = compileState->listDepth.maxDepth();
1437 if (compileState->compiledBindingData.isEmpty())
1438 init.compiledBinding = -1;
1440 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
1441 output->addInstruction(init);
1443 if (!compileState->v8BindingProgram.isEmpty()) {
1444 Instruction::InitV8Bindings bindings;
1445 bindings.program = output->indexForString(compileState->v8BindingProgram);
1446 bindings.programIndex = compileState->v8BindingProgramIndex;
1447 bindings.line = compileState->v8BindingProgramLine;
1448 output->addInstruction(bindings);
1453 Instruction::SetDefault def;
1454 output->addInstruction(def);
1456 Instruction::Done done;
1457 output->addInstruction(done);
1459 output->instruction(createInstruction)->createComponent.count =
1460 output->nextInstructionIndex() - nextInstructionIndex;
1462 compileState = oldCompileState;
1464 if (!obj->id.isEmpty()) {
1465 Instruction::SetId id;
1466 id.value = output->indexForString(obj->id);
1467 id.index = obj->idIndex;
1468 output->addInstruction(id);
1471 if (obj == unitRoot) {
1472 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1473 output->rootPropertyCache->addref();
1477 bool QDeclarativeCompiler::buildComponent(QDeclarativeScript::Object *obj,
1478 const BindingContext &ctxt)
1480 // The special "Component" element can only have the id property and a
1481 // default property, that actually defines the component's tree
1483 compileState->objectDepth.push();
1485 // Find, check and set the "id" property (if any)
1486 Property *idProp = 0;
1487 if (obj->properties.isMany() ||
1488 (obj->properties.isOne() && obj->properties.first()->name() != id_string))
1489 COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
1491 if (!obj->properties.isEmpty())
1492 idProp = obj->properties.first();
1495 if (idProp->value || idProp->values.isMany() || idProp->values.first()->object)
1496 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1497 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1499 QString idVal = idProp->values.first()->primitive();
1501 if (compileState->ids.value(idVal))
1502 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1508 // Check the Component tree is well formed
1509 if (obj->defaultProperty &&
1510 (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
1511 (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
1512 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1514 if (!obj->dynamicProperties.isEmpty())
1515 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1516 if (!obj->dynamicSignals.isEmpty())
1517 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1518 if (!obj->dynamicSlots.isEmpty())
1519 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1521 QDeclarativeScript::Object *root = 0;
1522 if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
1523 root = obj->defaultProperty->values.first()->object;
1526 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1528 // Build the component tree
1529 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1531 compileState->objectDepth.pop();
1536 bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeScript::Object *obj,
1537 const BindingContext &ctxt)
1539 ComponentCompileState *oldComponentCompileState = compileState;
1540 compileState = pool->New<ComponentCompileState>();
1541 compileState->root = obj;
1542 compileState->nested = true;
1544 if (componentStats) {
1545 ComponentStat oldComponentStat = componentStats->componentStat;
1547 componentStats->componentStat = ComponentStat();
1548 componentStats->componentStat.lineNumber = obj->location.start.line;
1551 COMPILE_CHECK(buildObject(obj, ctxt));
1553 COMPILE_CHECK(completeComponentBuild());
1555 componentStats->componentStat = oldComponentStat;
1558 COMPILE_CHECK(buildObject(obj, ctxt));
1560 COMPILE_CHECK(completeComponentBuild());
1563 compileState = oldComponentCompileState;
1569 // Build a sub-object. A sub-object is one that was not created directly by
1570 // QML - such as a grouped property object, or an attached object. Sub-object's
1571 // can't have an id, involve a custom parser, have attached properties etc.
1572 bool QDeclarativeCompiler::buildSubObject(QDeclarativeScript::Object *obj, const BindingContext &ctxt)
1574 Q_ASSERT(obj->metatype);
1575 Q_ASSERT(!obj->defaultProperty);
1576 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1579 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1580 if (isSignalPropertyName(prop->name())) {
1581 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1583 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1590 int QDeclarativeCompiler::componentTypeRef()
1592 if (cachedComponentTypeRef == -1) {
1593 QDeclarativeType *t = QDeclarativeMetaType::qmlType(Component_import_string,1,0);
1594 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1595 if (output->types.at(ii).type == t) {
1596 cachedComponentTypeRef = ii;
1600 QDeclarativeCompiledData::TypeReference ref;
1601 ref.className = Component_string;
1603 output->types << ref;
1604 cachedComponentTypeRef = output->types.count() - 1;
1606 return cachedComponentTypeRef;
1609 bool QDeclarativeCompiler::buildSignal(QDeclarativeScript::Property *prop, QDeclarativeScript::Object *obj,
1610 const BindingContext &ctxt)
1612 Q_ASSERT(obj->metaObject());
1614 const QHashedStringRef &propName = prop->name();
1616 Q_ASSERT(propName.startsWith(on_string));
1617 QString name = propName.mid(2, -1).toString();
1619 // Note that the property name could start with any alpha or '_' or '$' character,
1620 // so we need to do the lower-casing of the first alpha character.
1621 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1622 if (name.at(firstAlphaIndex).isUpper()) {
1623 name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1628 bool notInRevision = false;
1630 QDeclarativePropertyData *sig = signal(obj, QStringRef(&name), ¬InRevision);
1634 if (notInRevision && 0 == property(obj, propName, 0)) {
1635 Q_ASSERT(obj->type != -1);
1636 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1637 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1639 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(elementName(obj)).arg(prop->name().toString()).arg(type.type->module()).arg(type.majorVersion).arg(type.minorVersion));
1641 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1645 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1647 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1651 if (prop->value || !prop->values.isOne())
1652 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1654 prop->index = sig->coreIndex;
1657 obj->addSignalProperty(prop);
1659 if (prop->values.first()->object) {
1660 COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1661 prop->values.first()->type = Value::SignalObject;
1663 prop->values.first()->type = Value::SignalExpression;
1665 if (!prop->values.first()->value.isScript())
1666 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1668 QString script = prop->values.first()->value.asScript().trimmed();
1669 if (script.isEmpty())
1670 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1672 prop->values.first()->signalExpressionContextStack = ctxt.stack;
1681 Returns true if (value) property \a prop exists on obj, false otherwise.
1683 bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeScript::Property *prop,
1684 QDeclarativeScript::Object *obj)
1686 if (prop->name().isEmpty())
1688 if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1691 return property(obj, prop->name()) != 0;
1694 bool QDeclarativeCompiler::buildProperty(QDeclarativeScript::Property *prop,
1695 QDeclarativeScript::Object *obj,
1696 const BindingContext &ctxt)
1698 if (prop->isEmpty())
1699 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1701 const QMetaObject *metaObject = obj->metaObject();
1702 Q_ASSERT(metaObject);
1704 if (isAttachedPropertyName(prop->name())) {
1705 // Setup attached property data
1707 if (ctxt.isSubContext()) {
1708 // Attached properties cannot be used on sub-objects. Sub-objects
1709 // always exist in a binding sub-context, which is what we test
1711 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1714 QDeclarativeType *type = 0;
1715 QDeclarativeImportedNamespace *typeNamespace = 0;
1716 unit->imports().resolveType(prop->name().toString(), &type, 0, 0, 0, &typeNamespace);
1718 if (typeNamespace) {
1719 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1722 } else if (!type || !type->attachedPropertiesType()) {
1723 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1727 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1729 Q_ASSERT(type->attachedPropertiesFunction());
1730 prop->index = type->attachedPropertiesId();
1731 prop->value->metatype = type->attachedPropertiesType();
1733 // Setup regular property data
1734 bool notInRevision = false;
1735 QDeclarativePropertyData *d =
1736 prop->name().isEmpty()?0:property(obj, prop->name(), ¬InRevision);
1738 if (d == 0 && notInRevision) {
1739 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1740 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1742 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(elementName(obj)).arg(prop->name().toString()).arg(type.type->module()).arg(type.majorVersion).arg(type.minorVersion));
1744 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1747 prop->index = d->coreIndex;
1749 } else if (prop->isDefault) {
1750 QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
1751 QDeclarativePropertyData defaultPropertyData;
1752 defaultPropertyData.load(p, engine);
1754 prop->setName(QLatin1String(p.name()));
1755 prop->core = defaultPropertyData;
1756 prop->index = prop->core.coreIndex;
1759 // We can't error here as the "id" property does not require a
1760 // successful index resolution
1761 if (prop->index != -1)
1762 prop->type = prop->core.propType;
1764 // Check if this is an alias
1765 if (prop->index != -1 &&
1767 prop->parent->type != -1 &&
1768 output->types.at(prop->parent->type).component) {
1770 QDeclarativePropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1771 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1772 prop->isAlias = true;
1775 if (prop->index != -1 && !prop->values.isEmpty())
1776 prop->parent->setBindingBit(prop->index);
1779 if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1781 // The magic "id" behavior doesn't apply when "id" is resolved as a
1782 // default property or to sub-objects (which are always in binding
1784 COMPILE_CHECK(buildIdProperty(prop, obj));
1785 if (prop->type == QVariant::String &&
1786 prop->values.first()->value.isString())
1787 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1789 } else if (isAttachedPropertyName(prop->name())) {
1791 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1793 } else if (prop->index == -1) {
1795 if (prop->isDefault) {
1796 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1798 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1801 } else if (prop->value) {
1803 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1805 } else if (prop->core.isQList()) {
1807 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1809 } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) {
1811 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1815 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1822 bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
1823 QDeclarativeScript::Property *nsProp,
1824 QDeclarativeScript::Object *obj,
1825 const BindingContext &ctxt)
1828 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1830 for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1832 if (!isAttachedPropertyName(prop->name()))
1833 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1835 // Setup attached property data
1837 QDeclarativeType *type = 0;
1838 unit->imports().resolveType(ns, prop->name().toString(), &type, 0, 0, 0);
1840 if (!type || !type->attachedPropertiesType())
1841 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1844 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1846 Q_ASSERT(type->attachedPropertiesFunction());
1847 prop->index = type->index();
1848 prop->value->metatype = type->attachedPropertiesType();
1850 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1856 void QDeclarativeCompiler::genValueProperty(QDeclarativeScript::Property *prop,
1857 QDeclarativeScript::Object *obj)
1859 if (prop->core.isQList()) {
1860 genListProperty(prop, obj);
1862 genPropertyAssignment(prop, obj);
1866 void QDeclarativeCompiler::genListProperty(QDeclarativeScript::Property *prop,
1867 QDeclarativeScript::Object *obj)
1869 int listType = enginePrivate->listType(prop->type);
1871 Instruction::FetchQList fetch;
1872 fetch.property = prop->index;
1873 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1874 fetch.type = listType;
1875 output->addInstruction(fetch);
1877 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1879 if (v->type == Value::CreatedObject) {
1881 genObject(v->object);
1882 if (listTypeIsInterface) {
1883 Instruction::AssignObjectList assign;
1884 assign.line = prop->location.start.line;
1885 output->addInstruction(assign);
1887 Instruction::StoreObjectQList store;
1888 output->addInstruction(store);
1891 } else if (v->type == Value::PropertyBinding) {
1893 genBindingAssignment(v, prop, obj);
1899 Instruction::PopQList pop;
1900 output->addInstruction(pop);
1903 void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeScript::Property *prop,
1904 QDeclarativeScript::Object *obj,
1905 QDeclarativeScript::Property *valueTypeProperty)
1907 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1909 Q_ASSERT(v->type == Value::CreatedObject ||
1910 v->type == Value::PropertyBinding ||
1911 v->type == Value::Literal);
1913 if (v->type == Value::CreatedObject) {
1915 genObject(v->object);
1917 if (QDeclarativeMetaType::isInterface(prop->type)) {
1919 Instruction::StoreInterface store;
1920 store.line = v->object->location.start.line;
1921 store.propertyIndex = prop->index;
1922 output->addInstruction(store);
1924 } else if (prop->type == QMetaType::QVariant) {
1926 if (prop->core.isVMEProperty()) {
1927 Instruction::StoreVarObject store;
1928 store.line = v->object->location.start.line;
1929 store.propertyIndex = prop->index;
1930 output->addInstruction(store);
1932 Instruction::StoreVariantObject store;
1933 store.line = v->object->location.start.line;
1934 store.propertyIndex = prop->index;
1935 output->addInstruction(store);
1941 Instruction::StoreObject store;
1942 store.line = v->object->location.start.line;
1943 store.propertyIndex = prop->index;
1944 output->addInstruction(store);
1947 } else if (v->type == Value::PropertyBinding) {
1949 genBindingAssignment(v, prop, obj, valueTypeProperty);
1951 } else if (v->type == Value::Literal) {
1953 genLiteralAssignment(prop, v);
1959 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
1961 Q_ASSERT(v->type == Value::ValueSource ||
1962 v->type == Value::ValueInterceptor);
1964 if (v->type == Value::ValueSource) {
1965 genObject(v->object);
1967 Instruction::StoreValueSource store;
1968 if (valueTypeProperty) {
1969 store.property = genValueTypeData(prop, valueTypeProperty);
1972 store.property = prop->core;
1975 QDeclarativeType *valueType = toQmlType(v->object);
1976 store.castValue = valueType->propertyValueSourceCast();
1977 output->addInstruction(store);
1979 } else if (v->type == Value::ValueInterceptor) {
1980 genObject(v->object);
1982 Instruction::StoreValueInterceptor store;
1983 if (valueTypeProperty) {
1984 store.property = genValueTypeData(prop, valueTypeProperty);
1987 store.property = prop->core;
1990 QDeclarativeType *valueType = toQmlType(v->object);
1991 store.castValue = valueType->propertyValueInterceptorCast();
1992 output->addInstruction(store);
1998 bool QDeclarativeCompiler::buildIdProperty(QDeclarativeScript::Property *prop,
1999 QDeclarativeScript::Object *obj)
2002 prop->values.isMany() ||
2003 prop->values.first()->object)
2004 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
2006 QDeclarativeScript::Value *idValue = prop->values.first();
2007 QString val = idValue->primitive();
2009 COMPILE_CHECK(checkValidId(idValue, val));
2011 if (compileState->ids.value(val))
2012 COMPILE_EXCEPTION(prop, tr("id is not unique"));
2014 prop->values.first()->type = Value::Id;
2022 void QDeclarativeCompiler::addId(const QString &id, QDeclarativeScript::Object *obj)
2025 Q_ASSERT(!compileState->ids.value(id));
2026 Q_ASSERT(obj->id == id);
2027 obj->idIndex = compileState->ids.count();
2028 compileState->ids.append(obj);
2031 void QDeclarativeCompiler::addBindingReference(BindingReference *ref)
2033 Q_ASSERT(ref->value && !ref->value->bindingReference);
2034 ref->value->bindingReference = ref;
2035 compileState->totalBindingsCount++;
2036 compileState->bindings.prepend(ref);
2039 void QDeclarativeCompiler::saveComponentState()
2041 Q_ASSERT(compileState->root);
2042 Q_ASSERT(compileState->root->componentCompileState == 0);
2044 compileState->root->componentCompileState = compileState;
2047 componentStats->savedComponentStats.append(componentStats->componentStat);
2050 QDeclarativeCompilerTypes::ComponentCompileState *
2051 QDeclarativeCompiler::componentState(QDeclarativeScript::Object *obj)
2053 Q_ASSERT(obj->componentCompileState);
2054 return obj->componentCompileState;
2057 // Build attached property object. In this example,
2061 // GridView is an attached property object.
2062 bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeScript::Property *prop,
2063 QDeclarativeScript::Object *obj,
2064 const BindingContext &ctxt)
2066 Q_ASSERT(prop->value);
2067 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
2069 compileState->objectDepth.push();
2071 obj->addAttachedProperty(prop);
2073 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2075 compileState->objectDepth.pop();
2081 // Build "grouped" properties. In this example:
2083 // font.pointSize: 12
2084 // font.family: "Helvetica"
2086 // font is a nested property. pointSize and family are not.
2087 bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeScript::Property *prop,
2088 QDeclarativeScript::Object *obj,
2089 const BindingContext &ctxt)
2091 Q_ASSERT(prop->type != 0);
2092 Q_ASSERT(prop->index != -1);
2094 if (QDeclarativeValueTypeFactory::isValueType(prop->type)) {
2095 if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
2097 if (!prop->values.isEmpty()) {
2098 if (prop->values.first()->location < prop->value->location) {
2099 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
2101 COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
2105 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) {
2106 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2110 if (prop->isAlias) {
2111 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
2112 vtProp->isAlias = true;
2116 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
2117 prop->value, obj, ctxt.incr()));
2118 obj->addValueTypeProperty(prop);
2120 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2124 // Load the nested property's meta type
2125 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
2126 if (!prop->value->metatype)
2127 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2129 if (!prop->values.isEmpty())
2130 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
2132 obj->addGroupedProperty(prop);
2134 compileState->objectDepth.push();
2136 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2138 compileState->objectDepth.pop();
2144 bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
2145 QDeclarativeScript::Object *obj,
2146 QDeclarativeScript::Object *baseObj,
2147 const BindingContext &ctxt)
2149 compileState->objectDepth.push();
2151 if (obj->defaultProperty)
2152 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
2153 obj->metatype = type->metaObject();
2155 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
2157 QDeclarativePropertyData *d = property(obj, prop->name());
2159 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
2161 prop->index = d->coreIndex;
2162 prop->type = d->propType;
2164 prop->isValueTypeSubProperty = true;
2167 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
2169 if (prop->values.isMany()) {
2170 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
2171 } else if (!prop->values.isEmpty()) {
2172 QDeclarativeScript::Value *value = prop->values.first();
2174 if (value->object) {
2175 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
2176 } else if (value->value.isScript()) {
2177 // ### Check for writability
2179 //optimization for <Type>.<EnumValue> enum assignments
2180 bool isEnumAssignment = false;
2182 if (prop->core.isEnum())
2183 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, value, &isEnumAssignment));
2185 if (isEnumAssignment) {
2186 value->type = Value::Literal;
2188 BindingReference *reference = pool->New<BindingReference>();
2189 reference->expression = value->value;
2190 reference->property = prop;
2191 reference->value = value;
2192 reference->bindingContext = ctxt;
2193 reference->bindingContext.owner++;
2194 addBindingReference(reference);
2195 value->type = Value::PropertyBinding;
2198 COMPILE_CHECK(testLiteralAssignment(prop, value));
2199 value->type = Value::Literal;
2203 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2204 Q_ASSERT(v->object);
2206 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
2209 obj->addValueProperty(prop);
2212 compileState->objectDepth.pop();
2217 // Build assignments to QML lists. QML lists are properties of type
2218 // QDeclarativeListProperty<T>. List properties can accept a list of
2219 // objects, or a single binding.
2220 bool QDeclarativeCompiler::buildListProperty(QDeclarativeScript::Property *prop,
2221 QDeclarativeScript::Object *obj,
2222 const BindingContext &ctxt)
2224 Q_ASSERT(prop->core.isQList());
2226 compileState->listDepth.push();
2230 obj->addValueProperty(prop);
2232 int listType = enginePrivate->listType(t);
2233 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
2235 bool assignedBinding = false;
2236 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2238 v->type = Value::CreatedObject;
2239 COMPILE_CHECK(buildObject(v->object, ctxt));
2241 // We check object coercian here. We check interface assignment
2243 if (!listTypeIsInterface) {
2244 if (!canCoerce(listType, v->object)) {
2245 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2249 } else if (v->value.isScript()) {
2250 if (assignedBinding)
2251 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2253 assignedBinding = true;
2254 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2255 v->type = Value::PropertyBinding;
2257 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2261 compileState->listDepth.pop();
2266 // Compiles an assignment to a QDeclarativeScriptString property
2267 bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeScript::Property *prop,
2268 QDeclarativeScript::Object *obj,
2269 const BindingContext &ctxt)
2271 if (prop->values.isMany())
2272 COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2274 if (prop->values.first()->object)
2275 COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2277 prop->scriptStringScope = ctxt.stack;
2278 obj->addScriptStringProperty(prop);
2283 // Compile regular property assignments of the form "property: <value>"
2284 bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeScript::Property *prop,
2285 QDeclarativeScript::Object *obj,
2286 const BindingContext &ctxt)
2288 obj->addValueProperty(prop);
2290 if (prop->values.isMany())
2291 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2293 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2296 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2300 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2305 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2306 Q_ASSERT(v->object);
2307 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2313 // Compile assigning a single object instance to a regular property
2314 bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeScript::Property *prop,
2315 QDeclarativeScript::Object *obj,
2316 QDeclarativeScript::Value *v,
2317 const BindingContext &ctxt)
2319 Q_ASSERT(prop->index != -1);
2320 Q_ASSERT(v->object->type != -1);
2322 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2323 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2325 if (QDeclarativeMetaType::isInterface(prop->type)) {
2327 // Assigning an object to an interface ptr property
2328 COMPILE_CHECK(buildObject(v->object, ctxt));
2330 v->type = Value::CreatedObject;
2332 } else if (prop->type == QMetaType::QVariant) {
2334 // Assigning an object to a QVariant
2335 COMPILE_CHECK(buildObject(v->object, ctxt));
2337 v->type = Value::CreatedObject;
2339 // Normally buildObject() will set this up, but we need the static
2340 // meta object earlier to test for assignability. It doesn't matter
2341 // that there may still be outstanding synthesized meta object changes
2342 // on this type, as they are not relevant for assignability testing
2343 v->object->metatype = output->types.at(v->object->type).metaObject();
2344 Q_ASSERT(v->object->metaObject());
2346 // We want to raw metaObject here as the raw metaobject is the
2347 // actual property type before we applied any extensions that might
2348 // effect the properties on the type, but don't effect assignability
2349 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2351 // Will be true if the assgned type inherits propertyMetaObject
2352 bool isAssignable = false;
2353 // Determine isAssignable value
2354 if (propertyMetaObject) {
2355 const QMetaObject *c = v->object->metatype;
2357 isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject));
2358 c = c->superClass();
2363 // Simple assignment
2364 COMPILE_CHECK(buildObject(v->object, ctxt));
2366 v->type = Value::CreatedObject;
2367 } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) {
2368 // Automatic "Component" insertion
2369 QDeclarativeScript::Object *root = v->object;
2370 QDeclarativeScript::Object *component = pool->New<Object>();
2371 component->type = componentTypeRef();
2372 component->typeName = QStringLiteral("Qt/Component");
2373 component->metatype = &QDeclarativeComponent::staticMetaObject;
2374 component->location = root->location;
2375 QDeclarativeScript::Value *componentValue = pool->New<Value>();
2376 componentValue->object = root;
2377 component->getDefaultProperty()->addValue(componentValue);
2378 v->object = component;
2379 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2381 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2388 // Compile assigning a single object instance to a regular property using the "on" syntax.
2392 // NumberAnimation on x { }
2394 bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeScript::Property *prop,
2395 QDeclarativeScript::Object *obj,
2396 QDeclarativeScript::Object *baseObj,
2397 QDeclarativeScript::Value *v,
2398 const BindingContext &ctxt)
2400 Q_ASSERT(prop->index != -1);
2401 Q_ASSERT(v->object->type != -1);
2405 if (!prop->core.isWritable())
2406 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2409 // Normally buildObject() will set this up, but we need the static
2410 // meta object earlier to test for assignability. It doesn't matter
2411 // that there may still be outstanding synthesized meta object changes
2412 // on this type, as they are not relevant for assignability testing
2413 v->object->metatype = output->types.at(v->object->type).metaObject();
2414 Q_ASSERT(v->object->metaObject());
2416 // Will be true if the assigned type inherits QDeclarativePropertyValueSource
2417 bool isPropertyValue = false;
2418 // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor
2419 bool isPropertyInterceptor = false;
2420 if (QDeclarativeType *valueType = toQmlType(v->object)) {
2421 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2422 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2425 if (isPropertyValue || isPropertyInterceptor) {
2426 // Assign as a property value source
2427 COMPILE_CHECK(buildObject(v->object, ctxt));
2429 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2430 buildDynamicMeta(baseObj, ForceCreation);
2431 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2433 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(v->object->typeName).arg(prop->name().toString()));
2439 // Compile assigning a literal or binding to a regular property
2440 bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeScript::Property *prop,
2441 QDeclarativeScript::Object *obj,
2442 QDeclarativeScript::Value *v,
2443 const BindingContext &ctxt)
2445 Q_ASSERT(prop->index != -1);
2447 if (v->value.isScript()) {
2449 //optimization for <Type>.<EnumValue> enum assignments
2450 if (prop->core.isEnum()) {
2451 bool isEnumAssignment = false;
2452 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, v, &isEnumAssignment));
2453 if (isEnumAssignment) {
2454 v->type = Value::Literal;
2459 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2461 v->type = Value::PropertyBinding;
2465 COMPILE_CHECK(testLiteralAssignment(prop, v));
2467 v->type = Value::Literal;
2473 bool QDeclarativeCompiler::testQualifiedEnumAssignment(QDeclarativeScript::Property *prop,
2474 QDeclarativeScript::Object *obj,
2475 QDeclarativeScript::Value *v,
2478 *isAssignment = false;
2479 if (!prop->core.isEnum())
2482 QMetaProperty mprop = obj->metaObject()->property(prop->index);
2484 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2485 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2487 QString string = v->value.asString();
2488 if (!string.at(0).isUpper())
2491 QStringList parts = string.split(QLatin1Char('.'));
2492 if (parts.count() != 2)
2495 QString typeName = parts.at(0);
2496 QDeclarativeType *type = 0;
2497 unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
2499 //handle enums on value types (where obj->typeName is empty)
2500 QString objTypeName = obj->typeName;
2501 if (objTypeName.isEmpty()) {
2502 QDeclarativeType *objType = toQmlType(obj);
2504 objTypeName = objType->qmlTypeName();
2510 QString enumValue = parts.at(1);
2514 if (objTypeName == type->qmlTypeName()) {
2515 // When these two match, we can short cut the search
2516 if (mprop.isFlagType()) {
2517 value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
2519 value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
2522 // Otherwise we have to search the whole type
2523 // This matches the logic in QV8TypeWrapper
2524 QByteArray enumName = enumValue.toUtf8();
2525 const QMetaObject *metaObject = type->baseMetaObject();
2527 for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
2528 QMetaEnum e = metaObject->enumerator(ii);
2529 value = e.keyToValue(enumName.constData(), &ok);
2536 v->type = Value::Literal;
2537 v->value = QDeclarativeScript::Variant((double)value);
2538 *isAssignment = true;
2543 struct StaticQtMetaObject : public QObject
2545 static const QMetaObject *get()
2546 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2549 // Similar logic to above, but not knowing target property.
2550 int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const
2552 int dot = script.indexOf('.');
2554 const QByteArray &scope = script.left(dot);
2555 QDeclarativeType *type = 0;
2556 unit->imports().resolveType(QString::fromUtf8(script.left(dot)), &type, 0, 0, 0, 0);
2557 if (!type && scope != "Qt")
2559 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2560 const char *key = script.constData() + dot+1;
2561 int i = mo->enumeratorCount();
2564 int v = mo->enumerator(i).keyToValue(key, &ok);
2572 const QMetaObject *QDeclarativeCompiler::resolveType(const QString& name) const
2574 QDeclarativeType *qmltype = 0;
2575 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2579 return qmltype->metaObject();
2582 // similar to logic of completeComponentBuild, but also sticks data
2583 // into primitives at the end
2584 int QDeclarativeCompiler::rewriteBinding(const QDeclarativeScript::Variant& value, const QString& name)
2586 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2587 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1));
2589 QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0);
2591 return output->indexForString(rewrite);
2594 QString QDeclarativeCompiler::rewriteSignalHandler(const QString &handler, const QString &name)
2596 QDeclarativeRewrite::RewriteSignalHandler rewriteSignalHandler;
2597 return rewriteSignalHandler(handler, name);
2600 // Ensures that the dynamic meta specification on obj is valid
2601 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeScript::Object *obj)
2603 bool seenDefaultProperty = false;
2605 // We use a coarse grain, 31 bit hash to check if there are duplicates.
2606 // Calculating the hash for the names is not a waste as we have to test
2607 // them against the illegalNames set anyway.
2608 QHashField propNames;
2609 QHashField methodNames;
2612 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2613 const QDeclarativeScript::Object::DynamicProperty &prop = *p;
2615 if (prop.isDefaultProperty) {
2616 if (seenDefaultProperty)
2617 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2618 seenDefaultProperty = true;
2621 if (propNames.testAndSet(prop.name.hash())) {
2622 for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p;
2623 p2 = obj->dynamicProperties.next(p2)) {
2624 if (p2->name == prop.name)
2625 COMPILE_EXCEPTION(&prop, tr("Duplicate property name"));
2629 if (prop.name.at(0).isUpper())
2630 COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
2632 if (enginePrivate->v8engine()->illegalNames().contains(prop.name))
2633 COMPILE_EXCEPTION(&prop, tr("Illegal property name"));
2636 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2637 const QDeclarativeScript::Object::DynamicSignal &currSig = *s;
2639 if (methodNames.testAndSet(currSig.name.hash())) {
2640 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2641 s2 = obj->dynamicSignals.next(s2)) {
2642 if (s2->name == currSig.name)
2643 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2647 if (currSig.name.at(0).isUpper())
2648 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2649 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2650 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2653 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2654 const QDeclarativeScript::Object::DynamicSlot &currSlot = *s;
2656 if (methodNames.testAndSet(currSlot.name.hash())) {
2657 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2658 s2 = obj->dynamicSignals.next(s2)) {
2659 if (s2->name == currSlot.name)
2660 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2662 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2663 s2 = obj->dynamicSlots.next(s2)) {
2664 if (s2->name == currSlot.name)
2665 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2669 if (currSlot.name.at(0).isUpper())
2670 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2671 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2672 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2678 bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeScript::Object *obj)
2680 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2681 p = obj->dynamicProperties.next(p)) {
2683 if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2686 Property *property = 0;
2687 if (p->isDefaultProperty) {
2688 property = obj->getDefaultProperty();
2690 property = obj->getProperty(p->name);
2691 if (!property->values.isEmpty())
2692 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2696 property->isReadOnlyDeclaration = true;
2698 if (property->value)
2699 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2701 property->values.append(p->defaultValue->values);
2706 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2708 bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeScript::Object *obj, DynamicMetaMode mode)
2711 Q_ASSERT(obj->metatype);
2713 if (mode != ForceCreation &&
2714 obj->dynamicProperties.isEmpty() &&
2715 obj->dynamicSignals.isEmpty() &&
2716 obj->dynamicSlots.isEmpty())
2719 bool resolveAlias = (mode == ResolveAliases);
2721 const Object::DynamicProperty *defaultProperty = 0;
2723 int varPropCount = 0;
2724 int totalPropCount = 0;
2725 int firstPropertyVarIndex = 0;
2727 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2729 if (p->type == Object::DynamicProperty::Alias)
2731 if (p->type == Object::DynamicProperty::Var)
2734 if (p->isDefaultProperty &&
2735 (resolveAlias || p->type != Object::DynamicProperty::Alias))
2736 defaultProperty = p;
2738 if (!resolveAlias) {
2739 // No point doing this for both the alias and non alias cases
2740 QDeclarativePropertyData *d = property(obj, p->name);
2741 if (d && d->isFinal())
2742 COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2746 bool buildData = resolveAlias || aliasCount == 0;
2748 QByteArray dynamicData;
2750 typedef QDeclarativeVMEMetaData VMD;
2752 dynamicData = QByteArray(sizeof(QDeclarativeVMEMetaData) +
2753 (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) +
2754 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2755 aliasCount * sizeof(VMD::AliasData), 0);
2758 int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1);
2760 QByteArray newClassName = obj->metatype->className();
2761 newClassName.append("_QML_");
2762 newClassName.append(QByteArray::number(uniqueClassId));
2764 if (compileState->root == obj && !compileState->nested) {
2765 QString path = output->url.path();
2766 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2767 if (lastSlash > -1) {
2768 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2769 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2770 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId);
2774 QFastMetaBuilder builder;
2775 QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(),
2776 obj->dynamicProperties.count() - (resolveAlias?0:aliasCount),
2777 obj->dynamicSlots.count(),
2778 obj->dynamicSignals.count() + obj->dynamicProperties.count(),
2779 defaultProperty?1:0);
2782 Object::DynamicProperty::Type dtype;
2784 const char *cppType;
2785 } builtinTypes[] = {
2786 { Object::DynamicProperty::Var, 0, "QVariant" },
2787 { Object::DynamicProperty::Variant, 0, "QVariant" },
2788 { Object::DynamicProperty::Int, QMetaType::Int, "int" },
2789 { Object::DynamicProperty::Bool, QMetaType::Bool, "bool" },
2790 { Object::DynamicProperty::Real, QMetaType::Double, "double" },
2791 { Object::DynamicProperty::String, QMetaType::QString, "QString" },
2792 { Object::DynamicProperty::Url, QMetaType::QUrl, "QUrl" },
2793 { Object::DynamicProperty::Color, QMetaType::QColor, "QColor" },
2794 { Object::DynamicProperty::Time, QMetaType::QTime, "QTime" },
2795 { Object::DynamicProperty::Date, QMetaType::QDate, "QDate" },
2796 { Object::DynamicProperty::DateTime, QMetaType::QDateTime, "QDateTime" },
2798 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2799 QFastMetaBuilder::StringRef typeRefs[builtinTypeCount];
2801 // Reserve dynamic properties
2802 if (obj->dynamicProperties.count()) {
2803 typedef QDeclarativeVMEMetaData VMD;
2805 int effectivePropertyIndex = 0;
2806 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2808 // Reserve space for name
2809 p->nameRef = builder.newString(p->name.utf8length());
2811 int propertyType = 0;
2812 bool readonly = false;
2813 QFastMetaBuilder::StringRef typeRef;
2815 if (p->type == Object::DynamicProperty::Alias) {
2817 } else if (p->type < builtinTypeCount) {
2818 Q_ASSERT(builtinTypes[p->type].dtype == p->type);
2819 propertyType = builtinTypes[p->type].metaType;
2820 if (typeRefs[p->type].isEmpty())
2821 typeRefs[p->type] = builder.newString(strlen(builtinTypes[p->type].cppType));
2822 typeRef = typeRefs[p->type];
2823 if (p->type == Object::DynamicProperty::Variant)
2827 Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
2828 p->type == Object::DynamicProperty::Custom);
2830 // XXX don't double resolve this in the case of an alias run
2832 QByteArray customTypeName;
2833 QDeclarativeType *qmltype = 0;
2835 if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
2836 COMPILE_EXCEPTION(p, tr("Invalid property type"));
2839 QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(QUrl(url));
2841 Q_ASSERT(tdata->isComplete());
2843 QDeclarativeCompiledData *data = tdata->compiledData();
2844 customTypeName = data->root->className();
2848 customTypeName = qmltype->typeName();
2851 if (p->type == Object::DynamicProperty::Custom) {
2852 customTypeName += '*';
2853 propertyType = QMetaType::QObjectStar;
2856 customTypeName = QByteArray("QDeclarativeListProperty<") + customTypeName + QByteArray(">");
2857 propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
2860 p->resolvedCustomTypeName = pool->NewByteArray(customTypeName);
2861 p->typeRef = builder.newString(customTypeName.length());
2862 typeRef = p->typeRef;
2865 if (p->type == Object::DynamicProperty::Var)
2872 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2873 vmd->propertyCount++;
2874 (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType;
2877 if (p->type < builtinTypeCount)
2878 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef, (QMetaType::Type)propertyType,
2879 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2880 effectivePropertyIndex);
2882 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef,
2883 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2884 effectivePropertyIndex);
2886 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2887 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2889 effectivePropertyIndex++;
2893 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2895 vmd->varPropertyCount = varPropCount;
2896 firstPropertyVarIndex = effectivePropertyIndex;
2897 totalPropCount = varPropCount + effectivePropertyIndex;
2898 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2899 if (p->type == Object::DynamicProperty::Var) {
2900 QFastMetaBuilder::StringRef typeRef = typeRefs[p->type];
2902 vmd->propertyCount++;
2903 (vmd->propertyData() + effectivePropertyIndex)->propertyType = -1;
2906 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef,
2907 (QMetaType::Type)-1,
2908 p->isReadOnly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2909 effectivePropertyIndex);
2911 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2912 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2914 effectivePropertyIndex++;
2921 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2922 if (p->type == Object::DynamicProperty::Alias) {
2924 Q_ASSERT(buildData);
2925 ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++;
2926 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex,
2929 // Even if we aren't resolving the alias, we need a fake signal so that the
2930 // metaobject remains consistent across the resolve and non-resolve alias runs
2931 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2932 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2933 effectivePropertyIndex++;
2940 // Reserve default property
2941 QFastMetaBuilder::StringRef defPropRef;
2942 if (defaultProperty) {
2943 defPropRef = builder.newString(strlen("DefaultProperty"));
2944 builder.setClassInfo(0, defPropRef, defaultProperty->nameRef);
2947 // Reserve dynamic signals
2948 int signalIndex = 0;
2949 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2951 int paramCount = s->parameterNames.count();
2953 int signatureSize = s->name.utf8length() + 2 /* paren */;
2955 if (paramCount) signatureSize += s->parameterTypesLength() + (paramCount - 1) /* commas */;
2956 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1) /* commas */;
2958 s->signatureRef = builder.newString(signatureSize);
2959 if (namesSize) s->parameterNamesRef = builder.newString(namesSize);
2962 ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++;
2964 builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->signatureRef, s->parameterNamesRef);
2968 // Reserve dynamic slots
2969 if (obj->dynamicSlots.count()) {
2971 // Allocate QVariant string
2972 if (typeRefs[0].isEmpty())
2973 typeRefs[0] = builder.newString(strlen(builtinTypes[0].cppType));
2975 typedef QDeclarativeVMEMetaData VMD;
2977 int methodIndex = 0;
2978 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2979 int paramCount = s->parameterNames.count();
2981 int signatureSize = s->name.utf8length() + 2 /* paren */;
2983 if (paramCount) signatureSize += (paramCount * strlen("QVariant") + (paramCount - 1));
2984 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
2986 s->signatureRef = builder.newString(signatureSize);
2987 if (namesSize) s->parameterNamesRef = builder.newString(namesSize);
2989 builder.setMethod(methodIndex, s->signatureRef, s->parameterNamesRef, typeRefs[0]);
2993 funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ +
2994 namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
2995 funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
2996 for (int jj = 0; jj < paramCount; ++jj) {
2997 if (jj) funcScript.append(QLatin1Char(','));
2998 funcScript.append(QLatin1String(s->parameterNames.at(jj)));
3000 funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
3002 VMD::MethodData methodData = { s->parameterNames.count(), 0,
3003 funcScript.length(),
3004 s->location.start.line };
3006 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
3009 VMD::MethodData &md = *(vmd->methodData() + methodIndex);
3011 md.bodyOffset = dynamicData.size();
3013 dynamicData.append((const char *)funcScript.constData(),
3014 (funcScript.length() * sizeof(QChar)));
3021 // Now allocate used builtin types
3022 for (int ii = 0; ii < builtinTypeCount; ++ii) {
3023 if (!typeRefs[ii].isEmpty())
3024 typeRefs[ii].load(builtinTypes[ii].cppType);
3027 // Now allocate properties
3028 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
3030 char *d = p->changedSignatureRef.data();
3031 p->name.writeUtf8(d);
3032 strcpy(d + p->name.utf8length(), "Changed()");
3034 if (p->type == Object::DynamicProperty::Alias && !resolveAlias)
3037 p->nameRef.load(p->name);
3039 if (p->type >= builtinTypeCount) {
3040 Q_ASSERT(p->resolvedCustomTypeName);
3041 p->typeRef.load(*p->resolvedCustomTypeName);
3045 // Allocate default property if necessary
3046 if (defaultProperty)
3047 strcpy(defPropRef.data(), "DefaultProperty");
3049 // Now allocate signals
3050 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
3052 char *d = s->signatureRef.data();
3053 char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data();
3054 s->name.writeUtf8(d); d += s->name.utf8length();
3057 for (int jj = 0; jj < s->parameterNames.count(); ++jj) {
3058 if (jj != 0) { *d++ = ','; *d2++ = ','; }
3059 strcpy(d, s->parameterTypes.at(jj).constData());
3060 d += s->parameterTypes.at(jj).length();
3061 s->parameterNames.at(jj).writeUtf8(d2);
3062 d2 += s->parameterNames.at(jj).utf8length();
3069 // Now allocate methods
3070 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3071 char *d = s->signatureRef.data();
3072 char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data();
3073 s->name.writeUtf8(d); d += s->name.utf8length();
3075 for (int jj = 0; jj < s->parameterNames.count(); ++jj) {
3076 if (jj != 0) { *d++ = ','; *d2++ = ','; }
3077 strcpy(d, "QVariant");
3078 d += strlen("QVariant");
3079 strcpy(d2, s->parameterNames.at(jj).constData());
3080 d2 += s->parameterNames.at(jj).length();
3087 // Now allocate class name
3088 classNameRef.load(newClassName);
3090 obj->metadata = builder.toData();
3091 builder.fromData(&obj->extObject, obj->metatype, obj->metadata);
3093 if (mode == IgnoreAliases && aliasCount)
3094 compileState->aliasingObjects.append(obj);
3096 obj->synthdata = dynamicData;
3098 if (obj->synthCache) {
3099 obj->synthCache->release();
3100 obj->synthCache = 0;
3103 if (obj->type != -1) {
3104 QDeclarativePropertyCache *cache = output->types[obj->type].createPropertyCache(engine)->copy();
3105 cache->append(engine, &obj->extObject,
3106 QDeclarativePropertyData::NoFlags,
3107 QDeclarativePropertyData::IsVMEFunction,
3108 QDeclarativePropertyData::IsVMESignal);
3110 // now we modify the flags appropriately for var properties.
3111 int propertyOffset = obj->extObject.propertyOffset();
3112 QDeclarativePropertyData *currPropData = 0;
3113 for (int pvi = firstPropertyVarIndex; pvi < totalPropCount; ++pvi) {
3114 currPropData = cache->property(pvi + propertyOffset);
3115 currPropData->setFlags(currPropData->getFlags() | QDeclarativePropertyData::IsVMEProperty);
3118 obj->synthCache = cache;
3124 bool QDeclarativeCompiler::checkValidId(QDeclarativeScript::Value *v, const QString &val)
3127 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
3129 QChar ch = val.at(0);
3130 if (ch.isLetter() && !ch.isLower())
3131 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
3133 QChar u(QLatin1Char('_'));
3134 if (!ch.isLetter() && ch != u)
3135 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
3137 for (int ii = 1; ii < val.count(); ++ii) {
3139 if (!ch.isLetterOrNumber() && ch != u)
3140 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
3143 if (enginePrivate->v8engine()->illegalNames().contains(val))
3144 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
3149 #include <private/qdeclarativejsparser_p.h>
3151 static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node)
3153 if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) {
3155 static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name.toString();
3156 return QStringList() << name;
3157 } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) {
3158 QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node);
3160 QStringList rv = astNodeToStringList(expr->base);
3163 rv.append(expr->name.toString());
3166 return QStringList();
3169 bool QDeclarativeCompiler::compileAlias(QFastMetaBuilder &builder,
3171 QDeclarativeScript::Object *obj,
3172 int propIndex, int aliasIndex,
3173 Object::DynamicProperty &prop)
3175 if (!prop.defaultValue)
3176 COMPILE_EXCEPTION(obj, tr("No property alias location"));
3178 if (!prop.defaultValue->values.isOne() ||
3179 prop.defaultValue->values.first()->object ||
3180 !prop.defaultValue->values.first()->value.isScript())
3181 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3183 QDeclarativeJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST();
3185 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
3187 QStringList alias = astNodeToStringList(node);
3189 if (alias.count() < 1 || alias.count() > 3)
3190 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
3192 QDeclarativeScript::Object *idObject = compileState->ids.value(alias.at(0));
3194 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
3196 QByteArray typeName;
3201 bool writable = false;
3202 bool resettable = false;
3203 if (alias.count() == 2 || alias.count() == 3) {
3204 propIdx = indexOfProperty(idObject, alias.at(1));
3206 if (-1 == propIdx) {
3207 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3208 } else if (propIdx > 0xFFFF) {
3209 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
3212 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
3213 if (!aliasProperty.isScriptable())
3214 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3216 writable = aliasProperty.isWritable() && !prop.isReadOnly;
3217 resettable = aliasProperty.isResettable() && !prop.isReadOnly;
3219 if (aliasProperty.type() < QVariant::UserType ||
3220 aliasProperty.type() == QVariant::LastType /* for QVariant */ )
3221 type = aliasProperty.type();
3223 if (alias.count() == 3) {
3224 QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
3226 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3228 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
3230 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
3231 if (valueTypeIndex == -1)
3232 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3233 Q_ASSERT(valueTypeIndex <= 0xFF);
3235 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
3236 propIdx |= (valueTypeIndex << 16);
3238 // update the property type
3239 type = aliasProperty.type();
3240 if (type >= (int)QVariant::UserType)
3244 if (aliasProperty.isEnumType())
3245 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
3247 typeName = aliasProperty.typeName();
3249 Q_ASSERT(idObject->type != -1); // How else did it get an id?
3251 const QDeclarativeCompiledData::TypeReference &ref = output->types.at(idObject->type);
3253 typeName = ref.type->typeName();
3255 typeName = ref.component->root->className();
3260 if (typeName.endsWith('*'))
3261 flags |= QML_ALIAS_FLAG_PTR;
3263 QDeclarativeVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags };
3265 typedef QDeclarativeVMEMetaData VMD;
3266 VMD *vmd = (QDeclarativeVMEMetaData *)data.data();
3267 *(vmd->aliasData() + aliasIndex) = aliasData;
3269 prop.nameRef = builder.newString(prop.name.utf8length());
3270 prop.resolvedCustomTypeName = pool->NewByteArray(typeName);
3271 prop.typeRef = builder.newString(typeName.length());
3273 int propertyFlags = 0;
3275 propertyFlags |= QFastMetaBuilder::Writable;
3277 propertyFlags |= QFastMetaBuilder::Resettable;
3279 builder.setProperty(propIndex, prop.nameRef, prop.typeRef, (QMetaType::Type)type,
3280 (QFastMetaBuilder::PropertyFlag)propertyFlags,
3286 bool QDeclarativeCompiler::buildBinding(QDeclarativeScript::Value *value,
3287 QDeclarativeScript::Property *prop,
3288 const BindingContext &ctxt)
3290 Q_ASSERT(prop->index != -1);
3291 Q_ASSERT(prop->parent);
3292 Q_ASSERT(prop->parent->metaObject());
3294 if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
3295 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3297 BindingReference *reference = pool->New<BindingReference>();
3298 reference->expression = value->value;
3299 reference->property = prop;
3300 reference->value = value;
3301 reference->bindingContext = ctxt;
3302 addBindingReference(reference);
3307 void QDeclarativeCompiler::genBindingAssignment(QDeclarativeScript::Value *binding,
3308 QDeclarativeScript::Property *prop,
3309 QDeclarativeScript::Object *obj,
3310 QDeclarativeScript::Property *valueTypeProperty)
3313 Q_ASSERT(binding->bindingReference);
3315 const BindingReference &ref = *binding->bindingReference;
3316 if (ref.dataType == BindingReference::V4) {
3317 Instruction::StoreV4Binding store;
3318 store.value = ref.compiledIndex;
3319 store.context = ref.bindingContext.stack;
3320 store.owner = ref.bindingContext.owner;
3321 if (valueTypeProperty) {
3322 store.property = (valueTypeProperty->index & 0xFFFF) |
3323 ((valueTypeProperty->type & 0xFF)) << 16 |
3324 ((prop->index & 0xFF) << 24);
3325 store.isRoot = (compileState->root == valueTypeProperty->parent);
3327 store.property = prop->index;
3328 store.isRoot = (compileState->root == obj);
3330 store.line = binding->location.start.line;
3331 output->addInstruction(store);
3332 } else if (ref.dataType == BindingReference::V8) {
3333 Instruction::StoreV8Binding store;
3334 store.value = ref.compiledIndex;
3335 store.context = ref.bindingContext.stack;
3336 store.owner = ref.bindingContext.owner;
3337 if (valueTypeProperty) {
3338 store.isRoot = (compileState->root == valueTypeProperty->parent);
3340 store.isRoot = (compileState->root == obj);
3342 store.line = binding->location.start.line;
3344 Q_ASSERT(ref.bindingContext.owner == 0 ||
3345 (ref.bindingContext.owner != 0 && valueTypeProperty));
3346 if (ref.bindingContext.owner) {
3347 store.property = genValueTypeData(prop, valueTypeProperty);
3349 store.property = prop->core;
3352 output->addInstruction(store);
3354 QDeclarativeInstruction store;
3355 store.assignBinding.value = output->indexForString(ref.rewrittenExpression);
3356 store.assignBinding.context = ref.bindingContext.stack;
3357 store.assignBinding.owner = ref.bindingContext.owner;
3358 store.assignBinding.line = binding->location.start.line;
3360 if (valueTypeProperty) {
3361 store.assignBinding.isRoot = (compileState->root == valueTypeProperty->parent);
3363 store.assignBinding.isRoot = (compileState->root == obj);
3366 Q_ASSERT(ref.bindingContext.owner == 0 ||
3367 (ref.bindingContext.owner != 0 && valueTypeProperty));
3368 if (ref.bindingContext.owner) {
3369 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
3371 store.assignBinding.property = prop->core;
3373 output->addInstructionHelper(
3374 !prop->isAlias ? QDeclarativeInstruction::StoreBinding
3375 : QDeclarativeInstruction::StoreBindingOnAlias
3380 int QDeclarativeCompiler::genContextCache()
3382 if (compileState->ids.count() == 0)
3385 QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache();
3386 cache->reserve(compileState->ids.count());
3387 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
3388 cache->add(o->id, o->idIndex);
3390 output->contextCaches.append(cache);
3391 return output->contextCaches.count() - 1;
3394 QDeclarativePropertyData
3395 QDeclarativeCompiler::genValueTypeData(QDeclarativeScript::Property *valueTypeProp,
3396 QDeclarativeScript::Property *prop)
3398 typedef QDeclarativePropertyPrivate QDPP;
3399 return QDPP::saveValueType(prop->parent->metaObject(), prop->index,
3400 enginePrivate->valueTypes[prop->type]->metaObject(),
3401 valueTypeProp->index, engine);
3404 bool QDeclarativeCompiler::completeComponentBuild()
3407 componentStats->componentStat.ids = compileState->ids.count();
3409 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
3410 aliasObject = compileState->aliasingObjects.next(aliasObject))
3411 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
3413 QV4Compiler::Expression expr(unit->imports());
3414 expr.component = compileState->root;
3415 expr.ids = &compileState->ids;
3416 expr.importCache = output->importCache;
3418 QV4Compiler bindingCompiler;
3420 QList<BindingReference*> sharedBindings;
3422 for (BindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3424 BindingReference &binding = *b;
3426 // ### We don't currently optimize for bindings on alias's - because
3427 // of the solution to QTBUG-13719
3428 if (!binding.property->isAlias) {
3429 expr.context = binding.bindingContext.object;
3430 expr.property = binding.property;
3431 expr.expression = binding.expression;
3433 int index = bindingCompiler.compile(expr, enginePrivate);
3435 binding.dataType = BindingReference::V4;
3436 binding.compiledIndex = index;
3438 componentStats->componentStat.optimizedBindings.append(b->value->location);
3443 // Pre-rewrite the expression
3444 QString expression = binding.expression.asScript();
3446 QDeclarativeRewrite::RewriteBinding rewriteBinding;
3447 rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3448 bool isSharable = false;
3449 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3451 if (isSharable && !binding.property->isAlias /* See above re alias */ &&
3452 binding.property->type != qMetaTypeId<QDeclarativeBinding*>()) {
3453 binding.dataType = BindingReference::V8;
3454 sharedBindings.append(b);
3456 binding.dataType = BindingReference::QtScript;
3460 componentStats->componentStat.scriptBindings.append(b->value->location);
3463 if (!sharedBindings.isEmpty()) {
3465 static bool lt(const BindingReference *lhs, const BindingReference *rhs)
3467 return lhs->value->location.start.line < rhs->value->location.start.line;
3471 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3473 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3474 int lineNumber = startLineNumber;
3476 QString functionArray(QLatin1String("["));
3477 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3478 BindingReference *reference = sharedBindings.at(ii);
3479 QDeclarativeScript::Value *value = reference->value;
3480 const QString &expression = reference->rewrittenExpression;
3482 if (ii != 0) functionArray += QLatin1String(",");
3484 while (lineNumber < value->location.start.line) {
3486 functionArray += QLatin1String("\n");
3489 functionArray += expression;
3490 lineNumber += expression.count(QLatin1Char('\n'));
3491 reference->compiledIndex = ii;
3493 functionArray += QLatin1String("]");
3495 compileState->v8BindingProgram = functionArray;
3496 compileState->v8BindingProgramLine = startLineNumber;
3497 compileState->v8BindingProgramIndex = output->v8bindings.count();
3498 output->v8bindings.append(v8::Persistent<v8::Array>());
3501 if (bindingCompiler.isValid())
3502 compileState->compiledBindingData = bindingCompiler.program();
3504 // Check pop()'s matched push()'s
3505 Q_ASSERT(compileState->objectDepth.depth() == 0);
3506 Q_ASSERT(compileState->listDepth.depth() == 0);
3508 saveComponentState();
3513 void QDeclarativeCompiler::dumpStats()
3515 Q_ASSERT(componentStats);
3516 qWarning().nospace() << "QML Document: " << output->url.toString();
3517 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3518 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3519 qWarning().nospace() << " Component Line " << stat.lineNumber;
3520 qWarning().nospace() << " Total Objects: " << stat.objects;
3521 qWarning().nospace() << " IDs Used: " << stat.ids;
3522 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3526 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3527 if (0 == (ii % 10)) {
3528 if (ii) output.append("\n");
3533 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3535 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3536 output.append(") ");
3538 if (!output.isEmpty())
3539 qWarning().nospace() << output.constData();
3542 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3545 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3546 if (0 == (ii % 10)) {
3547 if (ii) output.append("\n");
3552 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3554 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3555 output.append(") ");
3557 if (!output.isEmpty())
3558 qWarning().nospace() << output.constData();
3564 Returns true if from can be assigned to a (QObject) property of type
3567 bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeScript::Object *from)
3569 const QMetaObject *toMo = enginePrivate->rawMetaObjectForType(to);
3570 const QMetaObject *fromMo = from->metaObject();
3573 if (QDeclarativePropertyPrivate::equal(fromMo, toMo))
3575 fromMo = fromMo->superClass();
3581 Returns the element name, as written in the QML file, for o.
3583 QString QDeclarativeCompiler::elementName(QDeclarativeScript::Object *o)
3586 if (o->type != -1) {
3587 return output->types.at(o->type).className;
3593 QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeScript::Object *from)
3596 const QMetaObject *mo = from->metatype;
3597 QDeclarativeType *type = 0;
3598 while (!type && mo) {
3599 type = QDeclarativeMetaType::qmlType(mo);
3600 mo = mo->superClass();
3605 QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeScript::Object *obj)
3607 const QMetaObject *mo = obj->metatype;
3609 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3611 return QStringList();
3613 QMetaClassInfo classInfo = mo->classInfo(idx);
3614 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3618 QDeclarativePropertyData *
3619 QDeclarativeCompiler::property(QDeclarativeScript::Object *object, int index)
3621 QDeclarativePropertyCache *cache = 0;
3623 if (object->synthCache)
3624 cache = object->synthCache;
3625 else if (object->type != -1)
3626 cache = output->types[object->type].createPropertyCache(engine);
3628 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3630 return cache->property(index);
3633 QDeclarativePropertyData *
3634 QDeclarativeCompiler::property(QDeclarativeScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3636 if (notInRevision) *notInRevision = false;
3638 QDeclarativePropertyCache *cache = 0;
3640 if (object->synthCache)
3641 cache = object->synthCache;
3642 else if (object->type != -1)
3643 cache = output->types[object->type].createPropertyCache(engine);
3645 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3647 QDeclarativePropertyData *d = cache->property(name);
3649 // Find the first property
3650 while (d && d->isFunction())
3651 d = cache->overrideData(d);
3653 if (d && !cache->isAllowedInRevision(d)) {
3654 if (notInRevision) *notInRevision = true;
3661 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3662 QDeclarativePropertyData *
3663 QDeclarativeCompiler::signal(QDeclarativeScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3665 if (notInRevision) *notInRevision = false;
3667 QDeclarativePropertyCache *cache = 0;
3669 if (object->synthCache)
3670 cache = object->synthCache;
3671 else if (object->type != -1)
3672 cache = output->types[object->type].createPropertyCache(engine);
3674 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3677 QDeclarativePropertyData *d = cache->property(name);
3678 if (notInRevision) *notInRevision = false;
3680 while (d && !(d->isFunction()))
3681 d = cache->overrideData(d);
3683 if (d && !cache->isAllowedInRevision(d)) {
3684 if (notInRevision) *notInRevision = true;
3690 if (name.endsWith(Changed_string)) {
3691 QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3693 d = property(object, propName, notInRevision);
3695 return cache->method(d->notifyIndex);
3701 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3702 int QDeclarativeCompiler::indexOfSignal(QDeclarativeScript::Object *object, const QString &name,
3703 bool *notInRevision)
3705 QDeclarativePropertyData *d = signal(object, QStringRef(&name), notInRevision);
3706 return d?d->coreIndex:-1;
3709 int QDeclarativeCompiler::indexOfProperty(QDeclarativeScript::Object *object, const QString &name,
3710 bool *notInRevision)
3712 return indexOfProperty(object, QStringRef(&name), notInRevision);
3715 int QDeclarativeCompiler::indexOfProperty(QDeclarativeScript::Object *object, const QHashedStringRef &name,
3716 bool *notInRevision)
3718 QDeclarativePropertyData *d = property(object, name, notInRevision);
3719 return d?d->coreIndex:-1;