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 QDeclarativeJS;
87 using namespace QDeclarativeScript;
88 using namespace QDeclarativeCompilerTypes;
90 static QString id_string(QLatin1String("id"));
91 static QString on_string(QLatin1String("on"));
92 static QString Changed_string(QLatin1String("Changed"));
93 static QString Component_string(QLatin1String("Component"));
94 static QString Component_import_string(QLatin1String("QML/Component"));
95 static QString qsTr_string(QLatin1String("qsTr"));
96 static QString qsTrId_string(QLatin1String("qsTrId"));
99 Instantiate a new QDeclarativeCompiler.
101 QDeclarativeCompiler::QDeclarativeCompiler(QDeclarativePool *pool)
102 : pool(pool), output(0), engine(0), unitRoot(0), unit(0), cachedComponentTypeRef(-1),
103 cachedTranslationContextIndex(-1), componentStats(0)
105 if (compilerStatDump())
106 componentStats = pool->New<ComponentStats>();
110 Returns true if the last call to compile() caused errors.
114 bool QDeclarativeCompiler::isError() const
116 return !exceptions.isEmpty();
120 Return the list of errors from the last call to compile(), or an empty list
121 if there were no errors.
123 QList<QDeclarativeError> QDeclarativeCompiler::errors() const
129 Returns true if \a name refers to an attached property, false otherwise.
131 Attached property names are those that start with a capital letter.
133 bool QDeclarativeCompiler::isAttachedPropertyName(const QString &name)
135 return isAttachedPropertyName(QHashedStringRef(&name));
138 bool QDeclarativeCompiler::isAttachedPropertyName(const QHashedStringRef &name)
140 return !name.isEmpty() && name.at(0).isUpper();
144 Returns true if \a name refers to a signal property, false otherwise.
146 Signal property names are those that start with "on", followed by a first
147 character which is either a capital letter or one or more underscores followed
148 by a capital letter, which is then followed by other allowed characters.
150 Note that although ECMA-262r3 supports dollarsigns and escaped unicode
151 character codes in property names, for simplicity and performance reasons
152 QML only supports letters, numbers and underscores.
154 bool QDeclarativeCompiler::isSignalPropertyName(const QString &name)
156 return isSignalPropertyName(QStringRef(&name));
159 bool QDeclarativeCompiler::isSignalPropertyName(const QHashedStringRef &name)
161 if (name.length() < 3) return false;
162 if (!name.startsWith(on_string)) return false;
163 int ns = name.length();
164 for (int i = 2; i < ns; ++i) {
165 const QChar curr = name.at(i);
166 if (curr.unicode() == '_') continue;
167 if (curr.isUpper()) return true;
170 return false; // consists solely of underscores - invalid.
174 \macro COMPILE_EXCEPTION
176 Inserts an error into the QDeclarativeCompiler error list, and returns false
179 \a token is used to source the error line and column, and \a desc is the
180 error itself. \a desc can be an expression that can be piped into QDebug.
185 COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(property->name));
188 #define COMPILE_EXCEPTION(token, desc) \
190 QString exceptionDescription; \
191 QDeclarativeError error; \
192 error.setUrl(output->url); \
193 error.setLine((token)->location.start.line); \
194 error.setColumn((token)->location.start.column); \
195 error.setDescription(desc.trimmed()); \
196 exceptions << error; \
203 Returns false if \a is false, otherwise does nothing.
205 #define COMPILE_CHECK(a) \
207 if (!a) return false; \
211 Returns true if literal \a v can be assigned to property \a prop, otherwise
214 This test corresponds to action taken by genLiteralAssignment(). Any change
215 made here, must have a corresponding action in genLiteralAssigment().
217 bool QDeclarativeCompiler::testLiteralAssignment(QDeclarativeScript::Property *prop,
218 QDeclarativeScript::Value *v)
220 const QDeclarativeScript::Variant &value = v->value;
222 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
223 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
225 if (prop->core.isEnum()) {
226 QMetaProperty p = prop->parent->metaObject()->property(prop->index);
229 if (p.isFlagType()) {
230 enumValue = p.enumerator().keysToValue(value.asString().toUtf8().constData(), &ok);
232 enumValue = p.enumerator().keyToValue(value.asString().toUtf8().constData(), &ok);
235 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration"));
237 v->value = QDeclarativeScript::Variant((double)enumValue);
241 int type = prop->type;
244 case QMetaType::QVariant:
246 case QVariant::String:
247 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
249 case QVariant::StringList: // we expect a string literal. A string list is not a literal assignment.
250 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or string list expected"));
252 case QVariant::ByteArray:
253 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected"));
256 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected"));
260 bool ok = v->value.isNumber();
262 double n = v->value.asNumber();
263 if (double(uint(n)) != n)
266 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected"));
271 bool ok = v->value.isNumber();
273 double n = v->value.asNumber();
274 if (double(int(n)) != n)
277 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected"));
280 case QMetaType::Float:
281 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
283 case QVariant::Double:
284 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
286 case QVariant::Color:
289 QDeclarativeStringConverters::colorFromString(value.asString(), &ok);
290 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected"));
293 #ifndef QT_NO_DATESTRING
297 QDeclarativeStringConverters::dateFromString(value.asString(), &ok);
298 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected"));
304 QDeclarativeStringConverters::timeFromString(value.asString(), &ok);
305 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected"));
308 case QVariant::DateTime:
311 QDeclarativeStringConverters::dateTimeFromString(value.asString(), &ok);
312 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected"));
315 #endif // QT_NO_DATESTRING
316 case QVariant::Point:
317 case QVariant::PointF:
320 QDeclarativeStringConverters::pointFFromString(value.asString(), &ok);
321 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected"));
325 case QVariant::SizeF:
328 QDeclarativeStringConverters::sizeFFromString(value.asString(), &ok);
329 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected"));
333 case QVariant::RectF:
336 QDeclarativeStringConverters::rectFFromString(value.asString(), &ok);
337 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected"));
342 if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected"));
345 case QVariant::Vector3D:
348 QDeclarativeStringConverters::vector3DFromString(value.asString(), &ok);
349 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected"));
352 case QVariant::Vector4D:
355 QDeclarativeStringConverters::vector4DFromString(value.asString(), &ok);
356 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 4D vector expected"));
361 // check if assigning a literal value to a list property.
362 // in each case, check the singular, since an Array of the specified type
363 // will not go via this literal assignment codepath.
364 if (type == qMetaTypeId<QList<qreal> >()) {
365 if (!v->value.isNumber()) {
366 COMPILE_EXCEPTION(v, tr("Invalid property assignment: real or array of reals expected"));
369 } else if (type == qMetaTypeId<QList<int> >()) {
370 bool ok = v->value.isNumber();
372 double n = v->value.asNumber();
373 if (double(int(n)) != n)
376 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int or array of ints expected"));
378 } else if (type == qMetaTypeId<QList<bool> >()) {
379 if (!v->value.isBoolean()) {
380 COMPILE_EXCEPTION(v, tr("Invalid property assignment: bool or array of bools expected"));
383 } else if (type == qMetaTypeId<QList<QString> >()) { // we expect a string literal. A string list is not a literal assignment.
384 if (!v->value.isString()) {
385 COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or array of strings expected"));
388 } else if (type == qMetaTypeId<QList<QUrl> >()) {
389 if (!v->value.isString()) {
390 COMPILE_EXCEPTION(v, tr("Invalid property assignment: url or array of urls expected"));
395 // otherwise, check for existence of string converter to custom type
396 QDeclarativeMetaType::StringConverter converter = QDeclarativeMetaType::customStringConverter(type);
398 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName((QVariant::Type)type))));
406 Generate a store instruction for assigning literal \a v to property \a prop.
408 Any literal assignment that is approved in testLiteralAssignment() must have
409 a corresponding action in this method.
411 void QDeclarativeCompiler::genLiteralAssignment(QDeclarativeScript::Property *prop,
412 QDeclarativeScript::Value *v)
414 if (prop->core.isEnum()) {
415 Q_ASSERT(v->value.isNumber());
417 int value = (int)v->value.asNumber();
419 Instruction::StoreInteger instr;
420 instr.propertyIndex = prop->index;
422 output->addInstruction(instr);
426 int type = prop->type;
428 case QMetaType::QVariant:
430 if (v->value.isNumber()) {
431 double n = v->value.asNumber();
432 if (double(int(n)) == n) {
433 if (prop->core.isVMEProperty()) {
434 Instruction::StoreVarInteger instr;
435 instr.propertyIndex = prop->index;
436 instr.value = int(n);
437 output->addInstruction(instr);
439 Instruction::StoreVariantInteger instr;
440 instr.propertyIndex = prop->index;
441 instr.value = int(n);
442 output->addInstruction(instr);
445 if (prop->core.isVMEProperty()) {
446 Instruction::StoreVarDouble instr;
447 instr.propertyIndex = prop->index;
449 output->addInstruction(instr);
451 Instruction::StoreVariantDouble instr;
452 instr.propertyIndex = prop->index;
454 output->addInstruction(instr);
457 } else if (v->value.isBoolean()) {
458 if (prop->core.isVMEProperty()) {
459 Instruction::StoreVarBool instr;
460 instr.propertyIndex = prop->index;
461 instr.value = v->value.asBoolean();
462 output->addInstruction(instr);
464 Instruction::StoreVariantBool instr;
465 instr.propertyIndex = prop->index;
466 instr.value = v->value.asBoolean();
467 output->addInstruction(instr);
470 if (prop->core.isVMEProperty()) {
471 Instruction::StoreVar instr;
472 instr.propertyIndex = prop->index;
473 instr.value = output->indexForString(v->value.asString());
474 output->addInstruction(instr);
476 Instruction::StoreVariant instr;
477 instr.propertyIndex = prop->index;
478 instr.value = output->indexForString(v->value.asString());
479 output->addInstruction(instr);
484 case QVariant::String:
486 Instruction::StoreString instr;
487 instr.propertyIndex = prop->index;
488 instr.value = output->indexForString(v->value.asString());
489 output->addInstruction(instr);
492 case QVariant::StringList:
494 Instruction::StoreStringList instr;
495 instr.propertyIndex = prop->index;
496 instr.value = output->indexForString(v->value.asString());
497 output->addInstruction(instr);
500 case QVariant::ByteArray:
502 Instruction::StoreByteArray instr;
503 instr.propertyIndex = prop->index;
504 instr.value = output->indexForByteArray(v->value.asString().toLatin1());
505 output->addInstruction(instr);
510 Instruction::StoreUrl instr;
511 QString string = v->value.asString();
512 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
513 instr.propertyIndex = prop->index;
514 instr.value = output->indexForUrl(u);
515 output->addInstruction(instr);
520 Instruction::StoreInteger instr;
521 instr.propertyIndex = prop->index;
522 instr.value = uint(v->value.asNumber());
523 output->addInstruction(instr);
528 Instruction::StoreInteger instr;
529 instr.propertyIndex = prop->index;
530 instr.value = int(v->value.asNumber());
531 output->addInstruction(instr);
534 case QMetaType::Float:
536 Instruction::StoreFloat instr;
537 instr.propertyIndex = prop->index;
538 instr.value = float(v->value.asNumber());
539 output->addInstruction(instr);
542 case QVariant::Double:
544 Instruction::StoreDouble instr;
545 instr.propertyIndex = prop->index;
546 instr.value = v->value.asNumber();
547 output->addInstruction(instr);
550 case QVariant::Color:
552 Instruction::StoreColor instr;
553 QColor c = QDeclarativeStringConverters::colorFromString(v->value.asString());
554 instr.propertyIndex = prop->index;
555 instr.value = c.rgba();
556 output->addInstruction(instr);
559 #ifndef QT_NO_DATESTRING
562 Instruction::StoreDate instr;
563 QDate d = QDeclarativeStringConverters::dateFromString(v->value.asString());
564 instr.propertyIndex = prop->index;
565 instr.value = d.toJulianDay();
566 output->addInstruction(instr);
571 Instruction::StoreTime instr;
572 QTime time = QDeclarativeStringConverters::timeFromString(v->value.asString());
573 instr.propertyIndex = prop->index;
574 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
575 ::memcpy(&instr.time, &time, sizeof(QTime));
576 output->addInstruction(instr);
579 case QVariant::DateTime:
581 Instruction::StoreDateTime instr;
582 QDateTime dateTime = QDeclarativeStringConverters::dateTimeFromString(v->value.asString());
583 QTime time = dateTime.time();
584 instr.propertyIndex = prop->index;
585 instr.date = dateTime.date().toJulianDay();
586 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
587 ::memcpy(&instr.time, &time, sizeof(QTime));
588 output->addInstruction(instr);
591 #endif // QT_NO_DATESTRING
592 case QVariant::Point:
594 Instruction::StorePoint instr;
596 QPoint point = QDeclarativeStringConverters::pointFFromString(v->value.asString(), &ok).toPoint();
597 instr.propertyIndex = prop->index;
598 instr.point.xp = point.x();
599 instr.point.yp = point.y();
600 output->addInstruction(instr);
603 case QVariant::PointF:
605 Instruction::StorePointF instr;
607 QPointF point = QDeclarativeStringConverters::pointFFromString(v->value.asString(), &ok);
608 instr.propertyIndex = prop->index;
609 instr.point.xp = point.x();
610 instr.point.yp = point.y();
611 output->addInstruction(instr);
616 Instruction::StoreSize instr;
618 QSize size = QDeclarativeStringConverters::sizeFFromString(v->value.asString(), &ok).toSize();
619 instr.propertyIndex = prop->index;
620 instr.size.wd = size.width();
621 instr.size.ht = size.height();
622 output->addInstruction(instr);
625 case QVariant::SizeF:
627 Instruction::StoreSizeF instr;
629 QSizeF size = QDeclarativeStringConverters::sizeFFromString(v->value.asString(), &ok);
630 instr.propertyIndex = prop->index;
631 instr.size.wd = size.width();
632 instr.size.ht = size.height();
633 output->addInstruction(instr);
638 Instruction::StoreRect instr;
640 QRect rect = QDeclarativeStringConverters::rectFFromString(v->value.asString(), &ok).toRect();
641 instr.propertyIndex = prop->index;
642 instr.rect.x1 = rect.left();
643 instr.rect.y1 = rect.top();
644 instr.rect.x2 = rect.right();
645 instr.rect.y2 = rect.bottom();
646 output->addInstruction(instr);
649 case QVariant::RectF:
651 Instruction::StoreRectF instr;
653 QRectF rect = QDeclarativeStringConverters::rectFFromString(v->value.asString(), &ok);
654 instr.propertyIndex = prop->index;
655 instr.rect.xp = rect.left();
656 instr.rect.yp = rect.top();
657 instr.rect.w = rect.width();
658 instr.rect.h = rect.height();
659 output->addInstruction(instr);
664 Instruction::StoreBool instr;
665 bool b = v->value.asBoolean();
666 instr.propertyIndex = prop->index;
668 output->addInstruction(instr);
671 case QVariant::Vector3D:
673 Instruction::StoreVector3D instr;
675 QVector3D vector = QDeclarativeStringConverters::vector3DFromString(v->value.asString(), &ok);
676 instr.propertyIndex = prop->index;
677 instr.vector.xp = vector.x();
678 instr.vector.yp = vector.y();
679 instr.vector.zp = vector.z();
680 output->addInstruction(instr);
683 case QVariant::Vector4D:
685 Instruction::StoreVector4D instr;
687 QVector4D vector = QDeclarativeStringConverters::vector4DFromString(v->value.asString(), &ok);
688 instr.propertyIndex = prop->index;
689 instr.vector.xp = vector.x();
690 instr.vector.yp = vector.y();
691 instr.vector.zp = vector.z();
692 instr.vector.wp = vector.w();
693 output->addInstruction(instr);
698 // generate single literal value assignment to a list property if required
699 if (type == qMetaTypeId<QList<qreal> >()) {
700 Instruction::StoreDoubleQList instr;
701 instr.propertyIndex = prop->index;
702 instr.value = v->value.asNumber();
703 output->addInstruction(instr);
705 } else if (type == qMetaTypeId<QList<int> >()) {
706 Instruction::StoreIntegerQList instr;
707 instr.propertyIndex = prop->index;
708 instr.value = int(v->value.asNumber());
709 output->addInstruction(instr);
711 } else if (type == qMetaTypeId<QList<bool> >()) {
712 Instruction::StoreBoolQList instr;
713 bool b = v->value.asBoolean();
714 instr.propertyIndex = prop->index;
716 output->addInstruction(instr);
718 } else if (type == qMetaTypeId<QList<QUrl> >()) {
719 Instruction::StoreUrlQList instr;
720 QString string = v->value.asString();
721 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
722 instr.propertyIndex = prop->index;
723 instr.value = output->indexForUrl(u);
724 output->addInstruction(instr);
726 } else if (type == qMetaTypeId<QList<QString> >()) {
727 Instruction::StoreStringQList instr;
728 instr.propertyIndex = prop->index;
729 instr.value = output->indexForString(v->value.asString());
730 output->addInstruction(instr);
734 // otherwise, generate custom type literal assignment
735 Instruction::AssignCustomType instr;
736 instr.propertyIndex = prop->index;
737 instr.primitive = output->indexForString(v->value.asString());
739 output->addInstruction(instr);
746 Resets data by clearing the lists that the QDeclarativeCompiler modifies.
748 void QDeclarativeCompiler::reset(QDeclarativeCompiledData *data)
751 data->primitives.clear();
753 data->bytecode.resize(0);
757 Compile \a unit, and store the output in \a out. \a engine is the QDeclarativeEngine
758 with which the QDeclarativeCompiledData will be associated.
760 Returns true on success, false on failure. On failure, the compile errors
761 are available from errors().
763 If the environment variant QML_COMPILER_DUMP is set
764 (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
765 on a successful compiler.
767 bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine,
768 QDeclarativeTypeData *unit,
769 QDeclarativeCompiledData *out)
776 QDeclarativeScript::Object *root = unit->parser().tree();
779 this->engine = engine;
780 this->enginePrivate = QDeclarativeEnginePrivate::get(engine);
782 this->unitRoot = root;
786 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
787 QList<QDeclarativeScript::TypeReference *> referencedTypes = unit->parser().referencedTypes();
789 for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
790 QDeclarativeCompiledData::TypeReference ref;
792 const QDeclarativeTypeData::TypeReference &tref = resolvedTypes.at(ii);
793 QDeclarativeScript::TypeReference *parserRef = referencedTypes.at(ii);
796 ref.type = tref.type;
797 if (!ref.type->isCreatable()) {
798 QString err = ref.type->noCreationReason();
800 err = tr( "Element is not creatable.");
801 COMPILE_EXCEPTION(parserRef->refObjects.first(), err);
804 if (ref.type->containsRevisionedAttributes()) {
805 QDeclarativeError cacheError;
806 ref.typePropertyCache = enginePrivate->cache(ref.type, resolvedTypes.at(ii).minorVersion,
808 if (!ref.typePropertyCache)
809 COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description());
810 ref.typePropertyCache->addref();
813 } else if (tref.typeData) {
814 ref.component = tref.typeData->compiledData();
816 ref.className = parserRef->name;
824 out->dumpInstructions();
827 Q_ASSERT(out->rootPropertyCache);
835 this->enginePrivate = 0;
837 this->cachedComponentTypeRef = -1;
838 this->cachedTranslationContextIndex = -1;
844 void QDeclarativeCompiler::compileTree(QDeclarativeScript::Object *tree)
846 compileState = pool->New<ComponentCompileState>();
848 compileState->root = tree;
850 componentStats->componentStat.lineNumber = tree->location.start.line;
852 // Build global import scripts
853 QStringList importedScriptIndexes;
855 foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
856 importedScriptIndexes.append(script.qualifier);
859 // We generate the importCache before we build the tree so that
860 // it can be used in the binding compiler. Given we "expect" the
861 // QML compilation to succeed, this isn't a waste.
862 output->importCache = new QDeclarativeTypeNameCache();
863 for (int ii = 0; ii < importedScriptIndexes.count(); ++ii)
864 output->importCache->add(importedScriptIndexes.at(ii), ii);
865 unit->imports().populateCache(output->importCache, engine);
867 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
870 Instruction::Init init;
871 init.bindingsSize = compileState->totalBindingsCount;
872 init.parserStatusSize = compileState->parserStatusCount;
873 init.contextCache = genContextCache();
874 init.objectStackSize = compileState->objectDepth.maxDepth();
875 init.listStackSize = compileState->listDepth.maxDepth();
876 if (compileState->compiledBindingData.isEmpty())
877 init.compiledBinding = -1;
879 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
880 output->addInstruction(init);
882 foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
883 Instruction::StoreImportedScript import;
884 import.value = output->scripts.count();
886 QDeclarativeScriptData *scriptData = script.script->scriptData();
887 scriptData->addref();
888 output->scripts << scriptData;
889 output->addInstruction(import);
892 if (!compileState->v8BindingProgram.isEmpty()) {
893 Instruction::InitV8Bindings bindings;
894 bindings.program = output->indexForString(compileState->v8BindingProgram);
895 bindings.programIndex = compileState->v8BindingProgramIndex;
896 bindings.line = compileState->v8BindingProgramLine;
897 output->addInstruction(bindings);
902 Instruction::SetDefault def;
903 output->addInstruction(def);
905 Instruction::Done done;
906 output->addInstruction(done);
908 Q_ASSERT(tree->metatype);
910 if (tree->metadata.isEmpty()) {
911 output->root = tree->metatype;
913 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
914 output->root = &output->rootData;
916 if (!tree->metadata.isEmpty())
917 enginePrivate->registerCompositeType(output);
920 static bool QStringList_contains(const QStringList &list, const QHashedStringRef &string)
922 for (int ii = 0; ii < list.count(); ++ii)
923 if (string == list.at(ii))
929 bool QDeclarativeCompiler::buildObject(QDeclarativeScript::Object *obj, const BindingContext &ctxt)
932 componentStats->componentStat.objects++;
934 Q_ASSERT (obj->type != -1);
935 const QDeclarativeCompiledData::TypeReference &tr = output->types.at(obj->type);
936 obj->metatype = tr.metaObject();
939 obj->typeName = tr.type->qmlTypeName();
941 // This object is a "Component" element
942 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
943 COMPILE_CHECK(buildComponent(obj, ctxt));
948 typedef QDeclarativeInstruction I;
949 const I *init = ((const I *)tr.component->bytecode.constData());
950 Q_ASSERT(init && tr.component->instructionType(init) == QDeclarativeInstruction::Init);
952 // Adjust stack depths to include nested components
953 compileState->objectDepth.pushPop(init->init.objectStackSize);
954 compileState->listDepth.pushPop(init->init.listStackSize);
955 compileState->parserStatusCount += init->init.parserStatusSize;
956 compileState->totalBindingsCount += init->init.bindingsSize;
959 compileState->objectDepth.push();
961 // Object instantiations reset the binding context
962 BindingContext objCtxt(obj);
964 // Create the synthesized meta object, ignoring aliases
965 COMPILE_CHECK(checkDynamicMeta(obj));
966 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
967 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
969 // Find the native type and check for the QDeclarativeParserStatus interface
970 QDeclarativeType *type = toQmlType(obj);
972 obj->parserStatusCast = type->parserStatusCast();
973 if (obj->parserStatusCast != -1)
974 compileState->parserStatusCount++;
976 // Check if this is a custom parser type. Custom parser types allow
977 // assignments to non-existent properties. These assignments are then
978 // compiled by the type.
979 bool isCustomParser = output->types.at(obj->type).type &&
980 output->types.at(obj->type).type->customParser() != 0;
981 QList<QDeclarativeCustomParserProperty> customProps;
983 // Fetch the list of deferred properties
984 QStringList deferredList = deferredProperties(obj);
986 // Must do id property first. This is to ensure that the id given to any
987 // id reference created matches the order in which the objects are
989 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
990 if (prop->name() == id_string) {
991 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
997 Property *defaultProperty = 0;
998 Property *skipProperty = 0;
999 if (obj->defaultProperty) {
1000 defaultProperty = obj->defaultProperty;
1002 Property *explicitProperty = 0;
1004 const QMetaObject *mo = obj->metatype;
1005 int idx = mo->indexOfClassInfo("DefaultProperty");
1007 QMetaClassInfo info = mo->classInfo(idx);
1008 const char *p = info.value();
1012 while (char c = p[plen++]) { ord |= c; };
1016 // Utf8 - unoptimal, but seldom hit
1017 QString *s = pool->NewString(QString::fromUtf8(p, plen));
1018 QHashedStringRef r(*s);
1020 if (obj->propertiesHashField.test(r.hash())) {
1021 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1022 if (ep->name() == r) {
1023 explicitProperty = ep;
1029 if (!explicitProperty)
1030 defaultProperty->setName(r);
1033 QHashedCStringRef r(p, plen);
1035 if (obj->propertiesHashField.test(r.hash())) {
1036 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1037 if (ep->name() == r) {
1038 explicitProperty = ep;
1044 if (!explicitProperty) {
1045 // Set the default property name
1046 QChar *buffer = pool->NewRawArray<QChar>(r.length());
1047 r.writeUtf16(buffer);
1048 defaultProperty->setName(QHashedStringRef(buffer, r.length(), r.hash()));
1054 if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) {
1056 skipProperty = explicitProperty; // We merge the values into defaultProperty
1058 // Find the correct insertion point
1059 Value *insertPos = 0;
1061 for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) {
1062 if (!(v->location.start < explicitProperty->values.first()->location.start))
1067 defaultProperty->values.insertAfter(insertPos, explicitProperty->values);
1071 QDeclarativeCustomParser *cp = 0;
1073 cp = output->types.at(obj->type).type->customParser();
1075 // Build all explicit properties specified
1076 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1078 if (prop == skipProperty)
1080 if (prop->name() == id_string)
1083 bool canDefer = false;
1084 if (isCustomParser) {
1085 if (doesPropertyExist(prop, obj) &&
1086 (!(cp->flags() & QDeclarativeCustomParser::AcceptsAttachedProperties) ||
1087 !isAttachedPropertyName(prop->name()))) {
1088 int ids = compileState->ids.count();
1089 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1090 canDefer = ids == compileState->ids.count();
1091 } else if (isSignalPropertyName(prop->name()) &&
1092 (cp->flags() & QDeclarativeCustomParser::AcceptsSignalHandlers)) {
1093 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1095 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
1098 if (isSignalPropertyName(prop->name())) {
1099 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1101 int ids = compileState->ids.count();
1102 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1103 canDefer = ids == compileState->ids.count();
1107 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1108 prop->isDeferred = true;
1112 // Build the default property
1113 if (defaultProperty) {
1114 Property *prop = defaultProperty;
1116 bool canDefer = false;
1117 if (isCustomParser) {
1118 if (doesPropertyExist(prop, obj)) {
1119 int ids = compileState->ids.count();
1120 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1121 canDefer = ids == compileState->ids.count();
1123 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
1126 int ids = compileState->ids.count();
1127 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1128 canDefer = ids == compileState->ids.count();
1131 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1132 prop->isDeferred = true;
1135 // Compile custom parser parts
1136 if (isCustomParser && !customProps.isEmpty()) {
1138 cp->compiler = this;
1140 obj->custom = cp->compile(customProps);
1143 foreach (QDeclarativeError err, cp->errors()) {
1144 err.setUrl(output->url);
1149 compileState->objectDepth.pop();
1154 void QDeclarativeCompiler::genObject(QDeclarativeScript::Object *obj)
1156 QDeclarativeCompiledData::TypeReference &tr = output->types[obj->type];
1157 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
1162 // Create the object
1163 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
1164 !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) {
1166 Instruction::CreateSimpleObject create;
1167 create.create = output->types.at(obj->type).type->createFunction();
1168 create.typeSize = output->types.at(obj->type).type->createSize();
1169 create.type = obj->type;
1170 create.line = obj->location.start.line;
1171 create.column = obj->location.start.column;
1172 output->addInstruction(create);
1176 if (output->types.at(obj->type).type) {
1177 Instruction::CreateCppObject create;
1178 create.line = obj->location.start.line;
1179 create.column = obj->location.start.column;
1181 if (!obj->custom.isEmpty())
1182 create.data = output->indexForByteArray(obj->custom);
1183 create.type = obj->type;
1184 create.isRoot = (compileState->root == obj);
1185 output->addInstruction(create);
1187 Instruction::CreateQMLObject create;
1188 create.type = obj->type;
1189 create.isRoot = (compileState->root == obj);
1191 if (!obj->bindingBitmask.isEmpty()) {
1192 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
1193 create.bindingBits = output->indexForByteArray(obj->bindingBitmask);
1195 create.bindingBits = -1;
1197 output->addInstruction(create);
1199 Instruction::CompleteQMLObject complete;
1200 complete.line = obj->location.start.line;
1201 complete.column = obj->location.start.column;
1202 complete.isRoot = (compileState->root == obj);
1203 output->addInstruction(complete);
1207 // Setup the synthesized meta object if necessary
1208 if (!obj->metadata.isEmpty()) {
1209 Instruction::StoreMetaObject meta;
1210 meta.data = output->indexForByteArray(obj->metadata);
1211 meta.aliasData = output->indexForByteArray(obj->synthdata);
1212 meta.propertyCache = output->propertyCaches.count();
1214 QDeclarativePropertyCache *propertyCache = obj->synthCache;
1215 Q_ASSERT(propertyCache);
1216 propertyCache->addref();
1218 // Add flag for alias properties
1219 if (!obj->synthdata.isEmpty()) {
1220 const QDeclarativeVMEMetaData *vmeMetaData =
1221 reinterpret_cast<const QDeclarativeVMEMetaData *>(obj->synthdata.constData());
1222 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
1223 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
1224 QDeclarativePropertyData *data = propertyCache->property(index);
1225 data->setFlags(data->getFlags() | QDeclarativePropertyData::IsAlias);
1229 if (obj == unitRoot) {
1230 propertyCache->addref();
1231 output->rootPropertyCache = propertyCache;
1234 output->propertyCaches << propertyCache;
1235 output->addInstruction(meta);
1236 } else if (obj == unitRoot) {
1237 output->rootPropertyCache = tr.createPropertyCache(engine);
1238 output->rootPropertyCache->addref();
1241 // Set the object id
1242 if (!obj->id.isEmpty()) {
1243 Instruction::SetId id;
1244 id.value = output->indexForString(obj->id);
1245 id.index = obj->idIndex;
1246 output->addInstruction(id);
1250 if (tr.type && obj->parserStatusCast != -1) {
1251 Instruction::BeginObject begin;
1252 begin.castValue = obj->parserStatusCast;
1253 output->addInstruction(begin);
1259 void QDeclarativeCompiler::genObjectBody(QDeclarativeScript::Object *obj)
1261 for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1262 Q_ASSERT(prop->scriptStringScope != -1);
1263 const QString &script = prop->values.first()->value.asScript();
1264 Instruction::StoreScriptString ss;
1265 ss.propertyIndex = prop->index;
1266 ss.value = output->indexForString(script);
1267 ss.scope = prop->scriptStringScope;
1268 // ss.bindingId = rewriteBinding(script, prop->name());
1269 ss.bindingId = rewriteBinding(prop->values.first()->value, QString()); // XXX
1270 ss.line = prop->location.start.line;
1271 output->addInstruction(ss);
1274 bool seenDefer = false;
1275 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1276 if (prop->isDeferred) {
1281 genValueProperty(prop, obj);
1284 Instruction::Defer defer;
1285 defer.deferCount = 0;
1286 int deferIdx = output->addInstruction(defer);
1287 int nextInstructionIndex = output->nextInstructionIndex();
1289 Instruction::DeferInit dinit;
1290 // XXX - these are now massive over allocations
1291 dinit.bindingsSize = compileState->totalBindingsCount;
1292 dinit.parserStatusSize = compileState->parserStatusCount;
1293 dinit.objectStackSize = compileState->objectDepth.maxDepth();
1294 dinit.listStackSize = compileState->listDepth.maxDepth();
1295 output->addInstruction(dinit);
1297 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1298 if (!prop->isDeferred)
1300 genValueProperty(prop, obj);
1303 Instruction::Done done;
1304 output->addInstruction(done);
1306 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1309 for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1311 QDeclarativeScript::Value *v = prop->values.first();
1313 if (v->type == Value::SignalObject) {
1315 genObject(v->object);
1317 Instruction::AssignSignalObject assign;
1318 assign.line = v->location.start.line;
1319 assign.signal = output->indexForString(prop->name().toString());
1320 output->addInstruction(assign);
1322 } else if (v->type == Value::SignalExpression) {
1324 Instruction::StoreSignal store;
1325 store.signalIndex = prop->index;
1326 QDeclarativeRewrite::RewriteSignalHandler rewriteSignalHandler;
1327 const QString &rewrite =
1328 rewriteSignalHandler(v->value.asScript().trimmed(), prop->name().toString());
1329 store.value = output->indexForString(rewrite);
1330 store.context = v->signalExpressionContextStack;
1331 store.line = v->location.start.line;
1332 output->addInstruction(store);
1338 for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1339 Instruction::FetchAttached fetch;
1340 fetch.id = prop->index;
1341 fetch.line = prop->location.start.line;
1342 output->addInstruction(fetch);
1344 genObjectBody(prop->value);
1346 Instruction::PopFetchedObject pop;
1347 output->addInstruction(pop);
1350 for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1351 Instruction::FetchObject fetch;
1352 fetch.property = prop->index;
1353 fetch.line = prop->location.start.line;
1354 output->addInstruction(fetch);
1356 if (!prop->value->metadata.isEmpty()) {
1357 Instruction::StoreMetaObject meta;
1358 meta.data = output->indexForByteArray(prop->value->metadata);
1359 meta.aliasData = output->indexForByteArray(prop->value->synthdata);
1360 meta.propertyCache = -1;
1361 output->addInstruction(meta);
1364 genObjectBody(prop->value);
1366 Instruction::PopFetchedObject pop;
1367 output->addInstruction(pop);
1370 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1372 genValueTypeProperty(obj, prop);
1375 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1376 if (prop->isDeferred)
1379 genValueProperty(prop, obj);
1382 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1384 genValueTypeProperty(obj, prop);
1388 void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeScript::Object *obj,QDeclarativeScript::Property *prop)
1390 Instruction::FetchValueType fetch;
1391 fetch.property = prop->index;
1392 fetch.type = prop->type;
1393 fetch.bindingSkipList = 0;
1395 if (obj->type == -1 || output->types.at(obj->type).component) {
1396 // We only have to do this if this is a composite type. If it is a builtin
1397 // type it can't possibly already have bindings that need to be cleared.
1398 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1399 if (!vprop->values.isEmpty()) {
1400 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1401 fetch.bindingSkipList |= (1 << vprop->index);
1406 output->addInstruction(fetch);
1408 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1409 genPropertyAssignment(vprop, prop->value, prop);
1412 Instruction::PopValueType pop;
1413 pop.property = prop->index;
1414 pop.type = prop->type;
1415 pop.bindingSkipList = 0;
1416 output->addInstruction(pop);
1419 void QDeclarativeCompiler::genComponent(QDeclarativeScript::Object *obj)
1421 QDeclarativeScript::Object *root = obj->defaultProperty->values.first()->object;
1424 Instruction::CreateComponent create;
1425 create.line = root->location.start.line;
1426 create.column = root->location.start.column;
1427 create.endLine = root->location.end.line;
1428 create.isRoot = (compileState->root == obj);
1429 int createInstruction = output->addInstruction(create);
1430 int nextInstructionIndex = output->nextInstructionIndex();
1432 ComponentCompileState *oldCompileState = compileState;
1433 compileState = componentState(root);
1435 Instruction::Init init;
1436 init.bindingsSize = compileState->totalBindingsCount;
1437 init.parserStatusSize = compileState->parserStatusCount;
1438 init.contextCache = genContextCache();
1439 init.objectStackSize = compileState->objectDepth.maxDepth();
1440 init.listStackSize = compileState->listDepth.maxDepth();
1441 if (compileState->compiledBindingData.isEmpty())
1442 init.compiledBinding = -1;
1444 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
1445 output->addInstruction(init);
1447 if (!compileState->v8BindingProgram.isEmpty()) {
1448 Instruction::InitV8Bindings bindings;
1449 bindings.program = output->indexForString(compileState->v8BindingProgram);
1450 bindings.programIndex = compileState->v8BindingProgramIndex;
1451 bindings.line = compileState->v8BindingProgramLine;
1452 output->addInstruction(bindings);
1457 Instruction::SetDefault def;
1458 output->addInstruction(def);
1460 Instruction::Done done;
1461 output->addInstruction(done);
1463 output->instruction(createInstruction)->createComponent.count =
1464 output->nextInstructionIndex() - nextInstructionIndex;
1466 compileState = oldCompileState;
1468 if (!obj->id.isEmpty()) {
1469 Instruction::SetId id;
1470 id.value = output->indexForString(obj->id);
1471 id.index = obj->idIndex;
1472 output->addInstruction(id);
1475 if (obj == unitRoot) {
1476 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1477 output->rootPropertyCache->addref();
1481 bool QDeclarativeCompiler::buildComponent(QDeclarativeScript::Object *obj,
1482 const BindingContext &ctxt)
1484 // The special "Component" element can only have the id property and a
1485 // default property, that actually defines the component's tree
1487 compileState->objectDepth.push();
1489 // Find, check and set the "id" property (if any)
1490 Property *idProp = 0;
1491 if (obj->properties.isMany() ||
1492 (obj->properties.isOne() && obj->properties.first()->name() != id_string))
1493 COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
1495 if (!obj->properties.isEmpty())
1496 idProp = obj->properties.first();
1499 if (idProp->value || idProp->values.isMany() || idProp->values.first()->object)
1500 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1501 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1503 QString idVal = idProp->values.first()->primitive();
1505 if (compileState->ids.value(idVal))
1506 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1512 // Check the Component tree is well formed
1513 if (obj->defaultProperty &&
1514 (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
1515 (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
1516 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1518 if (!obj->dynamicProperties.isEmpty())
1519 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1520 if (!obj->dynamicSignals.isEmpty())
1521 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1522 if (!obj->dynamicSlots.isEmpty())
1523 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1525 QDeclarativeScript::Object *root = 0;
1526 if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
1527 root = obj->defaultProperty->values.first()->object;
1530 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1532 // Build the component tree
1533 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1535 compileState->objectDepth.pop();
1540 bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeScript::Object *obj,
1541 const BindingContext &ctxt)
1543 ComponentCompileState *oldComponentCompileState = compileState;
1544 compileState = pool->New<ComponentCompileState>();
1545 compileState->root = obj;
1546 compileState->nested = true;
1548 if (componentStats) {
1549 ComponentStat oldComponentStat = componentStats->componentStat;
1551 componentStats->componentStat = ComponentStat();
1552 componentStats->componentStat.lineNumber = obj->location.start.line;
1555 COMPILE_CHECK(buildObject(obj, ctxt));
1557 COMPILE_CHECK(completeComponentBuild());
1559 componentStats->componentStat = oldComponentStat;
1562 COMPILE_CHECK(buildObject(obj, ctxt));
1564 COMPILE_CHECK(completeComponentBuild());
1567 compileState = oldComponentCompileState;
1573 // Build a sub-object. A sub-object is one that was not created directly by
1574 // QML - such as a grouped property object, or an attached object. Sub-object's
1575 // can't have an id, involve a custom parser, have attached properties etc.
1576 bool QDeclarativeCompiler::buildSubObject(QDeclarativeScript::Object *obj, const BindingContext &ctxt)
1578 Q_ASSERT(obj->metatype);
1579 Q_ASSERT(!obj->defaultProperty);
1580 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1583 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1584 if (isSignalPropertyName(prop->name())) {
1585 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1587 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1594 int QDeclarativeCompiler::componentTypeRef()
1596 if (cachedComponentTypeRef == -1) {
1597 QDeclarativeType *t = QDeclarativeMetaType::qmlType(Component_import_string,1,0);
1598 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1599 if (output->types.at(ii).type == t) {
1600 cachedComponentTypeRef = ii;
1604 QDeclarativeCompiledData::TypeReference ref;
1605 ref.className = Component_string;
1607 output->types << ref;
1608 cachedComponentTypeRef = output->types.count() - 1;
1610 return cachedComponentTypeRef;
1613 int QDeclarativeCompiler::translationContextIndex()
1615 if (cachedTranslationContextIndex == -1) {
1616 // This code must match that in the qsTr() implementation
1617 QString path = output->url.toString();
1618 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
1619 QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) :
1621 QByteArray contextUtf8 = context.toUtf8();
1622 cachedTranslationContextIndex = output->indexForByteArray(contextUtf8);
1624 return cachedTranslationContextIndex;
1627 bool QDeclarativeCompiler::buildSignal(QDeclarativeScript::Property *prop, QDeclarativeScript::Object *obj,
1628 const BindingContext &ctxt)
1630 Q_ASSERT(obj->metaObject());
1632 const QHashedStringRef &propName = prop->name();
1634 Q_ASSERT(propName.startsWith(on_string));
1635 QString name = propName.mid(2, -1).toString();
1637 // Note that the property name could start with any alpha or '_' or '$' character,
1638 // so we need to do the lower-casing of the first alpha character.
1639 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1640 if (name.at(firstAlphaIndex).isUpper()) {
1641 name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1646 bool notInRevision = false;
1648 QDeclarativePropertyData *sig = signal(obj, QStringRef(&name), ¬InRevision);
1652 if (notInRevision && 0 == property(obj, propName, 0)) {
1653 Q_ASSERT(obj->type != -1);
1654 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1655 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1657 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));
1659 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1663 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1665 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1669 if (prop->value || !prop->values.isOne())
1670 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1672 prop->index = sig->coreIndex;
1675 obj->addSignalProperty(prop);
1677 if (prop->values.first()->object) {
1678 COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1679 prop->values.first()->type = Value::SignalObject;
1681 prop->values.first()->type = Value::SignalExpression;
1683 if (!prop->values.first()->value.isScript())
1684 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1686 QString script = prop->values.first()->value.asScript().trimmed();
1687 if (script.isEmpty())
1688 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1690 prop->values.first()->signalExpressionContextStack = ctxt.stack;
1699 Returns true if (value) property \a prop exists on obj, false otherwise.
1701 bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeScript::Property *prop,
1702 QDeclarativeScript::Object *obj)
1704 if (prop->name().isEmpty())
1706 if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1709 return property(obj, prop->name()) != 0;
1712 bool QDeclarativeCompiler::buildProperty(QDeclarativeScript::Property *prop,
1713 QDeclarativeScript::Object *obj,
1714 const BindingContext &ctxt)
1716 if (prop->isEmpty())
1717 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1719 const QMetaObject *metaObject = obj->metaObject();
1720 Q_ASSERT(metaObject);
1722 if (isAttachedPropertyName(prop->name())) {
1723 // Setup attached property data
1725 if (ctxt.isSubContext()) {
1726 // Attached properties cannot be used on sub-objects. Sub-objects
1727 // always exist in a binding sub-context, which is what we test
1729 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1732 QDeclarativeType *type = 0;
1733 QDeclarativeImportedNamespace *typeNamespace = 0;
1734 unit->imports().resolveType(prop->name().toString(), &type, 0, 0, 0, &typeNamespace);
1736 if (typeNamespace) {
1737 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1740 } else if (!type || !type->attachedPropertiesType()) {
1741 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1745 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1747 Q_ASSERT(type->attachedPropertiesFunction());
1748 prop->index = type->attachedPropertiesId();
1749 prop->value->metatype = type->attachedPropertiesType();
1751 // Setup regular property data
1752 bool notInRevision = false;
1753 QDeclarativePropertyData *d =
1754 prop->name().isEmpty()?0:property(obj, prop->name(), ¬InRevision);
1756 if (d == 0 && notInRevision) {
1757 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1758 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1760 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));
1762 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1765 prop->index = d->coreIndex;
1767 } else if (prop->isDefault) {
1768 QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
1769 QDeclarativePropertyData defaultPropertyData;
1770 defaultPropertyData.load(p, engine);
1772 prop->setName(QLatin1String(p.name()));
1773 prop->core = defaultPropertyData;
1774 prop->index = prop->core.coreIndex;
1777 // We can't error here as the "id" property does not require a
1778 // successful index resolution
1779 if (prop->index != -1)
1780 prop->type = prop->core.propType;
1782 // Check if this is an alias
1783 if (prop->index != -1 &&
1785 prop->parent->type != -1 &&
1786 output->types.at(prop->parent->type).component) {
1788 QDeclarativePropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1789 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1790 prop->isAlias = true;
1793 if (prop->index != -1 && !prop->values.isEmpty())
1794 prop->parent->setBindingBit(prop->index);
1797 if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1799 // The magic "id" behavior doesn't apply when "id" is resolved as a
1800 // default property or to sub-objects (which are always in binding
1802 COMPILE_CHECK(buildIdProperty(prop, obj));
1803 if (prop->type == QVariant::String &&
1804 prop->values.first()->value.isString())
1805 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1807 } else if (isAttachedPropertyName(prop->name())) {
1809 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1811 } else if (prop->index == -1) {
1813 if (prop->isDefault) {
1814 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1816 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1819 } else if (prop->value) {
1821 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1823 } else if (prop->core.isQList()) {
1825 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1827 } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) {
1829 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1833 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1840 bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
1841 QDeclarativeScript::Property *nsProp,
1842 QDeclarativeScript::Object *obj,
1843 const BindingContext &ctxt)
1846 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1848 for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1850 if (!isAttachedPropertyName(prop->name()))
1851 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1853 // Setup attached property data
1855 QDeclarativeType *type = 0;
1856 unit->imports().resolveType(ns, prop->name().toString(), &type, 0, 0, 0);
1858 if (!type || !type->attachedPropertiesType())
1859 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1862 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1864 Q_ASSERT(type->attachedPropertiesFunction());
1865 prop->index = type->index();
1866 prop->value->metatype = type->attachedPropertiesType();
1868 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1874 void QDeclarativeCompiler::genValueProperty(QDeclarativeScript::Property *prop,
1875 QDeclarativeScript::Object *obj)
1877 if (prop->core.isQList()) {
1878 genListProperty(prop, obj);
1880 genPropertyAssignment(prop, obj);
1884 void QDeclarativeCompiler::genListProperty(QDeclarativeScript::Property *prop,
1885 QDeclarativeScript::Object *obj)
1887 int listType = enginePrivate->listType(prop->type);
1889 Instruction::FetchQList fetch;
1890 fetch.property = prop->index;
1891 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1892 fetch.type = listType;
1893 output->addInstruction(fetch);
1895 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1897 if (v->type == Value::CreatedObject) {
1899 genObject(v->object);
1900 if (listTypeIsInterface) {
1901 Instruction::AssignObjectList assign;
1902 assign.line = prop->location.start.line;
1903 output->addInstruction(assign);
1905 Instruction::StoreObjectQList store;
1906 output->addInstruction(store);
1909 } else if (v->type == Value::PropertyBinding) {
1911 genBindingAssignment(v, prop, obj);
1917 Instruction::PopQList pop;
1918 output->addInstruction(pop);
1921 void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeScript::Property *prop,
1922 QDeclarativeScript::Object *obj,
1923 QDeclarativeScript::Property *valueTypeProperty)
1925 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1927 Q_ASSERT(v->type == Value::CreatedObject ||
1928 v->type == Value::PropertyBinding ||
1929 v->type == Value::Literal);
1931 if (v->type == Value::CreatedObject) {
1933 genObject(v->object);
1935 if (QDeclarativeMetaType::isInterface(prop->type)) {
1937 Instruction::StoreInterface store;
1938 store.line = v->object->location.start.line;
1939 store.propertyIndex = prop->index;
1940 output->addInstruction(store);
1942 } else if (prop->type == QMetaType::QVariant) {
1944 if (prop->core.isVMEProperty()) {
1945 Instruction::StoreVarObject store;
1946 store.line = v->object->location.start.line;
1947 store.propertyIndex = prop->index;
1948 output->addInstruction(store);
1950 Instruction::StoreVariantObject store;
1951 store.line = v->object->location.start.line;
1952 store.propertyIndex = prop->index;
1953 output->addInstruction(store);
1959 Instruction::StoreObject store;
1960 store.line = v->object->location.start.line;
1961 store.propertyIndex = prop->index;
1962 output->addInstruction(store);
1965 } else if (v->type == Value::PropertyBinding) {
1967 genBindingAssignment(v, prop, obj, valueTypeProperty);
1969 } else if (v->type == Value::Literal) {
1971 genLiteralAssignment(prop, v);
1977 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
1979 Q_ASSERT(v->type == Value::ValueSource ||
1980 v->type == Value::ValueInterceptor);
1982 if (v->type == Value::ValueSource) {
1983 genObject(v->object);
1985 Instruction::StoreValueSource store;
1986 if (valueTypeProperty) {
1987 store.property = genValueTypeData(prop, valueTypeProperty);
1990 store.property = prop->core;
1993 QDeclarativeType *valueType = toQmlType(v->object);
1994 store.castValue = valueType->propertyValueSourceCast();
1995 output->addInstruction(store);
1997 } else if (v->type == Value::ValueInterceptor) {
1998 genObject(v->object);
2000 Instruction::StoreValueInterceptor store;
2001 if (valueTypeProperty) {
2002 store.property = genValueTypeData(prop, valueTypeProperty);
2005 store.property = prop->core;
2008 QDeclarativeType *valueType = toQmlType(v->object);
2009 store.castValue = valueType->propertyValueInterceptorCast();
2010 output->addInstruction(store);
2016 bool QDeclarativeCompiler::buildIdProperty(QDeclarativeScript::Property *prop,
2017 QDeclarativeScript::Object *obj)
2020 prop->values.isMany() ||
2021 prop->values.first()->object)
2022 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
2024 QDeclarativeScript::Value *idValue = prop->values.first();
2025 QString val = idValue->primitive();
2027 COMPILE_CHECK(checkValidId(idValue, val));
2029 if (compileState->ids.value(val))
2030 COMPILE_EXCEPTION(prop, tr("id is not unique"));
2032 prop->values.first()->type = Value::Id;
2040 void QDeclarativeCompiler::addId(const QString &id, QDeclarativeScript::Object *obj)
2043 Q_ASSERT(!compileState->ids.value(id));
2044 Q_ASSERT(obj->id == id);
2045 obj->idIndex = compileState->ids.count();
2046 compileState->ids.append(obj);
2049 void QDeclarativeCompiler::addBindingReference(JSBindingReference *ref)
2051 Q_ASSERT(ref->value && !ref->value->bindingReference);
2052 ref->value->bindingReference = ref;
2053 compileState->totalBindingsCount++;
2054 compileState->bindings.prepend(ref);
2057 void QDeclarativeCompiler::saveComponentState()
2059 Q_ASSERT(compileState->root);
2060 Q_ASSERT(compileState->root->componentCompileState == 0);
2062 compileState->root->componentCompileState = compileState;
2065 componentStats->savedComponentStats.append(componentStats->componentStat);
2068 QDeclarativeCompilerTypes::ComponentCompileState *
2069 QDeclarativeCompiler::componentState(QDeclarativeScript::Object *obj)
2071 Q_ASSERT(obj->componentCompileState);
2072 return obj->componentCompileState;
2075 // Build attached property object. In this example,
2079 // GridView is an attached property object.
2080 bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeScript::Property *prop,
2081 QDeclarativeScript::Object *obj,
2082 const BindingContext &ctxt)
2084 Q_ASSERT(prop->value);
2085 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
2087 compileState->objectDepth.push();
2089 obj->addAttachedProperty(prop);
2091 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2093 compileState->objectDepth.pop();
2099 // Build "grouped" properties. In this example:
2101 // font.pointSize: 12
2102 // font.family: "Helvetica"
2104 // font is a nested property. pointSize and family are not.
2105 bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeScript::Property *prop,
2106 QDeclarativeScript::Object *obj,
2107 const BindingContext &ctxt)
2109 Q_ASSERT(prop->type != 0);
2110 Q_ASSERT(prop->index != -1);
2112 if (QDeclarativeValueTypeFactory::isValueType(prop->type)) {
2113 if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
2115 if (!prop->values.isEmpty()) {
2116 if (prop->values.first()->location < prop->value->location) {
2117 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
2119 COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
2123 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) {
2124 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2128 if (prop->isAlias) {
2129 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
2130 vtProp->isAlias = true;
2134 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
2135 prop->value, obj, ctxt.incr()));
2136 obj->addValueTypeProperty(prop);
2138 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2142 // Load the nested property's meta type
2143 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
2144 if (!prop->value->metatype)
2145 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2147 if (!prop->values.isEmpty())
2148 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
2150 obj->addGroupedProperty(prop);
2152 compileState->objectDepth.push();
2154 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2156 compileState->objectDepth.pop();
2162 bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
2163 QDeclarativeScript::Object *obj,
2164 QDeclarativeScript::Object *baseObj,
2165 const BindingContext &ctxt)
2167 compileState->objectDepth.push();
2169 if (obj->defaultProperty)
2170 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
2171 obj->metatype = type->metaObject();
2173 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
2175 QDeclarativePropertyData *d = property(obj, prop->name());
2177 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
2179 prop->index = d->coreIndex;
2180 prop->type = d->propType;
2182 prop->isValueTypeSubProperty = true;
2185 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
2187 if (prop->values.isMany()) {
2188 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
2189 } else if (!prop->values.isEmpty()) {
2190 QDeclarativeScript::Value *value = prop->values.first();
2192 if (value->object) {
2193 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
2194 } else if (value->value.isScript()) {
2195 // ### Check for writability
2197 //optimization for <Type>.<EnumValue> enum assignments
2198 bool isEnumAssignment = false;
2200 if (prop->core.isEnum())
2201 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, value, &isEnumAssignment));
2203 if (isEnumAssignment) {
2204 value->type = Value::Literal;
2206 JSBindingReference *reference = pool->New<JSBindingReference>();
2207 reference->expression = value->value;
2208 reference->property = prop;
2209 reference->value = value;
2210 reference->bindingContext = ctxt;
2211 reference->bindingContext.owner++;
2212 addBindingReference(reference);
2213 value->type = Value::PropertyBinding;
2216 COMPILE_CHECK(testLiteralAssignment(prop, value));
2217 value->type = Value::Literal;
2221 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2222 Q_ASSERT(v->object);
2224 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
2227 obj->addValueProperty(prop);
2230 compileState->objectDepth.pop();
2235 // Build assignments to QML lists. QML lists are properties of type
2236 // QDeclarativeListProperty<T>. List properties can accept a list of
2237 // objects, or a single binding.
2238 bool QDeclarativeCompiler::buildListProperty(QDeclarativeScript::Property *prop,
2239 QDeclarativeScript::Object *obj,
2240 const BindingContext &ctxt)
2242 Q_ASSERT(prop->core.isQList());
2244 compileState->listDepth.push();
2248 obj->addValueProperty(prop);
2250 int listType = enginePrivate->listType(t);
2251 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
2253 bool assignedBinding = false;
2254 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2256 v->type = Value::CreatedObject;
2257 COMPILE_CHECK(buildObject(v->object, ctxt));
2259 // We check object coercian here. We check interface assignment
2261 if (!listTypeIsInterface) {
2262 if (!canCoerce(listType, v->object)) {
2263 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2267 } else if (v->value.isScript()) {
2268 if (assignedBinding)
2269 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2271 assignedBinding = true;
2272 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2273 v->type = Value::PropertyBinding;
2275 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2279 compileState->listDepth.pop();
2284 // Compiles an assignment to a QDeclarativeScriptString property
2285 bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeScript::Property *prop,
2286 QDeclarativeScript::Object *obj,
2287 const BindingContext &ctxt)
2289 if (prop->values.isMany())
2290 COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2292 if (prop->values.first()->object)
2293 COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2295 prop->scriptStringScope = ctxt.stack;
2296 obj->addScriptStringProperty(prop);
2301 // Compile regular property assignments of the form "property: <value>"
2302 bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeScript::Property *prop,
2303 QDeclarativeScript::Object *obj,
2304 const BindingContext &ctxt)
2306 obj->addValueProperty(prop);
2308 if (prop->values.isMany())
2309 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2311 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2314 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2318 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2323 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2324 Q_ASSERT(v->object);
2325 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2331 // Compile assigning a single object instance to a regular property
2332 bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeScript::Property *prop,
2333 QDeclarativeScript::Object *obj,
2334 QDeclarativeScript::Value *v,
2335 const BindingContext &ctxt)
2337 Q_ASSERT(prop->index != -1);
2338 Q_ASSERT(v->object->type != -1);
2340 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2341 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2343 if (QDeclarativeMetaType::isInterface(prop->type)) {
2345 // Assigning an object to an interface ptr property
2346 COMPILE_CHECK(buildObject(v->object, ctxt));
2348 v->type = Value::CreatedObject;
2350 } else if (prop->type == QMetaType::QVariant) {
2352 // Assigning an object to a QVariant
2353 COMPILE_CHECK(buildObject(v->object, ctxt));
2355 v->type = Value::CreatedObject;
2357 // Normally buildObject() will set this up, but we need the static
2358 // meta object earlier to test for assignability. It doesn't matter
2359 // that there may still be outstanding synthesized meta object changes
2360 // on this type, as they are not relevant for assignability testing
2361 v->object->metatype = output->types.at(v->object->type).metaObject();
2362 Q_ASSERT(v->object->metaObject());
2364 // We want to raw metaObject here as the raw metaobject is the
2365 // actual property type before we applied any extensions that might
2366 // effect the properties on the type, but don't effect assignability
2367 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2369 // Will be true if the assgned type inherits propertyMetaObject
2370 bool isAssignable = false;
2371 // Determine isAssignable value
2372 if (propertyMetaObject) {
2373 const QMetaObject *c = v->object->metatype;
2375 isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject));
2376 c = c->superClass();
2381 // Simple assignment
2382 COMPILE_CHECK(buildObject(v->object, ctxt));
2384 v->type = Value::CreatedObject;
2385 } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) {
2386 // Automatic "Component" insertion
2387 QDeclarativeScript::Object *root = v->object;
2388 QDeclarativeScript::Object *component = pool->New<Object>();
2389 component->type = componentTypeRef();
2390 component->typeName = QStringLiteral("Qt/Component");
2391 component->metatype = &QDeclarativeComponent::staticMetaObject;
2392 component->location = root->location;
2393 QDeclarativeScript::Value *componentValue = pool->New<Value>();
2394 componentValue->object = root;
2395 component->getDefaultProperty()->addValue(componentValue);
2396 v->object = component;
2397 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2399 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2406 // Compile assigning a single object instance to a regular property using the "on" syntax.
2410 // NumberAnimation on x { }
2412 bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeScript::Property *prop,
2413 QDeclarativeScript::Object *obj,
2414 QDeclarativeScript::Object *baseObj,
2415 QDeclarativeScript::Value *v,
2416 const BindingContext &ctxt)
2418 Q_ASSERT(prop->index != -1);
2419 Q_ASSERT(v->object->type != -1);
2423 if (!prop->core.isWritable())
2424 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2427 // Normally buildObject() will set this up, but we need the static
2428 // meta object earlier to test for assignability. It doesn't matter
2429 // that there may still be outstanding synthesized meta object changes
2430 // on this type, as they are not relevant for assignability testing
2431 v->object->metatype = output->types.at(v->object->type).metaObject();
2432 Q_ASSERT(v->object->metaObject());
2434 // Will be true if the assigned type inherits QDeclarativePropertyValueSource
2435 bool isPropertyValue = false;
2436 // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor
2437 bool isPropertyInterceptor = false;
2438 if (QDeclarativeType *valueType = toQmlType(v->object)) {
2439 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2440 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2443 if (isPropertyValue || isPropertyInterceptor) {
2444 // Assign as a property value source
2445 COMPILE_CHECK(buildObject(v->object, ctxt));
2447 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2448 buildDynamicMeta(baseObj, ForceCreation);
2449 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2451 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(v->object->typeName).arg(prop->name().toString()));
2457 // Compile assigning a literal or binding to a regular property
2458 bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeScript::Property *prop,
2459 QDeclarativeScript::Object *obj,
2460 QDeclarativeScript::Value *v,
2461 const BindingContext &ctxt)
2463 Q_ASSERT(prop->index != -1);
2465 if (v->value.isScript()) {
2467 //optimization for <Type>.<EnumValue> enum assignments
2468 if (prop->core.isEnum()) {
2469 bool isEnumAssignment = false;
2470 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, v, &isEnumAssignment));
2471 if (isEnumAssignment) {
2472 v->type = Value::Literal;
2477 // Test for other binding optimizations
2478 if (!buildLiteralBinding(v, prop, ctxt))
2479 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2481 v->type = Value::PropertyBinding;
2485 COMPILE_CHECK(testLiteralAssignment(prop, v));
2487 v->type = Value::Literal;
2493 bool QDeclarativeCompiler::testQualifiedEnumAssignment(QDeclarativeScript::Property *prop,
2494 QDeclarativeScript::Object *obj,
2495 QDeclarativeScript::Value *v,
2498 *isAssignment = false;
2499 if (!prop->core.isEnum())
2502 QMetaProperty mprop = obj->metaObject()->property(prop->index);
2504 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2505 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2507 QString string = v->value.asString();
2508 if (!string.at(0).isUpper())
2511 QStringList parts = string.split(QLatin1Char('.'));
2512 if (parts.count() != 2)
2515 QString typeName = parts.at(0);
2516 QDeclarativeType *type = 0;
2517 unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
2519 //handle enums on value types (where obj->typeName is empty)
2520 QString objTypeName = obj->typeName;
2521 if (objTypeName.isEmpty()) {
2522 QDeclarativeType *objType = toQmlType(obj);
2524 objTypeName = objType->qmlTypeName();
2530 QString enumValue = parts.at(1);
2534 if (objTypeName == type->qmlTypeName()) {
2535 // When these two match, we can short cut the search
2536 if (mprop.isFlagType()) {
2537 value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
2539 value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
2542 // Otherwise we have to search the whole type
2543 // This matches the logic in QV8TypeWrapper
2544 QByteArray enumName = enumValue.toUtf8();
2545 const QMetaObject *metaObject = type->baseMetaObject();
2547 for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
2548 QMetaEnum e = metaObject->enumerator(ii);
2549 value = e.keyToValue(enumName.constData(), &ok);
2556 v->type = Value::Literal;
2557 v->value = QDeclarativeScript::Variant((double)value);
2558 *isAssignment = true;
2563 struct StaticQtMetaObject : public QObject
2565 static const QMetaObject *get()
2566 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2569 // Similar logic to above, but not knowing target property.
2570 int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const
2572 int dot = script.indexOf('.');
2574 const QByteArray &scope = script.left(dot);
2575 QDeclarativeType *type = 0;
2576 unit->imports().resolveType(QString::fromUtf8(script.left(dot)), &type, 0, 0, 0, 0);
2577 if (!type && scope != "Qt")
2579 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2580 const char *key = script.constData() + dot+1;
2581 int i = mo->enumeratorCount();
2584 int v = mo->enumerator(i).keyToValue(key, &ok);
2592 const QMetaObject *QDeclarativeCompiler::resolveType(const QString& name) const
2594 QDeclarativeType *qmltype = 0;
2595 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2599 return qmltype->metaObject();
2602 // similar to logic of completeComponentBuild, but also sticks data
2603 // into primitives at the end
2604 int QDeclarativeCompiler::rewriteBinding(const QDeclarativeScript::Variant& value, const QString& name)
2606 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2607 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1));
2609 QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0);
2611 return output->indexForString(rewrite);
2614 QString QDeclarativeCompiler::rewriteSignalHandler(const QString &handler, const QString &name)
2616 QDeclarativeRewrite::RewriteSignalHandler rewriteSignalHandler;
2617 return rewriteSignalHandler(handler, name);
2620 // Ensures that the dynamic meta specification on obj is valid
2621 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeScript::Object *obj)
2623 bool seenDefaultProperty = false;
2625 // We use a coarse grain, 31 bit hash to check if there are duplicates.
2626 // Calculating the hash for the names is not a waste as we have to test
2627 // them against the illegalNames set anyway.
2628 QHashField propNames;
2629 QHashField methodNames;
2632 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2633 const QDeclarativeScript::Object::DynamicProperty &prop = *p;
2635 if (prop.isDefaultProperty) {
2636 if (seenDefaultProperty)
2637 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2638 seenDefaultProperty = true;
2641 if (propNames.testAndSet(prop.name.hash())) {
2642 for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p;
2643 p2 = obj->dynamicProperties.next(p2)) {
2644 if (p2->name == prop.name)
2645 COMPILE_EXCEPTION(&prop, tr("Duplicate property name"));
2649 if (prop.name.at(0).isUpper())
2650 COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
2652 if (enginePrivate->v8engine()->illegalNames().contains(prop.name))
2653 COMPILE_EXCEPTION(&prop, tr("Illegal property name"));
2656 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2657 const QDeclarativeScript::Object::DynamicSignal &currSig = *s;
2659 if (methodNames.testAndSet(currSig.name.hash())) {
2660 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2661 s2 = obj->dynamicSignals.next(s2)) {
2662 if (s2->name == currSig.name)
2663 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2667 if (currSig.name.at(0).isUpper())
2668 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2669 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2670 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2673 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2674 const QDeclarativeScript::Object::DynamicSlot &currSlot = *s;
2676 if (methodNames.testAndSet(currSlot.name.hash())) {
2677 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2678 s2 = obj->dynamicSignals.next(s2)) {
2679 if (s2->name == currSlot.name)
2680 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2682 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2683 s2 = obj->dynamicSlots.next(s2)) {
2684 if (s2->name == currSlot.name)
2685 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2689 if (currSlot.name.at(0).isUpper())
2690 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2691 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2692 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2698 bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeScript::Object *obj)
2700 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2701 p = obj->dynamicProperties.next(p)) {
2703 if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2706 Property *property = 0;
2707 if (p->isDefaultProperty) {
2708 property = obj->getDefaultProperty();
2710 property = obj->getProperty(p->name);
2711 if (!property->values.isEmpty())
2712 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2716 property->isReadOnlyDeclaration = true;
2718 if (property->value)
2719 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2721 property->values.append(p->defaultValue->values);
2726 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2728 bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeScript::Object *obj, DynamicMetaMode mode)
2731 Q_ASSERT(obj->metatype);
2733 if (mode != ForceCreation &&
2734 obj->dynamicProperties.isEmpty() &&
2735 obj->dynamicSignals.isEmpty() &&
2736 obj->dynamicSlots.isEmpty())
2739 bool resolveAlias = (mode == ResolveAliases);
2741 const Object::DynamicProperty *defaultProperty = 0;
2743 int varPropCount = 0;
2744 int totalPropCount = 0;
2745 int firstPropertyVarIndex = 0;
2747 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2749 if (p->type == Object::DynamicProperty::Alias)
2751 if (p->type == Object::DynamicProperty::Var)
2754 if (p->isDefaultProperty &&
2755 (resolveAlias || p->type != Object::DynamicProperty::Alias))
2756 defaultProperty = p;
2758 if (!resolveAlias) {
2759 // No point doing this for both the alias and non alias cases
2760 QDeclarativePropertyData *d = property(obj, p->name);
2761 if (d && d->isFinal())
2762 COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2766 bool buildData = resolveAlias || aliasCount == 0;
2768 QByteArray dynamicData;
2770 typedef QDeclarativeVMEMetaData VMD;
2772 dynamicData = QByteArray(sizeof(QDeclarativeVMEMetaData) +
2773 (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) +
2774 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2775 aliasCount * sizeof(VMD::AliasData), 0);
2778 int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1);
2780 QByteArray newClassName = obj->metatype->className();
2781 newClassName.append("_QML_");
2782 newClassName.append(QByteArray::number(uniqueClassId));
2784 if (compileState->root == obj && !compileState->nested) {
2785 QString path = output->url.path();
2786 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2787 if (lastSlash > -1) {
2788 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2789 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2790 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId);
2794 QFastMetaBuilder builder;
2795 QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(),
2796 obj->dynamicProperties.count() - (resolveAlias?0:aliasCount),
2797 obj->dynamicSlots.count(),
2798 obj->dynamicSignals.count() + obj->dynamicProperties.count(),
2799 defaultProperty?1:0);
2802 Object::DynamicProperty::Type dtype;
2804 const char *cppType;
2805 } builtinTypes[] = {
2806 { Object::DynamicProperty::Var, 0, "QVariant" },
2807 { Object::DynamicProperty::Variant, 0, "QVariant" },
2808 { Object::DynamicProperty::Int, QMetaType::Int, "int" },
2809 { Object::DynamicProperty::Bool, QMetaType::Bool, "bool" },
2810 { Object::DynamicProperty::Real, QMetaType::Double, "double" },
2811 { Object::DynamicProperty::String, QMetaType::QString, "QString" },
2812 { Object::DynamicProperty::Url, QMetaType::QUrl, "QUrl" },
2813 { Object::DynamicProperty::Color, QMetaType::QColor, "QColor" },
2814 { Object::DynamicProperty::Time, QMetaType::QTime, "QTime" },
2815 { Object::DynamicProperty::Date, QMetaType::QDate, "QDate" },
2816 { Object::DynamicProperty::DateTime, QMetaType::QDateTime, "QDateTime" },
2818 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2819 QFastMetaBuilder::StringRef typeRefs[builtinTypeCount];
2821 // Reserve dynamic properties
2822 if (obj->dynamicProperties.count()) {
2823 typedef QDeclarativeVMEMetaData VMD;
2825 int effectivePropertyIndex = 0;
2826 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2828 // Reserve space for name
2829 p->nameRef = builder.newString(p->name.utf8length());
2831 int propertyType = 0;
2832 bool readonly = false;
2833 QFastMetaBuilder::StringRef typeRef;
2835 if (p->type == Object::DynamicProperty::Alias) {
2837 } else if (p->type < builtinTypeCount) {
2838 Q_ASSERT(builtinTypes[p->type].dtype == p->type);
2839 propertyType = builtinTypes[p->type].metaType;
2840 if (typeRefs[p->type].isEmpty())
2841 typeRefs[p->type] = builder.newString(strlen(builtinTypes[p->type].cppType));
2842 typeRef = typeRefs[p->type];
2843 if (p->type == Object::DynamicProperty::Variant)
2847 Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
2848 p->type == Object::DynamicProperty::Custom);
2850 // XXX don't double resolve this in the case of an alias run
2852 QByteArray customTypeName;
2853 QDeclarativeType *qmltype = 0;
2855 if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
2856 COMPILE_EXCEPTION(p, tr("Invalid property type"));
2859 QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(QUrl(url));
2861 Q_ASSERT(tdata->isComplete());
2863 QDeclarativeCompiledData *data = tdata->compiledData();
2864 customTypeName = data->root->className();
2868 customTypeName = qmltype->typeName();
2871 if (p->type == Object::DynamicProperty::Custom) {
2872 customTypeName += '*';
2873 propertyType = QMetaType::QObjectStar;
2876 customTypeName = QByteArray("QDeclarativeListProperty<") + customTypeName + QByteArray(">");
2877 propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
2880 p->resolvedCustomTypeName = pool->NewByteArray(customTypeName);
2881 p->typeRef = builder.newString(customTypeName.length());
2882 typeRef = p->typeRef;
2885 if (p->type == Object::DynamicProperty::Var)
2892 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2893 vmd->propertyCount++;
2894 (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType;
2897 if (p->type < builtinTypeCount)
2898 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef, (QMetaType::Type)propertyType,
2899 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2900 effectivePropertyIndex);
2902 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef,
2903 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2904 effectivePropertyIndex);
2906 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2907 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2909 effectivePropertyIndex++;
2913 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2915 vmd->varPropertyCount = varPropCount;
2916 firstPropertyVarIndex = effectivePropertyIndex;
2917 totalPropCount = varPropCount + effectivePropertyIndex;
2918 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2919 if (p->type == Object::DynamicProperty::Var) {
2920 QFastMetaBuilder::StringRef typeRef = typeRefs[p->type];
2922 vmd->propertyCount++;
2923 (vmd->propertyData() + effectivePropertyIndex)->propertyType = -1;
2926 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef,
2927 (QMetaType::Type)-1,
2928 p->isReadOnly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2929 effectivePropertyIndex);
2931 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2932 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2934 effectivePropertyIndex++;
2941 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2942 if (p->type == Object::DynamicProperty::Alias) {
2944 Q_ASSERT(buildData);
2945 ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++;
2946 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex,
2949 // Even if we aren't resolving the alias, we need a fake signal so that the
2950 // metaobject remains consistent across the resolve and non-resolve alias runs
2951 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2952 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2953 effectivePropertyIndex++;
2960 // Reserve default property
2961 QFastMetaBuilder::StringRef defPropRef;
2962 if (defaultProperty) {
2963 defPropRef = builder.newString(strlen("DefaultProperty"));
2964 builder.setClassInfo(0, defPropRef, defaultProperty->nameRef);
2967 // Reserve dynamic signals
2968 int signalIndex = 0;
2969 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2971 int paramCount = s->parameterNames.count();
2973 int signatureSize = s->name.utf8length() + 2 /* paren */;
2975 if (paramCount) signatureSize += s->parameterTypesLength() + (paramCount - 1) /* commas */;
2976 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1) /* commas */;
2978 s->signatureRef = builder.newString(signatureSize);
2979 if (namesSize) s->parameterNamesRef = builder.newString(namesSize);
2982 ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++;
2984 builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->signatureRef, s->parameterNamesRef);
2988 // Reserve dynamic slots
2989 if (obj->dynamicSlots.count()) {
2991 // Allocate QVariant string
2992 if (typeRefs[0].isEmpty())
2993 typeRefs[0] = builder.newString(strlen(builtinTypes[0].cppType));
2995 typedef QDeclarativeVMEMetaData VMD;
2997 int methodIndex = 0;
2998 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2999 int paramCount = s->parameterNames.count();
3001 int signatureSize = s->name.utf8length() + 2 /* paren */;
3003 if (paramCount) signatureSize += (paramCount * strlen("QVariant") + (paramCount - 1));
3004 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
3006 s->signatureRef = builder.newString(signatureSize);
3007 if (namesSize) s->parameterNamesRef = builder.newString(namesSize);
3009 builder.setMethod(methodIndex, s->signatureRef, s->parameterNamesRef, typeRefs[0]);
3013 funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ +
3014 namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
3015 funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
3016 for (int jj = 0; jj < paramCount; ++jj) {
3017 if (jj) funcScript.append(QLatin1Char(','));
3018 funcScript.append(QLatin1String(s->parameterNames.at(jj)));
3020 funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
3022 VMD::MethodData methodData = { s->parameterNames.count(), 0,
3023 funcScript.length(),
3024 s->location.start.line };
3026 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
3029 VMD::MethodData &md = *(vmd->methodData() + methodIndex);
3031 md.bodyOffset = dynamicData.size();
3033 dynamicData.append((const char *)funcScript.constData(),
3034 (funcScript.length() * sizeof(QChar)));
3041 // Now allocate used builtin types
3042 for (int ii = 0; ii < builtinTypeCount; ++ii) {
3043 if (!typeRefs[ii].isEmpty())
3044 typeRefs[ii].load(builtinTypes[ii].cppType);
3047 // Now allocate properties
3048 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
3050 char *d = p->changedSignatureRef.data();
3051 p->name.writeUtf8(d);
3052 strcpy(d + p->name.utf8length(), "Changed()");
3054 if (p->type == Object::DynamicProperty::Alias && !resolveAlias)
3057 p->nameRef.load(p->name);
3059 if (p->type >= builtinTypeCount) {
3060 Q_ASSERT(p->resolvedCustomTypeName);
3061 p->typeRef.load(*p->resolvedCustomTypeName);
3065 // Allocate default property if necessary
3066 if (defaultProperty)
3067 strcpy(defPropRef.data(), "DefaultProperty");
3069 // Now allocate signals
3070 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
3072 char *d = s->signatureRef.data();
3073 char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data();
3074 s->name.writeUtf8(d); d += s->name.utf8length();
3077 for (int jj = 0; jj < s->parameterNames.count(); ++jj) {
3078 if (jj != 0) { *d++ = ','; *d2++ = ','; }
3079 strcpy(d, s->parameterTypes.at(jj).constData());
3080 d += s->parameterTypes.at(jj).length();
3081 s->parameterNames.at(jj).writeUtf8(d2);
3082 d2 += s->parameterNames.at(jj).utf8length();
3089 // Now allocate methods
3090 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3091 char *d = s->signatureRef.data();
3092 char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data();
3093 s->name.writeUtf8(d); d += s->name.utf8length();
3095 for (int jj = 0; jj < s->parameterNames.count(); ++jj) {
3096 if (jj != 0) { *d++ = ','; *d2++ = ','; }
3097 strcpy(d, "QVariant");
3098 d += strlen("QVariant");
3099 strcpy(d2, s->parameterNames.at(jj).constData());
3100 d2 += s->parameterNames.at(jj).length();
3107 // Now allocate class name
3108 classNameRef.load(newClassName);
3110 obj->metadata = builder.toData();
3111 builder.fromData(&obj->extObject, obj->metatype, obj->metadata);
3113 if (mode == IgnoreAliases && aliasCount)
3114 compileState->aliasingObjects.append(obj);
3116 obj->synthdata = dynamicData;
3118 if (obj->synthCache) {
3119 obj->synthCache->release();
3120 obj->synthCache = 0;
3123 if (obj->type != -1) {
3124 QDeclarativePropertyCache *superCache = output->types[obj->type].createPropertyCache(engine);
3125 QDeclarativePropertyCache *cache =
3126 superCache->copyAndAppend(engine, &obj->extObject,
3127 QDeclarativePropertyData::NoFlags,
3128 QDeclarativePropertyData::IsVMEFunction,
3129 QDeclarativePropertyData::IsVMESignal);
3131 // now we modify the flags appropriately for var properties.
3132 int propertyOffset = obj->extObject.propertyOffset();
3133 QDeclarativePropertyData *currPropData = 0;
3134 for (int pvi = firstPropertyVarIndex; pvi < totalPropCount; ++pvi) {
3135 currPropData = cache->property(pvi + propertyOffset);
3136 currPropData->setFlags(currPropData->getFlags() | QDeclarativePropertyData::IsVMEProperty);
3139 obj->synthCache = cache;
3145 bool QDeclarativeCompiler::checkValidId(QDeclarativeScript::Value *v, const QString &val)
3148 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
3150 QChar ch = val.at(0);
3151 if (ch.isLetter() && !ch.isLower())
3152 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
3154 QChar u(QLatin1Char('_'));
3155 if (!ch.isLetter() && ch != u)
3156 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
3158 for (int ii = 1; ii < val.count(); ++ii) {
3160 if (!ch.isLetterOrNumber() && ch != u)
3161 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
3164 if (enginePrivate->v8engine()->illegalNames().contains(val))
3165 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
3170 #include <private/qdeclarativejsparser_p.h>
3172 static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node)
3174 if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) {
3176 static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name.toString();
3177 return QStringList() << name;
3178 } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) {
3179 QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node);
3181 QStringList rv = astNodeToStringList(expr->base);
3184 rv.append(expr->name.toString());
3187 return QStringList();
3190 bool QDeclarativeCompiler::compileAlias(QFastMetaBuilder &builder,
3192 QDeclarativeScript::Object *obj,
3193 int propIndex, int aliasIndex,
3194 Object::DynamicProperty &prop)
3196 if (!prop.defaultValue)
3197 COMPILE_EXCEPTION(obj, tr("No property alias location"));
3199 if (!prop.defaultValue->values.isOne() ||
3200 prop.defaultValue->values.first()->object ||
3201 !prop.defaultValue->values.first()->value.isScript())
3202 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3204 QDeclarativeJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST();
3206 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
3208 QStringList alias = astNodeToStringList(node);
3210 if (alias.count() < 1 || alias.count() > 3)
3211 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
3213 QDeclarativeScript::Object *idObject = compileState->ids.value(alias.at(0));
3215 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
3217 QByteArray typeName;
3222 bool writable = false;
3223 bool resettable = false;
3224 if (alias.count() == 2 || alias.count() == 3) {
3225 propIdx = indexOfProperty(idObject, alias.at(1));
3227 if (-1 == propIdx) {
3228 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3229 } else if (propIdx > 0xFFFF) {
3230 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
3233 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
3234 if (!aliasProperty.isScriptable())
3235 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3237 writable = aliasProperty.isWritable() && !prop.isReadOnly;
3238 resettable = aliasProperty.isResettable() && !prop.isReadOnly;
3240 if (aliasProperty.type() < QVariant::UserType ||
3241 aliasProperty.type() == QVariant::LastType /* for QVariant */ )
3242 type = aliasProperty.type();
3244 if (alias.count() == 3) {
3245 QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
3247 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3249 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
3251 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
3252 if (valueTypeIndex == -1)
3253 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3254 Q_ASSERT(valueTypeIndex <= 0xFF);
3256 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
3257 propIdx |= (valueTypeIndex << 16);
3259 // update the property type
3260 type = aliasProperty.type();
3261 if (type >= (int)QVariant::UserType)
3265 if (aliasProperty.isEnumType())
3266 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
3268 typeName = aliasProperty.typeName();
3270 Q_ASSERT(idObject->type != -1); // How else did it get an id?
3272 const QDeclarativeCompiledData::TypeReference &ref = output->types.at(idObject->type);
3274 typeName = ref.type->typeName();
3276 typeName = ref.component->root->className();
3281 if (typeName.endsWith('*'))
3282 flags |= QML_ALIAS_FLAG_PTR;
3284 QDeclarativeVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags };
3286 typedef QDeclarativeVMEMetaData VMD;
3287 VMD *vmd = (QDeclarativeVMEMetaData *)data.data();
3288 *(vmd->aliasData() + aliasIndex) = aliasData;
3290 prop.nameRef = builder.newString(prop.name.utf8length());
3291 prop.resolvedCustomTypeName = pool->NewByteArray(typeName);
3292 prop.typeRef = builder.newString(typeName.length());
3294 int propertyFlags = 0;
3296 propertyFlags |= QFastMetaBuilder::Writable;
3298 propertyFlags |= QFastMetaBuilder::Resettable;
3300 builder.setProperty(propIndex, prop.nameRef, prop.typeRef, (QMetaType::Type)type,
3301 (QFastMetaBuilder::PropertyFlag)propertyFlags,
3307 bool QDeclarativeCompiler::buildBinding(QDeclarativeScript::Value *value,
3308 QDeclarativeScript::Property *prop,
3309 const BindingContext &ctxt)
3311 Q_ASSERT(prop->index != -1);
3312 Q_ASSERT(prop->parent);
3313 Q_ASSERT(prop->parent->metaObject());
3315 if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
3316 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3318 JSBindingReference *reference = pool->New<JSBindingReference>();
3319 reference->expression = value->value;
3320 reference->property = prop;
3321 reference->value = value;
3322 reference->bindingContext = ctxt;
3323 addBindingReference(reference);
3328 bool QDeclarativeCompiler::buildLiteralBinding(QDeclarativeScript::Value *v,
3329 QDeclarativeScript::Property *prop,
3330 const QDeclarativeCompilerTypes::BindingContext &)
3332 Q_ASSERT(v->value.isScript());
3334 if (!prop->core.isWritable())
3337 AST::Node *binding = v->value.asAST();
3339 if (prop->type == QVariant::String) {
3340 if (AST::CallExpression *e = AST::cast<AST::CallExpression *>(binding)) {
3341 if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(e->base)) {
3342 if (i->name == qsTrId_string) {
3343 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3344 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3346 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3347 (!arg2 || arg2->expression->kind == AST::Node::Kind_NumericLiteral) &&
3348 (!arg2 || !arg2->next)) {
3353 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3354 if (arg2) n = (int)AST::cast<AST::NumericLiteral *>(arg2->expression)->value;
3356 TrBindingReference *reference = pool->New<TrBindingReference>();
3357 reference->dataType = BindingReference::TrId;
3358 reference->text = text;
3360 v->bindingReference = reference;
3364 } else if (i->name == qsTr_string) {
3366 AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3367 AST::ArgumentList *arg2 = arg1?arg1->next:0;
3368 AST::ArgumentList *arg3 = arg2?arg2->next:0;
3370 if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3371 (!arg2 || arg2->expression->kind == AST::Node::Kind_StringLiteral) &&
3372 (!arg3 || arg3->expression->kind == AST::Node::Kind_NumericLiteral) &&
3373 (!arg3 || !arg3->next)) {
3379 text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3380 if (arg2) comment = AST::cast<AST::StringLiteral *>(arg2->expression)->value;
3381 if (arg3) n = (int)AST::cast<AST::NumericLiteral *>(arg3->expression)->value;
3383 TrBindingReference *reference = pool->New<TrBindingReference>();
3384 reference->dataType = BindingReference::Tr;
3385 reference->text = text;
3386 reference->comment = comment;
3388 v->bindingReference = reference;
3401 void QDeclarativeCompiler::genBindingAssignment(QDeclarativeScript::Value *binding,
3402 QDeclarativeScript::Property *prop,
3403 QDeclarativeScript::Object *obj,
3404 QDeclarativeScript::Property *valueTypeProperty)
3407 Q_ASSERT(binding->bindingReference);
3409 const BindingReference &ref = *binding->bindingReference;
3410 if (ref.dataType == BindingReference::TrId) {
3411 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3413 Instruction::StoreTrIdString store;
3414 store.propertyIndex = prop->core.coreIndex;
3415 store.text = output->indexForByteArray(tr.text.toUtf8());
3417 output->addInstruction(store);
3418 } else if (ref.dataType == BindingReference::Tr) {
3419 const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3421 Instruction::StoreTrString store;
3422 store.propertyIndex = prop->core.coreIndex;
3423 store.context = translationContextIndex();
3424 store.text = output->indexForByteArray(tr.text.toUtf8());
3425 store.comment = output->indexForByteArray(tr.comment.toUtf8());
3427 output->addInstruction(store);
3428 } else if (ref.dataType == BindingReference::V4) {
3429 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3431 Instruction::StoreV4Binding store;
3432 store.value = js.compiledIndex;
3433 store.context = js.bindingContext.stack;
3434 store.owner = js.bindingContext.owner;
3435 if (valueTypeProperty) {
3436 store.property = (valueTypeProperty->index & 0xFFFF) |
3437 ((valueTypeProperty->type & 0xFF)) << 16 |
3438 ((prop->index & 0xFF) << 24);
3439 store.isRoot = (compileState->root == valueTypeProperty->parent);
3441 store.property = prop->index;
3442 store.isRoot = (compileState->root == obj);
3444 store.line = binding->location.start.line;
3445 store.column = binding->location.start.column;
3446 output->addInstruction(store);
3447 } else if (ref.dataType == BindingReference::V8) {
3448 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3450 Instruction::StoreV8Binding store;
3451 store.value = js.compiledIndex;
3452 store.context = js.bindingContext.stack;
3453 store.owner = js.bindingContext.owner;
3454 if (valueTypeProperty) {
3455 store.isRoot = (compileState->root == valueTypeProperty->parent);
3457 store.isRoot = (compileState->root == obj);
3459 store.line = binding->location.start.line;
3460 store.column = binding->location.start.column;
3462 Q_ASSERT(js.bindingContext.owner == 0 ||
3463 (js.bindingContext.owner != 0 && valueTypeProperty));
3464 if (js.bindingContext.owner) {
3465 store.property = genValueTypeData(prop, valueTypeProperty);
3467 store.property = prop->core;
3470 output->addInstruction(store);
3471 } else if (ref.dataType == BindingReference::QtScript) {
3472 const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3474 QDeclarativeInstruction store;
3475 store.assignBinding.value = output->indexForString(js.rewrittenExpression);
3476 store.assignBinding.context = js.bindingContext.stack;
3477 store.assignBinding.owner = js.bindingContext.owner;
3478 store.assignBinding.line = binding->location.start.line;
3479 store.assignBinding.column = binding->location.start.column;
3481 if (valueTypeProperty) {
3482 store.assignBinding.isRoot = (compileState->root == valueTypeProperty->parent);
3484 store.assignBinding.isRoot = (compileState->root == obj);
3487 Q_ASSERT(js.bindingContext.owner == 0 ||
3488 (js.bindingContext.owner != 0 && valueTypeProperty));
3489 if (js.bindingContext.owner) {
3490 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
3492 store.assignBinding.property = prop->core;
3494 output->addInstructionHelper(
3495 !prop->isAlias ? QDeclarativeInstruction::StoreBinding
3496 : QDeclarativeInstruction::StoreBindingOnAlias
3499 Q_ASSERT(!"Unhandled BindingReference::DataType type");
3503 int QDeclarativeCompiler::genContextCache()
3505 if (compileState->ids.count() == 0)
3508 QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache();
3509 cache->reserve(compileState->ids.count());
3510 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
3511 cache->add(o->id, o->idIndex);
3513 output->contextCaches.append(cache);
3514 return output->contextCaches.count() - 1;
3517 QDeclarativePropertyData
3518 QDeclarativeCompiler::genValueTypeData(QDeclarativeScript::Property *valueTypeProp,
3519 QDeclarativeScript::Property *prop)
3521 typedef QDeclarativePropertyPrivate QDPP;
3522 return QDPP::saveValueType(prop->parent->metaObject(), prop->index,
3523 enginePrivate->valueTypes[prop->type]->metaObject(),
3524 valueTypeProp->index, engine);
3527 bool QDeclarativeCompiler::completeComponentBuild()
3530 componentStats->componentStat.ids = compileState->ids.count();
3532 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
3533 aliasObject = compileState->aliasingObjects.next(aliasObject))
3534 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
3536 QV4Compiler::Expression expr(unit->imports());
3537 expr.component = compileState->root;
3538 expr.ids = &compileState->ids;
3539 expr.importCache = output->importCache;
3541 QV4Compiler bindingCompiler;
3543 QList<JSBindingReference*> sharedBindings;
3545 for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3547 JSBindingReference &binding = *b;
3549 // ### We don't currently optimize for bindings on alias's - because
3550 // of the solution to QTBUG-13719
3551 if (!binding.property->isAlias) {
3552 expr.context = binding.bindingContext.object;
3553 expr.property = binding.property;
3554 expr.expression = binding.expression;
3556 int index = bindingCompiler.compile(expr, enginePrivate);
3558 binding.dataType = BindingReference::V4;
3559 binding.compiledIndex = index;
3561 componentStats->componentStat.optimizedBindings.append(b->value->location);
3566 // Pre-rewrite the expression
3567 QString expression = binding.expression.asScript();
3569 QDeclarativeRewrite::RewriteBinding rewriteBinding;
3570 rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3571 bool isSharable = false;
3572 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3574 if (isSharable && !binding.property->isAlias /* See above re alias */ &&
3575 binding.property->type != qMetaTypeId<QDeclarativeBinding*>()) {
3576 binding.dataType = BindingReference::V8;
3577 sharedBindings.append(b);
3579 binding.dataType = BindingReference::QtScript;
3583 componentStats->componentStat.scriptBindings.append(b->value->location);
3586 if (!sharedBindings.isEmpty()) {
3588 static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs)
3590 return lhs->value->location.start.line < rhs->value->location.start.line;
3594 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3596 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3597 int lineNumber = startLineNumber;
3599 QString functionArray(QLatin1String("["));
3600 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3601 JSBindingReference *reference = sharedBindings.at(ii);
3602 QDeclarativeScript::Value *value = reference->value;
3603 const QString &expression = reference->rewrittenExpression;
3605 if (ii != 0) functionArray += QLatin1String(",");
3607 while (lineNumber < value->location.start.line) {
3609 functionArray += QLatin1String("\n");
3612 functionArray += expression;
3613 lineNumber += expression.count(QLatin1Char('\n'));
3614 reference->compiledIndex = ii;
3616 functionArray += QLatin1String("]");
3618 compileState->v8BindingProgram = functionArray;
3619 compileState->v8BindingProgramLine = startLineNumber;
3620 compileState->v8BindingProgramIndex = output->v8bindings.count();
3621 output->v8bindings.append(v8::Persistent<v8::Array>());
3624 if (bindingCompiler.isValid())
3625 compileState->compiledBindingData = bindingCompiler.program();
3627 // Check pop()'s matched push()'s
3628 Q_ASSERT(compileState->objectDepth.depth() == 0);
3629 Q_ASSERT(compileState->listDepth.depth() == 0);
3631 saveComponentState();
3636 void QDeclarativeCompiler::dumpStats()
3638 Q_ASSERT(componentStats);
3639 qWarning().nospace() << "QML Document: " << output->url.toString();
3640 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3641 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3642 qWarning().nospace() << " Component Line " << stat.lineNumber;
3643 qWarning().nospace() << " Total Objects: " << stat.objects;
3644 qWarning().nospace() << " IDs Used: " << stat.ids;
3645 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3649 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3650 if (0 == (ii % 10)) {
3651 if (ii) output.append("\n");
3656 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3658 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3659 output.append(") ");
3661 if (!output.isEmpty())
3662 qWarning().nospace() << output.constData();
3665 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3668 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3669 if (0 == (ii % 10)) {
3670 if (ii) output.append("\n");
3675 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3677 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3678 output.append(") ");
3680 if (!output.isEmpty())
3681 qWarning().nospace() << output.constData();
3687 Returns true if from can be assigned to a (QObject) property of type
3690 bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeScript::Object *from)
3692 const QMetaObject *toMo = enginePrivate->rawMetaObjectForType(to);
3693 const QMetaObject *fromMo = from->metaObject();
3696 if (QDeclarativePropertyPrivate::equal(fromMo, toMo))
3698 fromMo = fromMo->superClass();
3704 Returns the element name, as written in the QML file, for o.
3706 QString QDeclarativeCompiler::elementName(QDeclarativeScript::Object *o)
3709 if (o->type != -1) {
3710 return output->types.at(o->type).className;
3716 QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeScript::Object *from)
3719 const QMetaObject *mo = from->metatype;
3720 QDeclarativeType *type = 0;
3721 while (!type && mo) {
3722 type = QDeclarativeMetaType::qmlType(mo);
3723 mo = mo->superClass();
3728 QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeScript::Object *obj)
3730 const QMetaObject *mo = obj->metatype;
3732 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3734 return QStringList();
3736 QMetaClassInfo classInfo = mo->classInfo(idx);
3737 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3741 QDeclarativePropertyData *
3742 QDeclarativeCompiler::property(QDeclarativeScript::Object *object, int index)
3744 QDeclarativePropertyCache *cache = 0;
3746 if (object->synthCache)
3747 cache = object->synthCache;
3748 else if (object->type != -1)
3749 cache = output->types[object->type].createPropertyCache(engine);
3751 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3753 return cache->property(index);
3756 QDeclarativePropertyData *
3757 QDeclarativeCompiler::property(QDeclarativeScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3759 if (notInRevision) *notInRevision = false;
3761 QDeclarativePropertyCache *cache = 0;
3763 if (object->synthCache)
3764 cache = object->synthCache;
3765 else if (object->type != -1)
3766 cache = output->types[object->type].createPropertyCache(engine);
3768 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3770 QDeclarativePropertyData *d = cache->property(name);
3772 // Find the first property
3773 while (d && d->isFunction())
3774 d = cache->overrideData(d);
3776 if (d && !cache->isAllowedInRevision(d)) {
3777 if (notInRevision) *notInRevision = true;
3784 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3785 QDeclarativePropertyData *
3786 QDeclarativeCompiler::signal(QDeclarativeScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3788 if (notInRevision) *notInRevision = false;
3790 QDeclarativePropertyCache *cache = 0;
3792 if (object->synthCache)
3793 cache = object->synthCache;
3794 else if (object->type != -1)
3795 cache = output->types[object->type].createPropertyCache(engine);
3797 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3800 QDeclarativePropertyData *d = cache->property(name);
3801 if (notInRevision) *notInRevision = false;
3803 while (d && !(d->isFunction()))
3804 d = cache->overrideData(d);
3806 if (d && !cache->isAllowedInRevision(d)) {
3807 if (notInRevision) *notInRevision = true;
3813 if (name.endsWith(Changed_string)) {
3814 QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3816 d = property(object, propName, notInRevision);
3818 return cache->method(d->notifyIndex);
3824 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3825 int QDeclarativeCompiler::indexOfSignal(QDeclarativeScript::Object *object, const QString &name,
3826 bool *notInRevision)
3828 QDeclarativePropertyData *d = signal(object, QStringRef(&name), notInRevision);
3829 return d?d->coreIndex:-1;
3832 int QDeclarativeCompiler::indexOfProperty(QDeclarativeScript::Object *object, const QString &name,
3833 bool *notInRevision)
3835 return indexOfProperty(object, QStringRef(&name), notInRevision);
3838 int QDeclarativeCompiler::indexOfProperty(QDeclarativeScript::Object *object, const QHashedStringRef &name,
3839 bool *notInRevision)
3841 QDeclarativePropertyData *d = property(object, name, notInRevision);
3842 return d?d->coreIndex:-1;