Merge master into api_changes
[profile/ivi/qtdeclarative.git] / src / qml / qml / qqmlcompiler.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qqmlcompiler_p.h"
43
44 #include "qqmlpropertyvaluesource.h"
45 #include "qqmlcomponent.h"
46 #include <private/qmetaobjectbuilder_p.h>
47 #include <private/qfastmetabuilder_p.h>
48 #include "qqmlstringconverters_p.h"
49 #include "qqmlengine_p.h"
50 #include "qqmlengine.h"
51 #include "qqmlcontext.h"
52 #include "qqmlmetatype_p.h"
53 #include "qqmlcustomparser_p_p.h"
54 #include "qqmlcontext_p.h"
55 #include "qqmlcomponent_p.h"
56 #include <private/qqmljsast_p.h>
57 #include "qqmlvmemetaobject_p.h"
58 #include "qqmlexpression_p.h"
59 #include "qqmlproperty_p.h"
60 #include "qqmlrewrite_p.h"
61 #include "qqmlscriptstring.h"
62 #include "qqmlglobal_p.h"
63 #include "qqmlbinding_p.h"
64 #include <private/qv4compiler_p.h>
65
66 #include <QColor>
67 #include <QDebug>
68 #include <QPointF>
69 #include <QSizeF>
70 #include <QRectF>
71 #include <QAtomicInt>
72 #include <QtCore/qdebug.h>
73 #include <QtCore/qdatetime.h>
74 #include <QtCore/qvarlengtharray.h>
75
76 Q_DECLARE_METATYPE(QList<int>)
77 Q_DECLARE_METATYPE(QList<qreal>)
78 Q_DECLARE_METATYPE(QList<bool>)
79 Q_DECLARE_METATYPE(QList<QString>)
80 Q_DECLARE_METATYPE(QList<QUrl>)
81
82 QT_BEGIN_NAMESPACE
83
84 DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP);
85 DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS);
86
87 using namespace QQmlJS;
88 using namespace QQmlScript;
89 using namespace QQmlCompilerTypes;
90
91 static QString id_string(QLatin1String("id"));
92 static QString on_string(QLatin1String("on"));
93 static QString Changed_string(QLatin1String("Changed"));
94 static QString Component_string(QLatin1String("Component"));
95 static QString Component_import_string(QLatin1String("QML/Component"));
96 static QString qsTr_string(QLatin1String("qsTr"));
97 static QString qsTrId_string(QLatin1String("qsTrId"));
98
99 /*!
100     Instantiate a new QQmlCompiler.
101 */
102 QQmlCompiler::QQmlCompiler(QQmlPool *pool)
103 : pool(pool), output(0), engine(0), unitRoot(0), unit(0), cachedComponentTypeRef(-1),
104   cachedTranslationContextIndex(-1), componentStats(0)
105 {
106     if (compilerStatDump()) 
107         componentStats = pool->New<ComponentStats>();
108 }
109
110 /*!
111     Returns true if the last call to compile() caused errors.
112
113     \sa errors()
114 */
115 bool QQmlCompiler::isError() const
116 {
117     return !exceptions.isEmpty();
118 }
119
120 /*!
121     Return the list of errors from the last call to compile(), or an empty list
122     if there were no errors.
123 */
124 QList<QQmlError> QQmlCompiler::errors() const
125 {
126     return exceptions;
127 }
128
129 /*!
130     Returns true if \a name refers to an attached property, false otherwise.
131
132     Attached property names are those that start with a capital letter.
133 */
134 bool QQmlCompiler::isAttachedPropertyName(const QString &name)
135 {
136     return isAttachedPropertyName(QHashedStringRef(&name));
137 }
138
139 bool QQmlCompiler::isAttachedPropertyName(const QHashedStringRef &name)
140 {
141     return !name.isEmpty() && name.at(0).isUpper();
142 }
143
144 /*!
145     Returns true if \a name refers to a signal property, false otherwise.
146
147     Signal property names are those that start with "on", followed by a first
148     character which is either a capital letter or one or more underscores followed
149     by a capital letter, which is then followed by other allowed characters.
150
151     Note that although ECMA-262r3 supports dollarsigns and escaped unicode
152     character codes in property names, for simplicity and performance reasons
153     QML only supports letters, numbers and underscores.
154 */
155 bool QQmlCompiler::isSignalPropertyName(const QString &name)
156 {
157     return isSignalPropertyName(QStringRef(&name));
158 }
159
160 bool QQmlCompiler::isSignalPropertyName(const QHashedStringRef &name)
161 {
162     if (name.length() < 3) return false;
163     if (!name.startsWith(on_string)) return false;
164     int ns = name.length();
165     for (int i = 2; i < ns; ++i) {
166         const QChar curr = name.at(i);
167         if (curr.unicode() == '_') continue;
168         if (curr.isUpper()) return true;
169         return false;
170     }
171     return false; // consists solely of underscores - invalid.
172 }
173
174 /*!
175     \macro COMPILE_EXCEPTION
176     \internal
177     Inserts an error into the QQmlCompiler error list, and returns false
178     (failure).
179
180     \a token is used to source the error line and column, and \a desc is the
181     error itself.  \a desc can be an expression that can be piped into QDebug.
182
183     For example:
184
185     \code
186     COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(property->name));
187     \endcode
188 */
189 #define COMPILE_EXCEPTION_LOCATION(line, column, desc) \
190     {  \
191         QQmlError error; \
192         error.setUrl(output->url); \
193         error.setLine(line); \
194         error.setColumn(column); \
195         error.setDescription(desc.trimmed()); \
196         exceptions << error; \
197         return false; \
198     }
199
200 #define COMPILE_EXCEPTION(token, desc) \
201     COMPILE_EXCEPTION_LOCATION((token)->location.start.line, (token)->location.start.column, desc)
202
203 /*!
204     \macro COMPILE_CHECK
205     \internal
206     Returns false if \a is false, otherwise does nothing.
207 */
208 #define COMPILE_CHECK(a) \
209     { \
210         if (!a) return false; \
211     }
212
213 /*!
214     Returns true if literal \a v can be assigned to property \a prop, otherwise
215     false.
216
217     This test corresponds to action taken by genLiteralAssignment().  Any change
218     made here, must have a corresponding action in genLiteralAssigment().
219 */
220 bool QQmlCompiler::testLiteralAssignment(QQmlScript::Property *prop,
221                                                  QQmlScript::Value *v)
222 {
223     const QQmlScript::Variant &value = v->value;
224
225     if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
226         COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
227
228     if (prop->core.isEnum()) {
229         QMetaProperty p = prop->parent->metaObject()->property(prop->index);
230         int enumValue;
231         bool ok;
232         if (p.isFlagType()) {
233             enumValue = p.enumerator().keysToValue(value.asString().toUtf8().constData(), &ok);
234         } else
235             enumValue = p.enumerator().keyToValue(value.asString().toUtf8().constData(), &ok);
236
237         if (!ok)
238             COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration"));
239
240         v->value = QQmlScript::Variant((double)enumValue);
241         return true;
242     }
243
244     int type = prop->type;
245
246     switch(type) {
247         case QMetaType::QVariant:
248             break;
249         case QVariant::String:
250             if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
251             break;
252         case QVariant::StringList: // we expect a string literal.  A string list is not a literal assignment.
253             if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or string list expected"));
254             break;
255         case QVariant::ByteArray:
256             if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected"));
257             break;
258         case QVariant::Url:
259             if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected"));
260             break;
261         case QVariant::RegExp:
262             COMPILE_EXCEPTION(v, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax"));
263             break;
264         case QVariant::UInt:
265             {
266             bool ok = v->value.isNumber();
267             if (ok) {
268                 double n = v->value.asNumber();
269                 if (double(uint(n)) != n)
270                     ok = false;
271             }
272             if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected"));
273             }
274             break;
275         case QVariant::Int:
276             {
277             bool ok = v->value.isNumber();
278             if (ok) {
279                 double n = v->value.asNumber();
280                 if (double(int(n)) != n)
281                     ok = false;
282             }
283             if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected"));
284             }
285             break;
286         case QMetaType::Float:
287             if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
288             break;
289         case QVariant::Double:
290             if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
291             break;
292         case QVariant::Color:
293             {
294             bool ok;
295             QQmlStringConverters::colorFromString(value.asString(), &ok);
296             if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected"));
297             }
298             break;
299 #ifndef QT_NO_DATESTRING
300         case QVariant::Date:
301             {
302             bool ok;
303             QQmlStringConverters::dateFromString(value.asString(), &ok);
304             if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected"));
305             }
306             break;
307         case QVariant::Time:
308             {
309             bool ok;
310             QQmlStringConverters::timeFromString(value.asString(), &ok);
311             if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected"));
312             }
313             break;
314         case QVariant::DateTime:
315             {
316             bool ok;
317             QQmlStringConverters::dateTimeFromString(value.asString(), &ok);
318             if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected"));
319             }
320             break;
321 #endif // QT_NO_DATESTRING
322         case QVariant::Point:
323         case QVariant::PointF:
324             {
325             bool ok;
326             QQmlStringConverters::pointFFromString(value.asString(), &ok);
327             if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected"));
328             }
329             break;
330         case QVariant::Size:
331         case QVariant::SizeF:
332             {
333             bool ok;
334             QQmlStringConverters::sizeFFromString(value.asString(), &ok);
335             if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected"));
336             }
337             break;
338         case QVariant::Rect:
339         case QVariant::RectF:
340             {
341             bool ok;
342             QQmlStringConverters::rectFFromString(value.asString(), &ok);
343             if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected"));
344             }
345             break;
346         case QVariant::Bool:
347             {
348             if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected"));
349             }
350             break;
351         case QVariant::Vector3D:
352             {
353             bool ok;
354             QQmlStringConverters::vector3DFromString(value.asString(), &ok);
355             if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected"));
356             }
357             break;
358         case QVariant::Vector4D:
359             {
360             bool ok;
361             QQmlStringConverters::vector4DFromString(value.asString(), &ok);
362             if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 4D vector expected"));
363             }
364             break;
365         default:
366             {
367             // check if assigning a literal value to a list property.
368             // in each case, check the singular, since an Array of the specified type
369             // will not go via this literal assignment codepath.
370             if (type == qMetaTypeId<QList<qreal> >()) {
371                 if (!v->value.isNumber()) {
372                     COMPILE_EXCEPTION(v, tr("Invalid property assignment: real or array of reals expected"));
373                 }
374                 break;
375             } else if (type == qMetaTypeId<QList<int> >()) {
376                 bool ok = v->value.isNumber();
377                 if (ok) {
378                     double n = v->value.asNumber();
379                     if (double(int(n)) != n)
380                         ok = false;
381                 }
382                 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int or array of ints expected"));
383                 break;
384             } else if (type == qMetaTypeId<QList<bool> >()) {
385                 if (!v->value.isBoolean()) {
386                     COMPILE_EXCEPTION(v, tr("Invalid property assignment: bool or array of bools expected"));
387                 }
388                 break;
389             } else if (type == qMetaTypeId<QList<QString> >()) { // we expect a string literal.  A string list is not a literal assignment.
390                 if (!v->value.isString()) {
391                     COMPILE_EXCEPTION(v, tr("Invalid property assignment: string or array of strings expected"));
392                 }
393                 break;
394             } else if (type == qMetaTypeId<QList<QUrl> >()) {
395                 if (!v->value.isString()) {
396                     COMPILE_EXCEPTION(v, tr("Invalid property assignment: url or array of urls expected"));
397                 }
398                 break;
399             }
400
401             // otherwise, check for existence of string converter to custom type
402             QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(type);
403             if (!converter)
404                 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName((QVariant::Type)type))));
405             }
406             break;
407     }
408     return true;
409 }
410
411 static QUrl urlFromUserString(const QString &data)
412 {
413     QUrl u;
414     // Preserve any valid percent-encoded octets supplied by the source
415     u.setEncodedUrl(data.toUtf8(), QUrl::TolerantMode);
416     return u;
417 }
418
419 /*!
420     Generate a store instruction for assigning literal \a v to property \a prop.
421
422     Any literal assignment that is approved in testLiteralAssignment() must have
423     a corresponding action in this method.
424 */
425 void QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop,
426                                                 QQmlScript::Value *v)
427 {
428     if (prop->core.isEnum()) {
429         Q_ASSERT(v->value.isNumber());
430         // Preresolved value
431         int value = (int)v->value.asNumber();
432
433         Instruction::StoreInteger instr;
434         instr.propertyIndex = prop->index;
435         instr.value = value;
436         output->addInstruction(instr);
437         return;
438     }
439
440     int type = prop->type;
441     switch(type) {
442         case QMetaType::QVariant:
443             {
444             if (v->value.isNumber()) {
445                 double n = v->value.asNumber();
446                 if (double(int(n)) == n) {
447                     if (prop->core.isVMEProperty()) {
448                         Instruction::StoreVarInteger instr;
449                         instr.propertyIndex = prop->index;
450                         instr.value = int(n);
451                         output->addInstruction(instr);
452                     } else {
453                         Instruction::StoreVariantInteger instr;
454                         instr.propertyIndex = prop->index;
455                         instr.value = int(n);
456                         output->addInstruction(instr);
457                     }
458                 } else {
459                     if (prop->core.isVMEProperty()) {
460                         Instruction::StoreVarDouble instr;
461                         instr.propertyIndex = prop->index;
462                         instr.value = n;
463                         output->addInstruction(instr);
464                     } else {
465                         Instruction::StoreVariantDouble instr;
466                         instr.propertyIndex = prop->index;
467                         instr.value = n;
468                         output->addInstruction(instr);
469                     }
470                 }
471             } else if (v->value.isBoolean()) {
472                 if (prop->core.isVMEProperty()) {
473                     Instruction::StoreVarBool instr;
474                     instr.propertyIndex = prop->index;
475                     instr.value = v->value.asBoolean();
476                     output->addInstruction(instr);
477                 } else {
478                     Instruction::StoreVariantBool instr;
479                     instr.propertyIndex = prop->index;
480                     instr.value = v->value.asBoolean();
481                     output->addInstruction(instr);
482                 }
483             } else {
484                 if (prop->core.isVMEProperty()) {
485                     Instruction::StoreVar instr;
486                     instr.propertyIndex = prop->index;
487                     instr.value = output->indexForString(v->value.asString());
488                     output->addInstruction(instr);
489                 } else {
490                     Instruction::StoreVariant instr;
491                     instr.propertyIndex = prop->index;
492                     instr.value = output->indexForString(v->value.asString());
493                     output->addInstruction(instr);
494                 }
495             }
496             }
497             break;
498         case QVariant::String:
499             {
500             Instruction::StoreString instr;
501             instr.propertyIndex = prop->index;
502             instr.value = output->indexForString(v->value.asString());
503             output->addInstruction(instr);
504             }
505             break;
506         case QVariant::StringList:
507             {
508             Instruction::StoreStringList instr;
509             instr.propertyIndex = prop->index;
510             instr.value = output->indexForString(v->value.asString());
511             output->addInstruction(instr);
512             }
513             break;
514         case QVariant::ByteArray:
515             {
516             Instruction::StoreByteArray instr;
517             instr.propertyIndex = prop->index;
518             instr.value = output->indexForByteArray(v->value.asString().toLatin1());
519             output->addInstruction(instr);
520             }
521             break;
522         case QVariant::Url:
523             {
524             Instruction::StoreUrl instr;
525             QString string = v->value.asString();
526             QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(urlFromUserString(string));
527             instr.propertyIndex = prop->index;
528             instr.value = output->indexForUrl(u);
529             output->addInstruction(instr);
530             }
531             break;
532         case QVariant::UInt:
533             {
534             Instruction::StoreInteger instr;
535             instr.propertyIndex = prop->index;
536             instr.value = uint(v->value.asNumber());
537             output->addInstruction(instr);
538             }
539             break;
540         case QVariant::Int:
541             {
542             Instruction::StoreInteger instr;
543             instr.propertyIndex = prop->index;
544             instr.value = int(v->value.asNumber());
545             output->addInstruction(instr);
546             }
547             break;
548         case QMetaType::Float:
549             {
550             Instruction::StoreFloat instr;
551             instr.propertyIndex = prop->index;
552             instr.value = float(v->value.asNumber());
553             output->addInstruction(instr);
554             }
555             break;
556         case QVariant::Double:
557             {
558             Instruction::StoreDouble instr;
559             instr.propertyIndex = prop->index;
560             instr.value = v->value.asNumber();
561             output->addInstruction(instr);
562             }
563             break;
564         case QVariant::Color:
565             {
566             Instruction::StoreColor instr;
567             QColor c = QQmlStringConverters::colorFromString(v->value.asString());
568             instr.propertyIndex = prop->index;
569             instr.value = c.rgba();
570             output->addInstruction(instr);
571             }
572             break;
573 #ifndef QT_NO_DATESTRING
574         case QVariant::Date:
575             {
576             Instruction::StoreDate instr;
577             QDate d = QQmlStringConverters::dateFromString(v->value.asString());
578             instr.propertyIndex = prop->index;
579             instr.value = d.toJulianDay();
580             output->addInstruction(instr);
581             }
582             break;
583         case QVariant::Time:
584             {
585             Instruction::StoreTime instr;
586             QTime time = QQmlStringConverters::timeFromString(v->value.asString());
587             instr.propertyIndex = prop->index;
588             Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
589             ::memcpy(&instr.time, &time, sizeof(QTime));
590             output->addInstruction(instr);
591             }
592             break;
593         case QVariant::DateTime:
594             {
595             Instruction::StoreDateTime instr;
596             QDateTime dateTime = QQmlStringConverters::dateTimeFromString(v->value.asString());
597             QTime time = dateTime.time();
598             instr.propertyIndex = prop->index;
599             instr.date = dateTime.date().toJulianDay();
600             Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
601             ::memcpy(&instr.time, &time, sizeof(QTime));
602             output->addInstruction(instr);
603             }
604             break;
605 #endif // QT_NO_DATESTRING
606         case QVariant::Point:
607             {
608             Instruction::StorePoint instr;
609             bool ok;
610             QPoint point = QQmlStringConverters::pointFFromString(v->value.asString(), &ok).toPoint();
611             instr.propertyIndex = prop->index;
612             instr.point.xp = point.x();
613             instr.point.yp = point.y();
614             output->addInstruction(instr);
615             }
616             break;
617         case QVariant::PointF:
618             {
619             Instruction::StorePointF instr;
620             bool ok;
621             QPointF point = QQmlStringConverters::pointFFromString(v->value.asString(), &ok);
622             instr.propertyIndex = prop->index;
623             instr.point.xp = point.x();
624             instr.point.yp = point.y();
625             output->addInstruction(instr);
626             }
627             break;
628         case QVariant::Size:
629             {
630             Instruction::StoreSize instr;
631             bool ok;
632             QSize size = QQmlStringConverters::sizeFFromString(v->value.asString(), &ok).toSize();
633             instr.propertyIndex = prop->index;
634             instr.size.wd = size.width();
635             instr.size.ht = size.height();
636             output->addInstruction(instr);
637             }
638             break;
639         case QVariant::SizeF:
640             {
641             Instruction::StoreSizeF instr;
642             bool ok;
643             QSizeF size = QQmlStringConverters::sizeFFromString(v->value.asString(), &ok);
644             instr.propertyIndex = prop->index;
645             instr.size.wd = size.width();
646             instr.size.ht = size.height();
647             output->addInstruction(instr);
648             }
649             break;
650         case QVariant::Rect:
651             {
652             Instruction::StoreRect instr;
653             bool ok;
654             QRect rect = QQmlStringConverters::rectFFromString(v->value.asString(), &ok).toRect();
655             instr.propertyIndex = prop->index;
656             instr.rect.x1 = rect.left();
657             instr.rect.y1 = rect.top();
658             instr.rect.x2 = rect.right();
659             instr.rect.y2 = rect.bottom();
660             output->addInstruction(instr);
661             }
662             break;
663         case QVariant::RectF:
664             {
665             Instruction::StoreRectF instr;
666             bool ok;
667             QRectF rect = QQmlStringConverters::rectFFromString(v->value.asString(), &ok);
668             instr.propertyIndex = prop->index;
669             instr.rect.xp = rect.left();
670             instr.rect.yp = rect.top();
671             instr.rect.w = rect.width();
672             instr.rect.h = rect.height();
673             output->addInstruction(instr);
674             }
675             break;
676         case QVariant::Bool:
677             {
678             Instruction::StoreBool instr;
679             bool b = v->value.asBoolean();
680             instr.propertyIndex = prop->index;
681             instr.value = b;
682             output->addInstruction(instr);
683             }
684             break;
685         case QVariant::Vector3D:
686             {
687             Instruction::StoreVector3D instr;
688             bool ok;
689             QVector3D vector = QQmlStringConverters::vector3DFromString(v->value.asString(), &ok);
690             instr.propertyIndex = prop->index;
691             instr.vector.xp = vector.x();
692             instr.vector.yp = vector.y();
693             instr.vector.zp = vector.z();
694             output->addInstruction(instr);
695             }
696             break;
697     case QVariant::Vector4D:
698             {
699             Instruction::StoreVector4D instr;
700             bool ok;
701             QVector4D vector = QQmlStringConverters::vector4DFromString(v->value.asString(), &ok);
702             instr.propertyIndex = prop->index;
703             instr.vector.xp = vector.x();
704             instr.vector.yp = vector.y();
705             instr.vector.zp = vector.z();
706             instr.vector.wp = vector.w();
707             output->addInstruction(instr);
708             }
709             break;
710         default:
711             {
712             // generate single literal value assignment to a list property if required
713             if (type == qMetaTypeId<QList<qreal> >()) {
714                 Instruction::StoreDoubleQList instr;
715                 instr.propertyIndex = prop->index;
716                 instr.value = v->value.asNumber();
717                 output->addInstruction(instr);
718                 break;
719             } else if (type == qMetaTypeId<QList<int> >()) {
720                 Instruction::StoreIntegerQList instr;
721                 instr.propertyIndex = prop->index;
722                 instr.value = int(v->value.asNumber());
723                 output->addInstruction(instr);
724                 break;
725             } else if (type == qMetaTypeId<QList<bool> >()) {
726                 Instruction::StoreBoolQList instr;
727                 bool b = v->value.asBoolean();
728                 instr.propertyIndex = prop->index;
729                 instr.value = b;
730                 output->addInstruction(instr);
731                 break;
732             } else if (type == qMetaTypeId<QList<QUrl> >()) {
733                 Instruction::StoreUrlQList instr;
734                 QString string = v->value.asString();
735                 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(urlFromUserString(string));
736                 instr.propertyIndex = prop->index;
737                 instr.value = output->indexForUrl(u);
738                 output->addInstruction(instr);
739                 break;
740             } else if (type == qMetaTypeId<QList<QString> >()) {
741                 Instruction::StoreStringQList instr;
742                 instr.propertyIndex = prop->index;
743                 instr.value = output->indexForString(v->value.asString());
744                 output->addInstruction(instr);
745                 break;
746             }
747
748             // otherwise, generate custom type literal assignment
749             Instruction::AssignCustomType instr;
750             instr.propertyIndex = prop->index;
751             instr.primitive = output->indexForString(v->value.asString());
752             instr.type = type;
753             output->addInstruction(instr);
754             }
755             break;
756     }
757 }
758
759 /*!
760     Resets data by clearing the lists that the QQmlCompiler modifies.
761 */
762 void QQmlCompiler::reset(QQmlCompiledData *data)
763 {
764     data->types.clear();
765     data->primitives.clear();
766     data->datas.clear();
767     data->bytecode.resize(0);
768 }
769
770 /*!
771     Compile \a unit, and store the output in \a out.  \a engine is the QQmlEngine
772     with which the QQmlCompiledData will be associated.
773
774     Returns true on success, false on failure.  On failure, the compile errors
775     are available from errors().
776
777     If the environment variant QML_COMPILER_DUMP is set
778     (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
779     on a successful compiler.
780 */
781 bool QQmlCompiler::compile(QQmlEngine *engine,
782                                    QQmlTypeData *unit,
783                                    QQmlCompiledData *out)
784 {
785     exceptions.clear();
786
787     Q_ASSERT(out);
788     reset(out);
789
790     QQmlScript::Object *root = unit->parser().tree();
791     Q_ASSERT(root);
792
793     this->engine = engine;
794     this->enginePrivate = QQmlEnginePrivate::get(engine);
795     this->unit = unit;
796     this->unitRoot = root;
797     this->output = out;
798
799     // Compile types
800     const QList<QQmlTypeData::TypeReference>  &resolvedTypes = unit->resolvedTypes();
801     QList<QQmlScript::TypeReference *> referencedTypes = unit->parser().referencedTypes();
802
803     for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
804         QQmlCompiledData::TypeReference ref;
805
806         const QQmlTypeData::TypeReference &tref = resolvedTypes.at(ii);
807         QQmlScript::TypeReference *parserRef = referencedTypes.at(ii);
808
809         if (tref.type) {
810             ref.type = tref.type;
811             if (!ref.type->isCreatable()) {
812                 QString err = ref.type->noCreationReason();
813                 if (err.isEmpty())
814                     err = tr( "Element is not creatable.");
815                 COMPILE_EXCEPTION(parserRef->refObjects.first(), err);
816             }
817             
818             if (ref.type->containsRevisionedAttributes()) {
819                 QQmlError cacheError;
820                 ref.typePropertyCache = enginePrivate->cache(ref.type, resolvedTypes.at(ii).minorVersion, 
821                                                              cacheError);
822                 if (!ref.typePropertyCache) 
823                     COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description());
824                 ref.typePropertyCache->addref();
825             }
826
827         } else if (tref.typeData) {
828             ref.component = tref.typeData->compiledData();
829         }
830         ref.className = parserRef->name;
831         out->types << ref;
832     }
833
834     compileTree(root);
835
836     if (!isError()) {
837         if (compilerDump())
838             out->dumpInstructions();
839         if (componentStats)
840             dumpStats();
841         Q_ASSERT(out->rootPropertyCache);
842     } else {
843         reset(out);
844     }
845
846     compileState = 0;
847     output = 0;
848     this->engine = 0;
849     this->enginePrivate = 0;
850     this->unit = 0;
851     this->cachedComponentTypeRef = -1;
852     this->cachedTranslationContextIndex = -1;
853     this->unitRoot = 0;
854
855     return !isError();
856 }
857
858 void QQmlCompiler::compileTree(QQmlScript::Object *tree)
859 {
860     compileState = pool->New<ComponentCompileState>();
861
862     compileState->root = tree;
863     if (componentStats)
864         componentStats->componentStat.lineNumber = tree->location.start.line;
865
866     // We generate the importCache before we build the tree so that
867     // it can be used in the binding compiler.  Given we "expect" the
868     // QML compilation to succeed, this isn't a waste.
869     output->importCache = new QQmlTypeNameCache();
870     foreach (const QString &ns, unit->namespaces()) {
871         output->importCache->add(ns);
872     }
873
874     int scriptIndex = 0;
875     foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
876         QString qualifier = script.qualifier;
877         QString enclosingNamespace;
878
879         const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
880         if (lastDotIndex != -1) {
881             enclosingNamespace = qualifier.left(lastDotIndex);
882             qualifier = qualifier.mid(lastDotIndex+1);
883         }
884
885         output->importCache->add(qualifier, scriptIndex++, enclosingNamespace);
886     }
887
888     unit->imports().populateCache(output->importCache, engine);
889
890     if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
891         return;
892
893     Instruction::Init init;
894     init.bindingsSize = compileState->totalBindingsCount;
895     init.parserStatusSize = compileState->parserStatusCount;
896     init.contextCache = genContextCache();
897     init.objectStackSize = compileState->objectDepth.maxDepth();
898     init.listStackSize = compileState->listDepth.maxDepth();
899     if (compileState->compiledBindingData.isEmpty())
900         init.compiledBinding = -1;
901     else
902         init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
903     output->addInstruction(init);
904
905     foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
906         Instruction::StoreImportedScript import;
907         import.value = output->scripts.count();
908
909         QQmlScriptData *scriptData = script.script->scriptData();
910         scriptData->addref();
911         output->scripts << scriptData;
912         output->addInstruction(import);
913     }
914
915     if (!compileState->v8BindingProgram.isEmpty()) {
916         Instruction::InitV8Bindings bindings;
917         int index = output->programs.count();
918
919         typedef QQmlCompiledData::V8Program V8Program;
920         output->programs.append(V8Program(compileState->v8BindingProgram, output));
921
922         bindings.programIndex = index;
923         bindings.line = compileState->v8BindingProgramLine;
924         output->addInstruction(bindings);
925     }
926
927     genObject(tree);
928
929     Instruction::SetDefault def;
930     output->addInstruction(def);
931
932     Instruction::Done done;
933     output->addInstruction(done);
934
935     Q_ASSERT(tree->metatype);
936
937     if (tree->metadata.isEmpty()) {
938         output->root = tree->metatype;
939     } else {
940         static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
941         output->root = &output->rootData;
942     }
943     if (!tree->metadata.isEmpty()) 
944         enginePrivate->registerCompositeType(output);
945 }
946
947 static bool QStringList_contains(const QStringList &list, const QHashedStringRef &string)
948 {
949     for (int ii = 0; ii < list.count(); ++ii)
950         if (string == list.at(ii))
951             return true;
952
953     return false;
954 }
955
956 bool QQmlCompiler::buildObject(QQmlScript::Object *obj, const BindingContext &ctxt)
957 {
958     if (componentStats)
959         componentStats->componentStat.objects++;
960
961     Q_ASSERT (obj->type != -1);
962     const QQmlCompiledData::TypeReference &tr = output->types.at(obj->type);
963     obj->metatype = tr.metaObject();
964
965     if (tr.type) 
966         obj->typeName = tr.type->qmlTypeName();
967
968     // This object is a "Component" element
969     if (tr.type && obj->metatype == &QQmlComponent::staticMetaObject) {
970         COMPILE_CHECK(buildComponent(obj, ctxt));
971         return true;
972     } 
973
974     if (tr.component) {
975         typedef QQmlInstruction I; 
976         const I *init = ((const I *)tr.component->bytecode.constData());
977         Q_ASSERT(init && tr.component->instructionType(init) == QQmlInstruction::Init);
978  
979         // Adjust stack depths to include nested components
980         compileState->objectDepth.pushPop(init->init.objectStackSize);
981         compileState->listDepth.pushPop(init->init.listStackSize);
982         compileState->parserStatusCount += init->init.parserStatusSize;
983         compileState->totalBindingsCount += init->init.bindingsSize;
984     }
985
986     compileState->objectDepth.push();
987
988     // Object instantiations reset the binding context
989     BindingContext objCtxt(obj);
990
991     // Create the synthesized meta object, ignoring aliases
992     COMPILE_CHECK(checkDynamicMeta(obj)); 
993     COMPILE_CHECK(mergeDynamicMetaProperties(obj));
994     COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
995
996     // Find the native type and check for the QQmlParserStatus interface
997     QQmlType *type = toQmlType(obj);
998     Q_ASSERT(type);
999     obj->parserStatusCast = type->parserStatusCast();
1000     if (obj->parserStatusCast != -1)
1001         compileState->parserStatusCount++;
1002
1003     // Check if this is a custom parser type.  Custom parser types allow
1004     // assignments to non-existent properties.  These assignments are then
1005     // compiled by the type.
1006     bool isCustomParser = output->types.at(obj->type).type &&
1007                           output->types.at(obj->type).type->customParser() != 0;
1008     QList<QQmlCustomParserProperty> customProps;
1009
1010     // Fetch the list of deferred properties
1011     QStringList deferredList = deferredProperties(obj);
1012
1013     // Must do id property first.  This is to ensure that the id given to any
1014     // id reference created matches the order in which the objects are
1015     // instantiated
1016     for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1017         if (prop->name() == id_string) {
1018             COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1019             break;
1020         }
1021     }
1022
1023     // Merge 
1024     Property *defaultProperty = 0;
1025     Property *skipProperty = 0;
1026     if (obj->defaultProperty) {
1027         defaultProperty = obj->defaultProperty;
1028
1029         Property *explicitProperty = 0;
1030
1031         const QMetaObject *mo = obj->metatype;
1032         int idx = mo->indexOfClassInfo("DefaultProperty"); 
1033         if (idx != -1) {
1034             QMetaClassInfo info = mo->classInfo(idx);
1035             const char *p = info.value();
1036             if (p) {
1037                 int plen = 0;
1038                 char ord = 0;
1039                 while (char c = p[plen++]) { ord |= c; };
1040                 --plen;
1041
1042                 if (ord & 0x80) {
1043                     // Utf8 - unoptimal, but seldom hit
1044                     QString *s = pool->NewString(QString::fromUtf8(p, plen));
1045                     QHashedStringRef r(*s);
1046
1047                     if (obj->propertiesHashField.test(r.hash())) {
1048                         for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1049                             if (ep->name() == r) {
1050                                 explicitProperty = ep;
1051                                 break;
1052                             }
1053                         }
1054                     }
1055
1056                     if (!explicitProperty)
1057                         defaultProperty->setName(r);
1058
1059                 } else {
1060                     QHashedCStringRef r(p, plen); 
1061
1062                     if (obj->propertiesHashField.test(r.hash())) {
1063                         for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
1064                             if (ep->name() == r) {
1065                                 explicitProperty = ep;
1066                                 break;
1067                             }
1068                         }
1069                     }
1070
1071                     if (!explicitProperty) {
1072                         // Set the default property name
1073                         QChar *buffer = pool->NewRawArray<QChar>(r.length());
1074                         r.writeUtf16(buffer);
1075                         defaultProperty->setName(QHashedStringRef(buffer, r.length(), r.hash()));
1076                     }
1077                 }
1078             }
1079         }
1080
1081         if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) {
1082
1083             skipProperty = explicitProperty; // We merge the values into defaultProperty
1084
1085             // Find the correct insertion point
1086             Value *insertPos = 0;
1087
1088             for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) {
1089                 if (!(v->location.start < explicitProperty->values.first()->location.start))
1090                     break;
1091                 insertPos = v;
1092             }
1093
1094             defaultProperty->values.insertAfter(insertPos, explicitProperty->values);
1095         } 
1096     }
1097
1098     QQmlCustomParser *cp = 0;
1099     if (isCustomParser)
1100         cp = output->types.at(obj->type).type->customParser();
1101
1102     // Build all explicit properties specified
1103     for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1104
1105         if (prop == skipProperty)
1106             continue;
1107         if (prop->name() == id_string)
1108             continue;
1109
1110         bool canDefer = false;
1111         if (isCustomParser) {
1112             if (doesPropertyExist(prop, obj) &&
1113                 (!(cp->flags() & QQmlCustomParser::AcceptsAttachedProperties) ||
1114                  !isAttachedPropertyName(prop->name()))) {
1115                 int ids = compileState->ids.count();
1116                 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1117                 canDefer = ids == compileState->ids.count();
1118             } else if (isSignalPropertyName(prop->name()) &&
1119                     (cp->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
1120                 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1121             } else {
1122                 customProps << QQmlCustomParserNodePrivate::fromProperty(prop);
1123             }
1124         } else {
1125             if (isSignalPropertyName(prop->name())) {
1126                 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1127             } else {
1128                 int ids = compileState->ids.count();
1129                 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1130                 canDefer = ids == compileState->ids.count();
1131             }
1132         }
1133
1134         if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1135             prop->isDeferred = true;
1136
1137     }
1138
1139     // Build the default property
1140     if (defaultProperty)  {
1141         Property *prop = defaultProperty;
1142
1143         bool canDefer = false;
1144         if (isCustomParser) {
1145             if (doesPropertyExist(prop, obj)) {
1146                 int ids = compileState->ids.count();
1147                 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1148                 canDefer = ids == compileState->ids.count();
1149             } else {
1150                 customProps << QQmlCustomParserNodePrivate::fromProperty(prop);
1151             }
1152         } else {
1153             int ids = compileState->ids.count();
1154             COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1155             canDefer = ids == compileState->ids.count();
1156         }
1157
1158         if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1159             prop->isDeferred = true;
1160     }
1161
1162     // Compile custom parser parts
1163     if (isCustomParser && !customProps.isEmpty()) {
1164         cp->clearErrors();
1165         cp->compiler = this;
1166         cp->object = obj;
1167         obj->custom = cp->compile(customProps);
1168         cp->compiler = 0;
1169         cp->object = 0;
1170         foreach (QQmlError err, cp->errors()) {
1171             err.setUrl(output->url);
1172             exceptions << err;
1173         }
1174     }
1175
1176     compileState->objectDepth.pop();
1177
1178     return true;
1179 }
1180
1181 void QQmlCompiler::genObject(QQmlScript::Object *obj)
1182 {
1183     QQmlCompiledData::TypeReference &tr = output->types[obj->type];
1184     if (tr.type && obj->metatype == &QQmlComponent::staticMetaObject) {
1185         genComponent(obj);
1186         return;
1187     }
1188
1189     // Create the object
1190     if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
1191         !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) {
1192
1193         Instruction::CreateSimpleObject create;
1194         create.create = output->types.at(obj->type).type->createFunction();
1195         create.typeSize = output->types.at(obj->type).type->createSize();
1196         create.type = obj->type;
1197         create.line = obj->location.start.line;
1198         create.column = obj->location.start.column;
1199         output->addInstruction(create);
1200
1201     } else {
1202
1203         if (output->types.at(obj->type).type) {
1204             Instruction::CreateCppObject create;
1205             create.line = obj->location.start.line;
1206             create.column = obj->location.start.column;
1207             create.data = -1;
1208             if (!obj->custom.isEmpty())
1209                 create.data = output->indexForByteArray(obj->custom);
1210             create.type = obj->type;
1211             create.isRoot = (compileState->root == obj);
1212             output->addInstruction(create);
1213         } else {
1214             Instruction::CreateQMLObject create;
1215             create.type = obj->type;
1216             create.isRoot = (compileState->root == obj);
1217
1218             if (!obj->bindingBitmask.isEmpty()) {
1219                 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
1220                 create.bindingBits = output->indexForByteArray(obj->bindingBitmask);
1221             } else {
1222                 create.bindingBits = -1;
1223             }
1224             output->addInstruction(create);
1225
1226             Instruction::CompleteQMLObject complete;
1227             complete.line = obj->location.start.line;
1228             complete.column = obj->location.start.column;
1229             complete.isRoot = (compileState->root == obj);
1230             output->addInstruction(complete);
1231         }
1232     }
1233
1234     // Setup the synthesized meta object if necessary
1235     if (!obj->metadata.isEmpty()) {
1236         Instruction::StoreMetaObject meta;
1237         meta.data = output->indexForByteArray(obj->metadata);
1238         meta.aliasData = output->indexForByteArray(obj->synthdata);
1239         meta.propertyCache = output->propertyCaches.count();
1240
1241         QQmlPropertyCache *propertyCache = obj->synthCache;
1242         Q_ASSERT(propertyCache);
1243         propertyCache->addref();
1244
1245         // Add flag for alias properties
1246         if (!obj->synthdata.isEmpty()) {
1247             const QQmlVMEMetaData *vmeMetaData = 
1248                 reinterpret_cast<const QQmlVMEMetaData *>(obj->synthdata.constData());
1249             for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
1250                 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
1251                 QQmlPropertyData *data = propertyCache->property(index);
1252                 data->setFlags(data->getFlags() | QQmlPropertyData::IsAlias);
1253             }
1254         }
1255
1256         if (obj == unitRoot) {
1257             propertyCache->addref();
1258             output->rootPropertyCache = propertyCache;
1259         }
1260
1261         output->propertyCaches << propertyCache;
1262         output->addInstruction(meta);
1263     } else if (obj == unitRoot) {
1264         output->rootPropertyCache = tr.createPropertyCache(engine);
1265         output->rootPropertyCache->addref();
1266     }
1267
1268     // Set the object id
1269     if (!obj->id.isEmpty()) {
1270         Instruction::SetId id;
1271         id.value = output->indexForString(obj->id);
1272         id.index = obj->idIndex;
1273         output->addInstruction(id);
1274     }
1275
1276     // Begin the class
1277     if (tr.type && obj->parserStatusCast != -1) {
1278         Instruction::BeginObject begin;
1279         begin.castValue = obj->parserStatusCast;
1280         output->addInstruction(begin);
1281     }
1282
1283     genObjectBody(obj);
1284 }
1285
1286 void QQmlCompiler::genObjectBody(QQmlScript::Object *obj)
1287 {
1288     for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1289         Q_ASSERT(prop->scriptStringScope != -1);
1290         const QString &script = prop->values.first()->value.asScript();
1291         Instruction::StoreScriptString ss;
1292         ss.propertyIndex = prop->index;
1293         ss.value = output->indexForString(script);
1294         ss.scope = prop->scriptStringScope;
1295 //        ss.bindingId = rewriteBinding(script, prop->name());
1296         ss.bindingId = rewriteBinding(prop->values.first()->value, QString()); // XXX
1297         ss.line = prop->location.start.line;
1298         ss.column = prop->location.start.column;
1299         output->addInstruction(ss);
1300     }
1301
1302     bool seenDefer = false;
1303     for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1304         if (prop->isDeferred) {
1305             seenDefer = true;
1306             continue;
1307         }
1308         if (!prop->isAlias)
1309             genValueProperty(prop, obj);
1310     }
1311     if (seenDefer) {
1312         Instruction::Defer defer;
1313         defer.deferCount = 0;
1314         int deferIdx = output->addInstruction(defer);
1315         int nextInstructionIndex = output->nextInstructionIndex();
1316
1317         Instruction::DeferInit dinit;
1318         // XXX - these are now massive over allocations
1319         dinit.bindingsSize = compileState->totalBindingsCount;
1320         dinit.parserStatusSize = compileState->parserStatusCount; 
1321         dinit.objectStackSize = compileState->objectDepth.maxDepth(); 
1322         dinit.listStackSize = compileState->listDepth.maxDepth(); 
1323         output->addInstruction(dinit);
1324
1325         for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1326             if (!prop->isDeferred)
1327                 continue;
1328             genValueProperty(prop, obj);
1329         }
1330
1331         Instruction::Done done;
1332         output->addInstruction(done);
1333
1334         output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1335     }
1336
1337     for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1338
1339         QQmlScript::Value *v = prop->values.first();
1340
1341         if (v->type == Value::SignalObject) {
1342
1343             genObject(v->object);
1344
1345             Instruction::AssignSignalObject assign;
1346             assign.line = v->location.start.line;
1347             assign.signal = output->indexForString(prop->name().toString());
1348             output->addInstruction(assign);
1349
1350         } else if (v->type == Value::SignalExpression) {
1351
1352             Instruction::StoreSignal store;
1353             store.signalIndex = prop->index;
1354             const QString &rewrite = rewriteSignalHandler(v->value, prop->name().toString());
1355             store.value = output->indexForByteArray(rewrite.toUtf8());
1356             store.context = v->signalExpressionContextStack;
1357             store.line = v->location.start.line;
1358             store.column = v->location.start.column;
1359             output->addInstruction(store);
1360
1361         }
1362
1363     }
1364
1365     for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1366         Instruction::FetchAttached fetch;
1367         fetch.id = prop->index;
1368         fetch.line = prop->location.start.line;
1369         output->addInstruction(fetch);
1370
1371         genObjectBody(prop->value);
1372
1373         Instruction::PopFetchedObject pop;
1374         output->addInstruction(pop);
1375     }
1376
1377     for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1378         Instruction::FetchObject fetch;
1379         fetch.property = prop->index;
1380         fetch.line = prop->location.start.line;
1381         output->addInstruction(fetch);
1382
1383         if (!prop->value->metadata.isEmpty()) {
1384             Instruction::StoreMetaObject meta;
1385             meta.data = output->indexForByteArray(prop->value->metadata);
1386             meta.aliasData = output->indexForByteArray(prop->value->synthdata);
1387             meta.propertyCache = -1;
1388             output->addInstruction(meta);
1389         }
1390
1391         genObjectBody(prop->value);
1392
1393         Instruction::PopFetchedObject pop;
1394         output->addInstruction(pop);
1395     }
1396
1397     for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1398         if (!prop->isAlias)
1399             genValueTypeProperty(obj, prop);
1400     }
1401
1402     for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1403         if (prop->isDeferred) 
1404             continue;
1405         if (prop->isAlias)
1406             genValueProperty(prop, obj);
1407     }
1408
1409     for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1410         if (prop->isAlias)
1411             genValueTypeProperty(obj, prop);
1412     }
1413 }
1414
1415 void QQmlCompiler::genValueTypeProperty(QQmlScript::Object *obj,QQmlScript::Property *prop)
1416 {
1417     Instruction::FetchValueType fetch;
1418     fetch.property = prop->index;
1419     fetch.type = prop->type;
1420     fetch.bindingSkipList = 0;
1421
1422     if (obj->type == -1 || output->types.at(obj->type).component) {
1423         // We only have to do this if this is a composite type.  If it is a builtin
1424         // type it can't possibly already have bindings that need to be cleared.
1425         for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1426             if (!vprop->values.isEmpty()) {
1427                 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1428                 fetch.bindingSkipList |= (1 << vprop->index);
1429             }
1430         }
1431     }
1432
1433     output->addInstruction(fetch);
1434
1435     for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1436         genPropertyAssignment(vprop, prop->value, prop);
1437     }
1438
1439     Instruction::PopValueType pop;
1440     pop.property = prop->index;
1441     pop.type = prop->type;
1442     pop.bindingSkipList = 0;
1443     output->addInstruction(pop);
1444 }
1445
1446 void QQmlCompiler::genComponent(QQmlScript::Object *obj)
1447 {
1448     QQmlScript::Object *root = obj->defaultProperty->values.first()->object;
1449     Q_ASSERT(root);
1450
1451     Instruction::CreateComponent create;
1452     create.line = root->location.start.line;
1453     create.column = root->location.start.column;
1454     create.endLine = root->location.end.line;
1455     create.isRoot = (compileState->root == obj);
1456     int createInstruction = output->addInstruction(create);
1457     int nextInstructionIndex = output->nextInstructionIndex();
1458
1459     ComponentCompileState *oldCompileState = compileState;
1460     compileState = componentState(root);
1461
1462     Instruction::Init init;
1463     init.bindingsSize = compileState->totalBindingsCount;
1464     init.parserStatusSize = compileState->parserStatusCount;
1465     init.contextCache = genContextCache();
1466     init.objectStackSize = compileState->objectDepth.maxDepth();
1467     init.listStackSize = compileState->listDepth.maxDepth();
1468     if (compileState->compiledBindingData.isEmpty())
1469         init.compiledBinding = -1;
1470     else
1471         init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
1472     output->addInstruction(init);
1473
1474     if (!compileState->v8BindingProgram.isEmpty()) {
1475         Instruction::InitV8Bindings bindings;
1476         int index = output->programs.count();
1477
1478         typedef QQmlCompiledData::V8Program V8Program;
1479         output->programs.append(V8Program(compileState->v8BindingProgram, output));
1480
1481         bindings.programIndex = index;
1482         bindings.line = compileState->v8BindingProgramLine;
1483         output->addInstruction(bindings);
1484     }
1485
1486     genObject(root);
1487
1488     Instruction::SetDefault def;
1489     output->addInstruction(def);
1490
1491     Instruction::Done done;
1492     output->addInstruction(done);
1493
1494     output->instruction(createInstruction)->createComponent.count = 
1495         output->nextInstructionIndex() - nextInstructionIndex;
1496
1497     compileState = oldCompileState;
1498
1499     if (!obj->id.isEmpty()) {
1500         Instruction::SetId id;
1501         id.value = output->indexForString(obj->id);
1502         id.index = obj->idIndex;
1503         output->addInstruction(id);
1504     }
1505
1506     if (obj == unitRoot) {
1507         output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1508         output->rootPropertyCache->addref();
1509     }
1510 }
1511
1512 bool QQmlCompiler::buildComponent(QQmlScript::Object *obj,
1513                                  const BindingContext &ctxt)
1514 {
1515     // The special "Component" element can only have the id property and a
1516     // default property, that actually defines the component's tree
1517
1518     compileState->objectDepth.push();
1519
1520     // Find, check and set the "id" property (if any)
1521     Property *idProp = 0;
1522     if (obj->properties.isMany() ||
1523        (obj->properties.isOne() && obj->properties.first()->name() != id_string))
1524         COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
1525        
1526     if (!obj->properties.isEmpty())
1527         idProp = obj->properties.first();
1528
1529     if (idProp) {
1530        if (idProp->value || idProp->values.isMany() || idProp->values.first()->object) 
1531            COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1532        COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1533
1534         QString idVal = idProp->values.first()->primitive();
1535
1536         if (compileState->ids.value(idVal))
1537             COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1538
1539         obj->id = idVal;
1540         addId(idVal, obj);
1541     }
1542
1543     // Check the Component tree is well formed
1544     if (obj->defaultProperty &&
1545        (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
1546         (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
1547         COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1548
1549     if (!obj->dynamicProperties.isEmpty())
1550         COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1551     if (!obj->dynamicSignals.isEmpty())
1552         COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1553     if (!obj->dynamicSlots.isEmpty())
1554         COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1555
1556     QQmlScript::Object *root = 0;
1557     if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
1558         root = obj->defaultProperty->values.first()->object;
1559
1560     if (!root)
1561         COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1562
1563     // Build the component tree
1564     COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1565
1566     compileState->objectDepth.pop();
1567
1568     return true;
1569 }
1570
1571 bool QQmlCompiler::buildComponentFromRoot(QQmlScript::Object *obj,
1572                                          const BindingContext &ctxt)
1573 {
1574     ComponentCompileState *oldComponentCompileState = compileState;
1575     compileState = pool->New<ComponentCompileState>();
1576     compileState->root = obj;
1577     compileState->nested = true;
1578
1579     if (componentStats) {
1580         ComponentStat oldComponentStat = componentStats->componentStat;
1581
1582         componentStats->componentStat = ComponentStat();
1583         componentStats->componentStat.lineNumber = obj->location.start.line;
1584
1585         if (obj)
1586             COMPILE_CHECK(buildObject(obj, ctxt));
1587
1588         COMPILE_CHECK(completeComponentBuild());
1589
1590         componentStats->componentStat = oldComponentStat;
1591     } else {
1592         if (obj)
1593             COMPILE_CHECK(buildObject(obj, ctxt));
1594
1595         COMPILE_CHECK(completeComponentBuild());
1596     }
1597
1598     compileState = oldComponentCompileState;
1599
1600     return true;
1601 }
1602
1603
1604 // Build a sub-object.  A sub-object is one that was not created directly by
1605 // QML - such as a grouped property object, or an attached object.  Sub-object's
1606 // can't have an id, involve a custom parser, have attached properties etc.
1607 bool QQmlCompiler::buildSubObject(QQmlScript::Object *obj, const BindingContext &ctxt)
1608 {
1609     Q_ASSERT(obj->metatype);
1610     Q_ASSERT(!obj->defaultProperty);
1611     Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1612                                    // sub-context
1613
1614     for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1615         if (isSignalPropertyName(prop->name())) {
1616             COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1617         } else {
1618             COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1619         }
1620     }
1621
1622     return true;
1623 }
1624
1625 int QQmlCompiler::componentTypeRef()
1626 {
1627     if (cachedComponentTypeRef == -1) {
1628         QQmlType *t = QQmlMetaType::qmlType(Component_import_string,1,0);
1629         for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1630             if (output->types.at(ii).type == t) {
1631                 cachedComponentTypeRef = ii;
1632                 return ii;
1633             }
1634         }
1635         QQmlCompiledData::TypeReference ref;
1636         ref.className = Component_string;
1637         ref.type = t;
1638         output->types << ref;
1639         cachedComponentTypeRef = output->types.count() - 1;
1640     }
1641     return cachedComponentTypeRef;
1642 }
1643
1644 int QQmlCompiler::translationContextIndex()
1645 {
1646     if (cachedTranslationContextIndex == -1) {
1647         // This code must match that in the qsTr() implementation
1648         const QString &path = output->name;
1649         int lastSlash = path.lastIndexOf(QLatin1Char('/'));
1650         QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) :
1651                                              QString();
1652         QByteArray contextUtf8 = context.toUtf8();
1653         cachedTranslationContextIndex = output->indexForByteArray(contextUtf8);
1654     }
1655     return cachedTranslationContextIndex;
1656 }
1657
1658 bool QQmlCompiler::buildSignal(QQmlScript::Property *prop, QQmlScript::Object *obj,
1659                                        const BindingContext &ctxt)
1660 {
1661     Q_ASSERT(obj->metaObject());
1662
1663     const QHashedStringRef &propName = prop->name();
1664
1665     Q_ASSERT(propName.startsWith(on_string));
1666     QString name = propName.mid(2, -1).toString();
1667
1668     // Note that the property name could start with any alpha or '_' or '$' character,
1669     // so we need to do the lower-casing of the first alpha character.
1670     for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1671         if (name.at(firstAlphaIndex).isUpper()) {
1672             name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1673             break;
1674         }
1675     }
1676
1677     bool notInRevision = false;
1678
1679     QQmlPropertyData *sig = signal(obj, QStringRef(&name), &notInRevision);
1680
1681     if (sig == 0) {
1682
1683         if (notInRevision && 0 == property(obj, propName, 0)) {
1684             Q_ASSERT(obj->type != -1);
1685             const QList<QQmlTypeData::TypeReference>  &resolvedTypes = unit->resolvedTypes();
1686             const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1687             if (type.type) {
1688                 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));
1689             } else {
1690                 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1691             }
1692         }
1693
1694         // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1695         // property.
1696         COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1697
1698     }  else {
1699
1700         if (prop->value || !prop->values.isOne())
1701             COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1702
1703         prop->index = sig->coreIndex;
1704         prop->core = *sig;
1705
1706         obj->addSignalProperty(prop);
1707
1708         if (prop->values.first()->object) {
1709             COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1710             prop->values.first()->type = Value::SignalObject;
1711         } else {
1712             prop->values.first()->type = Value::SignalExpression;
1713
1714             if (!prop->values.first()->value.isScript())
1715                 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1716
1717             QString script = prop->values.first()->value.asScript().trimmed();
1718             if (script.isEmpty())
1719                 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1720
1721             prop->values.first()->signalExpressionContextStack = ctxt.stack;
1722         }
1723     }
1724
1725     return true;
1726 }
1727
1728
1729 /*!
1730     Returns true if (value) property \a prop exists on obj, false otherwise.
1731 */
1732 bool QQmlCompiler::doesPropertyExist(QQmlScript::Property *prop,
1733                                              QQmlScript::Object *obj)
1734 {
1735     if (prop->name().isEmpty())
1736         return false;
1737     if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1738         return true;
1739
1740     return property(obj, prop->name()) != 0;
1741 }
1742
1743 bool QQmlCompiler::buildProperty(QQmlScript::Property *prop,
1744                                          QQmlScript::Object *obj,
1745                                          const BindingContext &ctxt)
1746 {
1747     if (prop->isEmpty()) 
1748         COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1749
1750     const QMetaObject *metaObject = obj->metaObject();
1751     Q_ASSERT(metaObject);
1752
1753     if (isAttachedPropertyName(prop->name())) {
1754         // Setup attached property data
1755
1756         if (ctxt.isSubContext()) {
1757             // Attached properties cannot be used on sub-objects.  Sub-objects
1758             // always exist in a binding sub-context, which is what we test
1759             // for here.
1760             COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1761         }
1762
1763         QQmlType *type = 0;
1764         QQmlImportedNamespace *typeNamespace = 0;
1765         unit->imports().resolveType(prop->name().toString(), &type, 0, 0, 0, &typeNamespace);
1766
1767         if (typeNamespace) {
1768             COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj, 
1769                                                    ctxt));
1770             return true;
1771         } else if (!type || !type->attachedPropertiesType())  {
1772             COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1773         }
1774
1775         if (!prop->value)
1776             COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1777
1778         Q_ASSERT(type->attachedPropertiesFunction());
1779         prop->index = type->attachedPropertiesId();
1780         prop->value->metatype = type->attachedPropertiesType();
1781     } else {
1782         // Setup regular property data
1783         bool notInRevision = false;
1784         QQmlPropertyData *d =
1785             prop->name().isEmpty()?0:property(obj, prop->name(), &notInRevision);
1786
1787         if (d == 0 && notInRevision) {
1788             const QList<QQmlTypeData::TypeReference>  &resolvedTypes = unit->resolvedTypes();
1789             const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1790             if (type.type) {
1791                 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));
1792             } else {
1793                 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1794             }
1795         } else if (d) {
1796             prop->index = d->coreIndex;
1797             prop->core = *d;
1798         } else if (prop->isDefault) {
1799             QMetaProperty p = QQmlMetaType::defaultProperty(metaObject);
1800             QQmlPropertyData defaultPropertyData;
1801             defaultPropertyData.load(p, engine);
1802             if (p.name())
1803                 prop->setName(QLatin1String(p.name()));
1804             prop->core = defaultPropertyData;
1805             prop->index = prop->core.coreIndex;
1806         }
1807
1808         // We can't error here as the "id" property does not require a
1809         // successful index resolution
1810         if (prop->index != -1) 
1811             prop->type = prop->core.propType;
1812
1813         // Check if this is an alias
1814         if (prop->index != -1 && 
1815             prop->parent && 
1816             prop->parent->type != -1 && 
1817             output->types.at(prop->parent->type).component) {
1818
1819             QQmlPropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1820             if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1821                 prop->isAlias = true;
1822         }
1823
1824         if (prop->index != -1 && !prop->values.isEmpty()) 
1825             prop->parent->setBindingBit(prop->index);
1826     }
1827
1828     if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1829
1830         // The magic "id" behavior doesn't apply when "id" is resolved as a
1831         // default property or to sub-objects (which are always in binding
1832         // sub-contexts)
1833         COMPILE_CHECK(buildIdProperty(prop, obj));
1834         if (prop->type == QVariant::String &&
1835             prop->values.first()->value.isString())
1836             COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1837
1838     } else if (isAttachedPropertyName(prop->name())) {
1839
1840         COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1841
1842     } else if (prop->index == -1) {
1843
1844         if (prop->isDefault) {
1845             COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1846         } else {
1847             COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1848         }
1849
1850     } else if (prop->value) {
1851
1852         COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1853
1854     } else if (prop->core.isQList()) {
1855
1856         COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1857
1858     } else if (prop->type == qMetaTypeId<QQmlScriptString>()) {
1859
1860         COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1861
1862     } else {
1863
1864         COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1865
1866     }
1867
1868     return true;
1869 }
1870
1871 bool QQmlCompiler::buildPropertyInNamespace(QQmlImportedNamespace *ns,
1872                                                     QQmlScript::Property *nsProp, 
1873                                                     QQmlScript::Object *obj, 
1874                                                     const BindingContext &ctxt)
1875 {
1876     if (!nsProp->value)
1877         COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1878
1879     for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1880
1881         if (!isAttachedPropertyName(prop->name()))
1882             COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1883
1884         // Setup attached property data
1885
1886         QQmlType *type = 0;
1887         unit->imports().resolveType(ns, prop->name().toString(), &type, 0, 0, 0);
1888
1889         if (!type || !type->attachedPropertiesType()) 
1890             COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1891
1892         if (!prop->value)
1893             COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1894
1895         Q_ASSERT(type->attachedPropertiesFunction());
1896         prop->index = type->index();
1897         prop->value->metatype = type->attachedPropertiesType();
1898
1899         COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1900     }
1901
1902     return true;
1903 }
1904
1905 void QQmlCompiler::genValueProperty(QQmlScript::Property *prop,
1906                                    QQmlScript::Object *obj)
1907 {
1908     if (prop->core.isQList()) {
1909         genListProperty(prop, obj);
1910     } else {
1911         genPropertyAssignment(prop, obj);
1912     }
1913 }
1914
1915 void QQmlCompiler::genListProperty(QQmlScript::Property *prop,
1916                                   QQmlScript::Object *obj)
1917 {
1918     int listType = enginePrivate->listType(prop->type);
1919
1920     Instruction::FetchQList fetch;
1921     fetch.property = prop->index;
1922     bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
1923     fetch.type = listType;
1924     output->addInstruction(fetch);
1925
1926     for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1927
1928         if (v->type == Value::CreatedObject) {
1929
1930             genObject(v->object);
1931             if (listTypeIsInterface) {
1932                 Instruction::AssignObjectList assign;
1933                 assign.line = prop->location.start.line;
1934                 output->addInstruction(assign);
1935             } else {
1936                 Instruction::StoreObjectQList store;
1937                 output->addInstruction(store);
1938             }
1939
1940         } else if (v->type == Value::PropertyBinding) {
1941
1942             genBindingAssignment(v, prop, obj);
1943
1944         }
1945
1946     }
1947
1948     Instruction::PopQList pop;
1949     output->addInstruction(pop);
1950 }
1951
1952 void QQmlCompiler::genPropertyAssignment(QQmlScript::Property *prop,
1953                                         QQmlScript::Object *obj,
1954                                         QQmlScript::Property *valueTypeProperty)
1955 {
1956     for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1957
1958         Q_ASSERT(v->type == Value::CreatedObject ||
1959                  v->type == Value::PropertyBinding ||
1960                  v->type == Value::Literal);
1961
1962         if (v->type == Value::CreatedObject) {
1963
1964             genObject(v->object);
1965
1966             if (QQmlMetaType::isInterface(prop->type)) {
1967
1968                 Instruction::StoreInterface store;
1969                 store.line = v->object->location.start.line;
1970                 store.propertyIndex = prop->index;
1971                 output->addInstruction(store);
1972
1973             } else if (prop->type == QMetaType::QVariant) {
1974
1975                 if (prop->core.isVMEProperty()) {
1976                     Instruction::StoreVarObject store;
1977                     store.line = v->object->location.start.line;
1978                     store.propertyIndex = prop->index;
1979                     output->addInstruction(store);
1980                 } else {
1981                     Instruction::StoreVariantObject store;
1982                     store.line = v->object->location.start.line;
1983                     store.propertyIndex = prop->index;
1984                     output->addInstruction(store);
1985                 }
1986
1987
1988             } else {
1989
1990                 Instruction::StoreObject store;
1991                 store.line = v->object->location.start.line;
1992                 store.propertyIndex = prop->index;
1993                 output->addInstruction(store);
1994
1995             }
1996         } else if (v->type == Value::PropertyBinding) {
1997
1998             genBindingAssignment(v, prop, obj, valueTypeProperty);
1999
2000         } else if (v->type == Value::Literal) {
2001
2002             genLiteralAssignment(prop, v);
2003
2004         }
2005
2006     }
2007
2008     for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2009
2010         Q_ASSERT(v->type == Value::ValueSource ||
2011                  v->type == Value::ValueInterceptor);
2012
2013         if (v->type == Value::ValueSource) {
2014             genObject(v->object);
2015
2016             Instruction::StoreValueSource store;
2017             if (valueTypeProperty) {
2018                 store.property = genValueTypeData(prop, valueTypeProperty);
2019                 store.owner = 1;
2020             } else {
2021                 store.property = prop->core;
2022                 store.owner = 0;
2023             }
2024             QQmlType *valueType = toQmlType(v->object);
2025             store.castValue = valueType->propertyValueSourceCast();
2026             output->addInstruction(store);
2027
2028         } else if (v->type == Value::ValueInterceptor) {
2029             genObject(v->object);
2030
2031             Instruction::StoreValueInterceptor store;
2032             if (valueTypeProperty) {
2033                 store.property = genValueTypeData(prop, valueTypeProperty);
2034                 store.owner = 1;
2035             } else {
2036                 store.property = prop->core;
2037                 store.owner = 0;
2038             }
2039             QQmlType *valueType = toQmlType(v->object);
2040             store.castValue = valueType->propertyValueInterceptorCast();
2041             output->addInstruction(store);
2042         }
2043
2044     }
2045 }
2046
2047 bool QQmlCompiler::buildIdProperty(QQmlScript::Property *prop,
2048                                   QQmlScript::Object *obj)
2049 {
2050     if (prop->value ||
2051         prop->values.isMany() ||
2052         prop->values.first()->object)
2053         COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
2054
2055     QQmlScript::Value *idValue = prop->values.first();
2056     QString val = idValue->primitive();
2057
2058     COMPILE_CHECK(checkValidId(idValue, val));
2059
2060     if (compileState->ids.value(val))
2061         COMPILE_EXCEPTION(prop, tr("id is not unique"));
2062
2063     prop->values.first()->type = Value::Id;
2064
2065     obj->id = val;
2066     addId(val, obj);
2067
2068     return true;
2069 }
2070
2071 void QQmlCompiler::addId(const QString &id, QQmlScript::Object *obj)
2072 {
2073     Q_UNUSED(id);
2074     Q_ASSERT(!compileState->ids.value(id));
2075     Q_ASSERT(obj->id == id);
2076     obj->idIndex = compileState->ids.count();
2077     compileState->ids.append(obj);
2078 }
2079
2080 void QQmlCompiler::addBindingReference(JSBindingReference *ref)
2081 {
2082     Q_ASSERT(ref->value && !ref->value->bindingReference);
2083     ref->value->bindingReference = ref;
2084     compileState->totalBindingsCount++;
2085     compileState->bindings.prepend(ref);
2086 }
2087
2088 void QQmlCompiler::saveComponentState()
2089 {
2090     Q_ASSERT(compileState->root);
2091     Q_ASSERT(compileState->root->componentCompileState == 0);
2092
2093     compileState->root->componentCompileState = compileState;
2094
2095     if (componentStats) 
2096         componentStats->savedComponentStats.append(componentStats->componentStat);
2097 }
2098
2099 QQmlCompilerTypes::ComponentCompileState *
2100 QQmlCompiler::componentState(QQmlScript::Object *obj)
2101 {
2102     Q_ASSERT(obj->componentCompileState);
2103     return obj->componentCompileState;
2104 }
2105
2106 // Build attached property object.  In this example,
2107 // Text {
2108 //    GridView.row: 10
2109 // }
2110 // GridView is an attached property object.
2111 bool QQmlCompiler::buildAttachedProperty(QQmlScript::Property *prop,
2112                                         QQmlScript::Object *obj,
2113                                         const BindingContext &ctxt)
2114 {
2115     Q_ASSERT(prop->value);
2116     Q_ASSERT(prop->index != -1); // This is set in buildProperty()
2117
2118     compileState->objectDepth.push();
2119
2120     obj->addAttachedProperty(prop);
2121
2122     COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2123
2124     compileState->objectDepth.pop();
2125
2126     return true;
2127 }
2128
2129
2130 // Build "grouped" properties. In this example:
2131 // Text {
2132 //     font.pointSize: 12
2133 //     font.family: "Helvetica"
2134 // }
2135 // font is a nested property.  pointSize and family are not.
2136 bool QQmlCompiler::buildGroupedProperty(QQmlScript::Property *prop,
2137                                                 QQmlScript::Object *obj,
2138                                                 const BindingContext &ctxt)
2139 {
2140     Q_ASSERT(prop->type != 0);
2141     Q_ASSERT(prop->index != -1);
2142
2143     if (QQmlValueTypeFactory::isValueType(prop->type)) {
2144         if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
2145
2146             if (!prop->values.isEmpty()) {
2147                 if (prop->values.first()->location < prop->value->location) {
2148                     COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
2149                 } else {
2150                     COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
2151                 }
2152             }
2153
2154             if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) {
2155                 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2156             }
2157
2158
2159             if (prop->isAlias) {
2160                 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
2161                     vtProp->isAlias = true;
2162                 }
2163             }
2164
2165             COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
2166                                                  prop->value, obj, ctxt.incr()));
2167             obj->addValueTypeProperty(prop);
2168         } else {
2169             COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2170         }
2171
2172     } else {
2173         // Load the nested property's meta type
2174         prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
2175         if (!prop->value->metatype)
2176             COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2177
2178         if (!prop->values.isEmpty()) 
2179             COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
2180
2181         obj->addGroupedProperty(prop);
2182
2183         compileState->objectDepth.push();
2184
2185         COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2186
2187         compileState->objectDepth.pop();
2188     }
2189
2190     return true;
2191 }
2192
2193 bool QQmlCompiler::buildValueTypeProperty(QObject *type,
2194                                                   QQmlScript::Object *obj,
2195                                                   QQmlScript::Object *baseObj,
2196                                                   const BindingContext &ctxt)
2197 {
2198     compileState->objectDepth.push();
2199
2200     if (obj->defaultProperty)
2201         COMPILE_EXCEPTION(obj, tr("Invalid property use"));
2202     obj->metatype = type->metaObject();
2203
2204     for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
2205
2206         QQmlPropertyData *d = property(obj, prop->name());
2207         if (d == 0) 
2208             COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
2209
2210         prop->index = d->coreIndex;
2211         prop->type = d->propType;
2212         prop->core = *d;
2213         prop->isValueTypeSubProperty = true;
2214
2215         if (prop->value)
2216             COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
2217
2218         if (prop->values.isMany()) {
2219             COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
2220         } else if (!prop->values.isEmpty()) {
2221             QQmlScript::Value *value = prop->values.first();
2222
2223             if (value->object) {
2224                 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
2225             } else if (value->value.isScript()) {
2226                 // ### Check for writability
2227
2228                 //optimization for <Type>.<EnumValue> enum assignments
2229                 bool isEnumAssignment = false;
2230
2231                 if (prop->core.isEnum()) 
2232                     COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, value, &isEnumAssignment));
2233
2234                 if (isEnumAssignment) {
2235                     value->type = Value::Literal;
2236                 } else {
2237                     JSBindingReference *reference = pool->New<JSBindingReference>();
2238                     reference->expression = value->value;
2239                     reference->property = prop;
2240                     reference->value = value;
2241                     reference->bindingContext = ctxt;
2242                     reference->bindingContext.owner++;
2243                     addBindingReference(reference);
2244                     value->type = Value::PropertyBinding;
2245                 }
2246             } else  {
2247                 COMPILE_CHECK(testLiteralAssignment(prop, value));
2248                 value->type = Value::Literal;
2249             }
2250         }
2251
2252         for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2253             Q_ASSERT(v->object);
2254
2255             COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt)); 
2256         }
2257
2258         obj->addValueProperty(prop);
2259     }
2260
2261     compileState->objectDepth.pop();
2262
2263     return true;
2264 }
2265
2266 // Build assignments to QML lists.  QML lists are properties of type
2267 // QQmlListProperty<T>.  List properties can accept a list of 
2268 // objects, or a single binding.
2269 bool QQmlCompiler::buildListProperty(QQmlScript::Property *prop,
2270                                              QQmlScript::Object *obj,
2271                                              const BindingContext &ctxt)
2272 {
2273     Q_ASSERT(prop->core.isQList());
2274
2275     compileState->listDepth.push();
2276
2277     int t = prop->type;
2278
2279     obj->addValueProperty(prop);
2280
2281     int listType = enginePrivate->listType(t);
2282     bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
2283
2284     bool assignedBinding = false;
2285     for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2286         if (v->object) {
2287             v->type = Value::CreatedObject;
2288             COMPILE_CHECK(buildObject(v->object, ctxt));
2289
2290             // We check object coercian here.  We check interface assignment
2291             // at runtime.
2292             if (!listTypeIsInterface) {
2293                 if (!canCoerce(listType, v->object)) {
2294                     COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2295                 }
2296             }
2297
2298         } else if (v->value.isScript()) {
2299             if (assignedBinding)
2300                 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2301
2302             assignedBinding = true;
2303             COMPILE_CHECK(buildBinding(v, prop, ctxt));
2304             v->type = Value::PropertyBinding;
2305         } else {
2306             COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2307         }
2308     }
2309
2310     compileState->listDepth.pop();
2311
2312     return true;
2313 }
2314
2315 // Compiles an assignment to a QQmlScriptString property
2316 bool QQmlCompiler::buildScriptStringProperty(QQmlScript::Property *prop,
2317                                             QQmlScript::Object *obj,
2318                                             const BindingContext &ctxt)
2319 {
2320     if (prop->values.isMany())
2321         COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2322
2323     if (prop->values.first()->object)
2324         COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2325
2326     prop->scriptStringScope = ctxt.stack;
2327     obj->addScriptStringProperty(prop);
2328
2329     return true;
2330 }
2331
2332 // Compile regular property assignments of the form "property: <value>"
2333 bool QQmlCompiler::buildPropertyAssignment(QQmlScript::Property *prop,
2334                                           QQmlScript::Object *obj,
2335                                           const BindingContext &ctxt)
2336 {
2337     obj->addValueProperty(prop);
2338
2339     if (prop->values.isMany())
2340         COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2341
2342     for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2343         if (v->object) {
2344
2345             COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2346
2347         } else {
2348
2349             COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2350
2351         }
2352     }
2353
2354     for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2355         Q_ASSERT(v->object);
2356         COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2357     }
2358
2359     return true;
2360 }
2361
2362 // Compile assigning a single object instance to a regular property
2363 bool QQmlCompiler::buildPropertyObjectAssignment(QQmlScript::Property *prop,
2364                                                          QQmlScript::Object *obj,
2365                                                          QQmlScript::Value *v,
2366                                                          const BindingContext &ctxt)
2367 {
2368     Q_ASSERT(prop->index != -1);
2369     Q_ASSERT(v->object->type != -1);
2370
2371     if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2372         COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2373
2374     if (QQmlMetaType::isInterface(prop->type)) {
2375
2376         // Assigning an object to an interface ptr property
2377         COMPILE_CHECK(buildObject(v->object, ctxt));
2378
2379         v->type = Value::CreatedObject;
2380
2381     } else if (prop->type == QMetaType::QVariant) {
2382
2383         // Assigning an object to a QVariant
2384         COMPILE_CHECK(buildObject(v->object, ctxt));
2385
2386         v->type = Value::CreatedObject;
2387     } else {
2388         // Normally buildObject() will set this up, but we need the static
2389         // meta object earlier to test for assignability.  It doesn't matter
2390         // that there may still be outstanding synthesized meta object changes
2391         // on this type, as they are not relevant for assignability testing
2392         v->object->metatype = output->types.at(v->object->type).metaObject();
2393         Q_ASSERT(v->object->metaObject());
2394
2395         // We want to raw metaObject here as the raw metaobject is the
2396         // actual property type before we applied any extensions that might
2397         // effect the properties on the type, but don't effect assignability
2398         const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2399
2400         // Will be true if the assgned type inherits propertyMetaObject
2401         bool isAssignable = false;
2402         // Determine isAssignable value
2403         if (propertyMetaObject) {
2404             const QMetaObject *c = v->object->metatype;
2405             while(c) {
2406                 isAssignable |= (QQmlPropertyPrivate::equal(c, propertyMetaObject));
2407                 c = c->superClass();
2408             }
2409         }
2410
2411         if (isAssignable) {
2412             // Simple assignment
2413             COMPILE_CHECK(buildObject(v->object, ctxt));
2414
2415             v->type = Value::CreatedObject;
2416         } else if (propertyMetaObject == &QQmlComponent::staticMetaObject) {
2417             // Automatic "Component" insertion
2418             QQmlScript::Object *root = v->object;
2419             QQmlScript::Object *component = pool->New<Object>();
2420             component->type = componentTypeRef();
2421             component->typeName = QStringLiteral("Qt/Component");
2422             component->metatype = &QQmlComponent::staticMetaObject;
2423             component->location = root->location;
2424             QQmlScript::Value *componentValue = pool->New<Value>();
2425             componentValue->object = root;
2426             component->getDefaultProperty()->addValue(componentValue);
2427             v->object = component;
2428             COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2429         } else {
2430             COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2431         }
2432     }
2433
2434     return true;
2435 }
2436
2437 // Compile assigning a single object instance to a regular property using the "on" syntax.
2438 //
2439 // For example:
2440 //     Item {
2441 //         NumberAnimation on x { }
2442 //     }
2443 bool QQmlCompiler::buildPropertyOnAssignment(QQmlScript::Property *prop,
2444                                                      QQmlScript::Object *obj,
2445                                                      QQmlScript::Object *baseObj,
2446                                                      QQmlScript::Value *v,
2447                                                      const BindingContext &ctxt)
2448 {
2449     Q_ASSERT(prop->index != -1);
2450     Q_ASSERT(v->object->type != -1);
2451
2452     Q_UNUSED(obj);
2453
2454     if (!prop->core.isWritable())
2455         COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2456
2457
2458     // Normally buildObject() will set this up, but we need the static
2459     // meta object earlier to test for assignability.  It doesn't matter
2460     // that there may still be outstanding synthesized meta object changes
2461     // on this type, as they are not relevant for assignability testing
2462     v->object->metatype = output->types.at(v->object->type).metaObject();
2463     Q_ASSERT(v->object->metaObject());
2464
2465     // Will be true if the assigned type inherits QQmlPropertyValueSource
2466     bool isPropertyValue = false;
2467     // Will be true if the assigned type inherits QQmlPropertyValueInterceptor
2468     bool isPropertyInterceptor = false;
2469     if (QQmlType *valueType = toQmlType(v->object)) {
2470         isPropertyValue = valueType->propertyValueSourceCast() != -1;
2471         isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2472     }
2473
2474     if (isPropertyValue || isPropertyInterceptor) {
2475         // Assign as a property value source
2476         COMPILE_CHECK(buildObject(v->object, ctxt));
2477
2478         if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2479             buildDynamicMeta(baseObj, ForceCreation);
2480         v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2481     } else {
2482         COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(v->object->typeName).arg(prop->name().toString()));
2483     }
2484
2485     return true;
2486 }
2487
2488 // Compile assigning a literal or binding to a regular property
2489 bool QQmlCompiler::buildPropertyLiteralAssignment(QQmlScript::Property *prop,
2490                                                           QQmlScript::Object *obj,
2491                                                           QQmlScript::Value *v,
2492                                                           const BindingContext &ctxt)
2493 {
2494     Q_ASSERT(prop->index != -1);
2495
2496     if (v->value.isScript()) {
2497
2498         //optimization for <Type>.<EnumValue> enum assignments
2499         if (prop->core.isEnum()) {
2500             bool isEnumAssignment = false;
2501             COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, v, &isEnumAssignment));
2502             if (isEnumAssignment) {
2503                 v->type = Value::Literal;
2504                 return true;
2505             }
2506         }
2507
2508         // Test for other binding optimizations
2509         if (!buildLiteralBinding(v, prop, ctxt))
2510             COMPILE_CHECK(buildBinding(v, prop, ctxt));
2511
2512         v->type = Value::PropertyBinding;
2513
2514     } else {
2515
2516         COMPILE_CHECK(testLiteralAssignment(prop, v));
2517
2518         v->type = Value::Literal;
2519     }
2520
2521     return true;
2522 }
2523
2524 bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
2525                                                        QQmlScript::Object *obj,
2526                                                        QQmlScript::Value *v,
2527                                                        bool *isAssignment)
2528 {
2529     *isAssignment = false;
2530     if (!prop->core.isEnum())
2531         return true;
2532
2533     QMetaProperty mprop = obj->metaObject()->property(prop->index);
2534
2535     if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2536         COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2537
2538     QString string = v->value.asString();
2539     if (!string.at(0).isUpper())
2540         return true;
2541
2542     QStringList parts = string.split(QLatin1Char('.'));
2543     if (parts.count() != 2)
2544         return true;
2545
2546     QString typeName = parts.at(0);
2547     QQmlType *type = 0;
2548     unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
2549
2550     //handle enums on value types (where obj->typeName is empty)
2551     QString objTypeName = obj->typeName;
2552     if (objTypeName.isEmpty()) {
2553         QQmlType *objType = toQmlType(obj);
2554         if (objType)
2555             objTypeName = objType->qmlTypeName();
2556     }
2557
2558     if (!type)
2559         return true;
2560
2561     QString enumValue = parts.at(1);
2562     int value;
2563     bool ok;
2564
2565     if (objTypeName == type->qmlTypeName()) {
2566         // When these two match, we can short cut the search
2567         if (mprop.isFlagType()) {
2568             value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
2569         } else {
2570             value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
2571         }
2572     } else {
2573         // Otherwise we have to search the whole type
2574         // This matches the logic in QV8TypeWrapper
2575         QByteArray enumName = enumValue.toUtf8();
2576         const QMetaObject *metaObject = type->baseMetaObject();
2577         ok = false;
2578         for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
2579             QMetaEnum e = metaObject->enumerator(ii);
2580             value = e.keyToValue(enumName.constData(), &ok);
2581         }
2582     }
2583
2584     if (!ok)
2585         return true;
2586
2587     v->type = Value::Literal;
2588     v->value = QQmlScript::Variant((double)value);
2589     *isAssignment = true;
2590
2591     return true;
2592 }
2593
2594 struct StaticQtMetaObject : public QObject
2595 {
2596     static const QMetaObject *get()
2597         { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2598 };
2599
2600 // Similar logic to above, but not knowing target property.
2601 int QQmlCompiler::evaluateEnum(const QByteArray& script) const
2602 {
2603     int dot = script.indexOf('.');
2604     if (dot > 0) {
2605         const QByteArray &scope = script.left(dot);
2606         QQmlType *type = 0;
2607         unit->imports().resolveType(QString::fromUtf8(script.left(dot)), &type, 0, 0, 0, 0);
2608         if (!type && scope != "Qt")
2609             return -1;
2610         const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2611         const char *key = script.constData() + dot+1;
2612         int i = mo->enumeratorCount();
2613         while (i--) {
2614             bool ok;
2615             int v = mo->enumerator(i).keyToValue(key, &ok);
2616             if (ok)
2617                 return v;
2618         }
2619     }
2620     return -1;
2621 }
2622
2623 const QMetaObject *QQmlCompiler::resolveType(const QString& name) const
2624 {
2625     QQmlType *qmltype = 0;
2626     if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2627         return 0;
2628     if (!qmltype)
2629         return 0;
2630     return qmltype->metaObject();
2631 }
2632
2633 // similar to logic of completeComponentBuild, but also sticks data
2634 // into primitives at the end
2635 int QQmlCompiler::rewriteBinding(const QQmlScript::Variant& value, const QString& name)
2636 {
2637     QQmlRewrite::RewriteBinding rewriteBinding;
2638     rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1));
2639
2640     QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0);
2641
2642     return output->indexForString(rewrite);
2643 }
2644
2645 QString QQmlCompiler::rewriteSignalHandler(const QQmlScript::Variant& value, const QString &name)
2646 {
2647     QQmlRewrite::RewriteSignalHandler rewriteSignalHandler;
2648     return rewriteSignalHandler(value.asAST(), value.asScript(), name);
2649 }
2650
2651 // Ensures that the dynamic meta specification on obj is valid
2652 bool QQmlCompiler::checkDynamicMeta(QQmlScript::Object *obj)
2653 {
2654     bool seenDefaultProperty = false;
2655
2656     // We use a coarse grain, 31 bit hash to check if there are duplicates.
2657     // Calculating the hash for the names is not a waste as we have to test
2658     // them against the illegalNames set anyway.
2659     QHashField propNames;
2660     QHashField methodNames;
2661
2662     // Check properties
2663     for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2664         const QQmlScript::Object::DynamicProperty &prop = *p;
2665
2666         if (prop.isDefaultProperty) {
2667             if (seenDefaultProperty)
2668                 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2669             seenDefaultProperty = true;
2670         }
2671
2672         if (propNames.testAndSet(prop.name.hash())) {
2673             for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p; 
2674                  p2 = obj->dynamicProperties.next(p2)) {
2675                 if (p2->name == prop.name) {
2676                     COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2677                                                prop.nameLocation.column,
2678                                                tr("Duplicate property name"));
2679                 }
2680             }
2681         }
2682
2683         if (prop.name.at(0).isUpper()) {
2684             COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2685                                        prop.nameLocation.column,
2686                                        tr("Property names cannot begin with an upper case letter"));
2687         }
2688
2689         if (enginePrivate->v8engine()->illegalNames().contains(prop.name)) {
2690             COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2691                                        prop.nameLocation.column,
2692                                        tr("Illegal property name"));
2693         }
2694     }
2695
2696     for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2697         const QQmlScript::Object::DynamicSignal &currSig = *s;
2698
2699         if (methodNames.testAndSet(currSig.name.hash())) {
2700             for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2701                  s2 = obj->dynamicSignals.next(s2)) {
2702                 if (s2->name == currSig.name)
2703                     COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2704             }
2705         }
2706
2707         if (currSig.name.at(0).isUpper())
2708             COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2709         if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2710             COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2711     }
2712
2713     for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2714         const QQmlScript::Object::DynamicSlot &currSlot = *s;
2715
2716         if (methodNames.testAndSet(currSlot.name.hash())) {
2717             for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2718                  s2 = obj->dynamicSignals.next(s2)) {
2719                 if (s2->name == currSlot.name)
2720                     COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2721             }
2722             for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2723                  s2 = obj->dynamicSlots.next(s2)) {
2724                 if (s2->name == currSlot.name)
2725                     COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2726             }
2727         }
2728
2729         if (currSlot.name.at(0).isUpper())
2730             COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2731         if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2732             COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2733     }
2734
2735     return true;
2736 }
2737
2738 bool QQmlCompiler::mergeDynamicMetaProperties(QQmlScript::Object *obj)
2739 {
2740     for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2741          p = obj->dynamicProperties.next(p)) {
2742
2743         if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2744             continue;
2745
2746         Property *property = 0;
2747         if (p->isDefaultProperty) {
2748             property = obj->getDefaultProperty();
2749         } else {
2750             property = obj->getProperty(p->name);
2751             if (!property->values.isEmpty()) 
2752                 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2753         }
2754
2755         if (p->isReadOnly)
2756             property->isReadOnlyDeclaration = true;
2757
2758         if (property->value)
2759             COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2760
2761         property->values.append(p->defaultValue->values);
2762     }
2763     return true;
2764 }
2765
2766 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2767
2768 bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mode)
2769 {
2770     Q_ASSERT(obj);
2771     Q_ASSERT(obj->metatype);
2772
2773     if (mode != ForceCreation &&
2774         obj->dynamicProperties.isEmpty() &&
2775         obj->dynamicSignals.isEmpty() &&
2776         obj->dynamicSlots.isEmpty())
2777         return true;
2778
2779     bool resolveAlias = (mode == ResolveAliases);
2780
2781     const Object::DynamicProperty *defaultProperty = 0;
2782     int aliasCount = 0;
2783     int varPropCount = 0;
2784     int totalPropCount = 0;
2785     int firstPropertyVarIndex = 0;
2786
2787     for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2788
2789         if (p->type == Object::DynamicProperty::Alias)
2790             aliasCount++;
2791         if (p->type == Object::DynamicProperty::Var)
2792             varPropCount++;
2793
2794         if (p->isDefaultProperty && 
2795             (resolveAlias || p->type != Object::DynamicProperty::Alias))
2796             defaultProperty = p;
2797
2798         if (!resolveAlias) {
2799             // No point doing this for both the alias and non alias cases
2800             QQmlPropertyData *d = property(obj, p->name);
2801             if (d && d->isFinal())
2802                 COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2803         }
2804     }
2805
2806     bool buildData = resolveAlias || aliasCount == 0;
2807
2808     QByteArray dynamicData;
2809     if (buildData) {
2810         typedef QQmlVMEMetaData VMD;
2811
2812         dynamicData = QByteArray(sizeof(QQmlVMEMetaData) +
2813                                  (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) +
2814                                  obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2815                                  aliasCount * sizeof(VMD::AliasData), 0);
2816     }
2817
2818     int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1);
2819
2820     QByteArray newClassName = obj->metatype->className();
2821     newClassName.append("_QML_");
2822     newClassName.append(QByteArray::number(uniqueClassId));
2823
2824     if (compileState->root == obj && !compileState->nested) {
2825         QString path = output->url.path();
2826         int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2827         if (lastSlash > -1) {
2828             QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2829             if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2830                 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId);
2831         }
2832     }
2833
2834     // Size of the array that describes parameter types & names
2835     int paramDataSize = (obj->aggregateDynamicSignalParameterCount() + obj->aggregateDynamicSlotParameterCount()) * 2
2836             + obj->dynamicProperties.count() // for Changed() signals return types
2837             // Return "parameters" don't have names
2838             - (obj->dynamicSignals.count() + obj->dynamicSlots.count());
2839
2840     QFastMetaBuilder builder;
2841     int paramIndex;
2842     QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(), 
2843             obj->dynamicProperties.count() - (resolveAlias?0:aliasCount),
2844             obj->dynamicSlots.count(),
2845             obj->dynamicSignals.count() + obj->dynamicProperties.count(),
2846             defaultProperty?1:0, paramDataSize, &paramIndex);
2847
2848     struct TypeData {
2849         Object::DynamicProperty::Type dtype;
2850         int metaType;
2851     } builtinTypes[] = {
2852         { Object::DynamicProperty::Var, QMetaType::QVariant },
2853         { Object::DynamicProperty::Variant, QMetaType::QVariant },
2854         { Object::DynamicProperty::Int, QMetaType::Int },
2855         { Object::DynamicProperty::Bool, QMetaType::Bool },
2856         { Object::DynamicProperty::Real, QMetaType::Double },
2857         { Object::DynamicProperty::String, QMetaType::QString },
2858         { Object::DynamicProperty::Url, QMetaType::QUrl },
2859         { Object::DynamicProperty::Color, QMetaType::QColor },
2860         { Object::DynamicProperty::Time, QMetaType::QTime },
2861         { Object::DynamicProperty::Date, QMetaType::QDate },
2862         { Object::DynamicProperty::DateTime, QMetaType::QDateTime },
2863     };
2864     static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2865
2866     // Reserve dynamic properties
2867     if (obj->dynamicProperties.count()) {
2868         typedef QQmlVMEMetaData VMD;
2869
2870         int effectivePropertyIndex = 0;
2871         for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2872
2873             // Reserve space for name
2874             if (p->type != Object::DynamicProperty::Alias || resolveAlias)
2875                 p->nameRef = builder.newString(p->name.utf8length());
2876
2877             int metaType = 0;
2878             int propertyType = 0; // for VMD
2879             bool readonly = false;
2880
2881             if (p->type == Object::DynamicProperty::Alias) {
2882                 continue;
2883             } else if (p->type < builtinTypeCount) {
2884                 Q_ASSERT(builtinTypes[p->type].dtype == p->type);
2885                 metaType = builtinTypes[p->type].metaType;
2886                 propertyType = metaType;
2887
2888             } else {
2889                 Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
2890                          p->type == Object::DynamicProperty::Custom);
2891
2892                 // XXX don't double resolve this in the case of an alias run
2893
2894                 QByteArray customTypeName;
2895                 QQmlType *qmltype = 0;
2896                 QString url;
2897                 if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
2898                     COMPILE_EXCEPTION(p, tr("Invalid property type"));
2899
2900                 if (!qmltype) {
2901                     QQmlTypeData *tdata = enginePrivate->typeLoader.get(QUrl(url));
2902                     Q_ASSERT(tdata);
2903                     Q_ASSERT(tdata->isComplete());
2904
2905                     QQmlCompiledData *data = tdata->compiledData();
2906                     customTypeName = data->root->className();
2907                     data->release();
2908                     tdata->release();
2909                 } else {
2910                     customTypeName = qmltype->typeName();
2911                 }
2912
2913                 if (p->type == Object::DynamicProperty::Custom) {
2914                     customTypeName += '*';
2915                     propertyType = QMetaType::QObjectStar;
2916                 } else {
2917                     readonly = true;
2918                     customTypeName = QByteArray("QQmlListProperty<") + customTypeName + QByteArray(">");
2919                     propertyType = qMetaTypeId<QQmlListProperty<QObject> >();
2920                 }
2921
2922                 metaType = QMetaType::type(customTypeName);
2923                 Q_ASSERT(metaType != QMetaType::UnknownType);
2924                 Q_ASSERT(metaType != QMetaType::Void);
2925             }
2926
2927             if (p->type == Object::DynamicProperty::Var)
2928                 continue;
2929
2930             if (p->isReadOnly)
2931                 readonly = true;
2932
2933             if (buildData) {
2934                 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
2935                 vmd->propertyCount++;
2936                 (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType;
2937             }
2938
2939             builder.setProperty(effectivePropertyIndex, p->nameRef, metaType,
2940                                 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2941                                 effectivePropertyIndex);
2942
2943             p->changedNameRef = builder.newString(p->name.utf8length() + strlen("Changed"));
2944             builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
2945             paramIndex++;
2946
2947             effectivePropertyIndex++;
2948         }
2949
2950         if (varPropCount) {
2951             VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
2952             if (buildData)
2953                 vmd->varPropertyCount = varPropCount;
2954             firstPropertyVarIndex = effectivePropertyIndex;
2955             totalPropCount = varPropCount + effectivePropertyIndex;
2956             for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2957                 if (p->type == Object::DynamicProperty::Var) {
2958                     if (buildData) {
2959                         vmd->propertyCount++;
2960                         (vmd->propertyData() + effectivePropertyIndex)->propertyType = QMetaType::QVariant;
2961                     }
2962
2963                     builder.setProperty(effectivePropertyIndex, p->nameRef,
2964                                         QMetaType::QVariant,
2965                                         p->isReadOnly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2966                                         effectivePropertyIndex);
2967
2968                     p->changedNameRef = builder.newString(p->name.utf8length() + strlen("Changed"));
2969                     builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
2970                     paramIndex++;
2971
2972                     effectivePropertyIndex++;
2973                 }
2974             }
2975         }
2976         
2977         if (aliasCount) {
2978             int aliasIndex = 0;
2979             for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2980                 if (p->type == Object::DynamicProperty::Alias) {
2981                     if (resolveAlias) {
2982                         Q_ASSERT(buildData);
2983                         ((QQmlVMEMetaData *)dynamicData.data())->aliasCount++;
2984                         COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex, 
2985                                                    aliasIndex, *p));
2986                     }
2987                     // Even if we aren't resolving the alias, we need a fake signal so that the 
2988                     // metaobject remains consistent across the resolve and non-resolve alias runs
2989                     p->changedNameRef = builder.newString(p->name.utf8length() + strlen("Changed"));
2990                     builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex);
2991                     paramIndex++;
2992                     effectivePropertyIndex++;
2993                     aliasIndex++;
2994                 }
2995             }
2996         }
2997     }
2998
2999     // Reserve default property
3000     QFastMetaBuilder::StringRef defPropRef;
3001     if (defaultProperty) {
3002         defPropRef = builder.newString(strlen("DefaultProperty"));
3003         builder.setClassInfo(0, defPropRef, defaultProperty->nameRef);
3004     }
3005
3006     // Reserve dynamic signals
3007     int signalIndex = 0;
3008     for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
3009
3010         s->nameRef = builder.newString(s->name.utf8length());
3011
3012         int paramCount = s->parameterNames.count();
3013         QVarLengthArray<int, 10> paramTypes(paramCount);
3014         if (paramCount) {
3015             s->parameterNamesRef = pool->NewRawList<QFastMetaBuilder::StringRef>(paramCount);
3016             for (int i = 0; i < paramCount; ++i) {
3017                 s->parameterNamesRef[i] = builder.newString(s->parameterNames.at(i).utf8length());
3018                 Q_ASSERT(s->parameterTypes.at(i) < builtinTypeCount);
3019                 paramTypes[i] = builtinTypes[s->parameterTypes.at(i)].metaType;
3020             }
3021         }
3022
3023         if (buildData)
3024             ((QQmlVMEMetaData *)dynamicData.data())->signalCount++;
3025         
3026         builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->nameRef,
3027                           paramIndex, paramCount, paramTypes.constData(), s->parameterNamesRef.data());
3028         paramIndex += paramCount*2 + 1;
3029         ++signalIndex;
3030     }
3031
3032     // Reserve dynamic slots
3033     if (obj->dynamicSlots.count()) {
3034
3035         typedef QQmlVMEMetaData VMD;
3036
3037         int methodIndex = 0;
3038         for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3039             s->nameRef = builder.newString(s->name.utf8length());
3040             int paramCount = s->parameterNames.count();
3041
3042             QVarLengthArray<int, 10> paramTypes(paramCount);
3043             if (paramCount) {
3044                 s->parameterNamesRef = pool->NewRawList<QFastMetaBuilder::StringRef>(paramCount);
3045                 for (int i = 0; i < paramCount; ++i) {
3046                     s->parameterNamesRef[i] = builder.newString(s->parameterNames.at(i).size());
3047                     paramTypes[i] = QMetaType::QVariant;
3048                 }
3049             }
3050
3051             builder.setMethod(methodIndex, s->nameRef, paramIndex, paramCount,
3052                               paramTypes.constData(), s->parameterNamesRef.data(), QMetaType::QVariant);
3053             paramIndex += paramCount*2 + 1;
3054
3055             if (buildData) {
3056                 QString funcScript;
3057                 int namesSize = 0;
3058                 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
3059                 funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ +
3060                         namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
3061                 funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
3062                 for (int jj = 0; jj < paramCount; ++jj) {
3063                     if (jj) funcScript.append(QLatin1Char(','));
3064                     funcScript.append(QLatin1String(s->parameterNames.at(jj)));
3065                 }
3066                 funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
3067
3068                 QByteArray utf8 = funcScript.toUtf8();
3069                 VMD::MethodData methodData = { s->parameterNames.count(), 0, 
3070                                                utf8.length(),
3071                                                s->location.start.line };
3072
3073                 VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3074                 vmd->methodCount++;
3075
3076                 VMD::MethodData &md = *(vmd->methodData() + methodIndex);
3077                 md = methodData;
3078                 md.bodyOffset = dynamicData.size();
3079
3080                 dynamicData.append((const char *)utf8.constData(), utf8.length());
3081             }
3082
3083
3084             methodIndex++;
3085         }
3086     }
3087
3088     // Now allocate properties
3089     for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
3090
3091         char *d = p->changedNameRef.data();
3092         p->name.writeUtf8(d);
3093         strcpy(d + p->name.utf8length(), "Changed");
3094         p->changedNameRef.loadByteArrayData();
3095
3096         if (p->type == Object::DynamicProperty::Alias && !resolveAlias)
3097             continue;
3098
3099         p->nameRef.load(p->name);
3100     }
3101
3102     // Allocate default property if necessary
3103     if (defaultProperty) 
3104         defPropRef.load("DefaultProperty");
3105
3106     // Now allocate signals
3107     for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
3108
3109         s->nameRef.load(s->name);
3110
3111         for (int jj = 0; jj < s->parameterNames.count(); ++jj)
3112             s->parameterNamesRef[jj].load(s->parameterNames.at(jj));
3113     }
3114
3115     // Now allocate methods
3116     for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3117         s->nameRef.load(s->name);
3118
3119         for (int jj = 0; jj < s->parameterNames.count(); ++jj)
3120             s->parameterNamesRef[jj].load(s->parameterNames.at(jj).constData());
3121     }
3122
3123     // Now allocate class name
3124     classNameRef.load(newClassName);
3125
3126     obj->metadata = builder.toData();
3127     builder.fromData(&obj->extObject, obj->metatype, obj->metadata);
3128
3129     if (mode == IgnoreAliases && aliasCount) 
3130         compileState->aliasingObjects.append(obj);
3131
3132     obj->synthdata = dynamicData;
3133
3134     if (obj->synthCache) {
3135         obj->synthCache->release();
3136         obj->synthCache = 0;
3137     }
3138
3139     if (obj->type != -1) {
3140         QQmlPropertyCache *superCache = output->types[obj->type].createPropertyCache(engine);
3141         QQmlPropertyCache *cache =
3142             superCache->copyAndAppend(engine, &obj->extObject,
3143                                       QQmlPropertyData::NoFlags,
3144                                       QQmlPropertyData::IsVMEFunction,
3145                                       QQmlPropertyData::IsVMESignal);
3146
3147         // now we modify the flags appropriately for var properties.
3148         int propertyOffset = obj->extObject.propertyOffset();
3149         QQmlPropertyData *currPropData = 0;
3150         for (int pvi = firstPropertyVarIndex; pvi < totalPropCount; ++pvi) {
3151             currPropData = cache->property(pvi + propertyOffset);
3152             currPropData->setFlags(currPropData->getFlags() | QQmlPropertyData::IsVMEProperty);
3153         }
3154
3155         obj->synthCache = cache;
3156     }
3157
3158     return true;
3159 }
3160
3161 bool QQmlCompiler::checkValidId(QQmlScript::Value *v, const QString &val)
3162 {
3163     if (val.isEmpty()) 
3164         COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
3165
3166     QChar ch = val.at(0);
3167     if (ch.isLetter() && !ch.isLower())
3168         COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
3169
3170     QChar u(QLatin1Char('_'));
3171     if (!ch.isLetter() && ch != u)
3172         COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
3173
3174     for (int ii = 1; ii < val.count(); ++ii) {
3175         ch = val.at(ii);
3176         if (!ch.isLetterOrNumber() && ch != u)
3177             COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
3178     }
3179
3180     if (enginePrivate->v8engine()->illegalNames().contains(val))
3181         COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
3182
3183     return true;
3184 }
3185
3186 #include <private/qqmljsparser_p.h>
3187
3188 static QStringList astNodeToStringList(QQmlJS::AST::Node *node)
3189 {
3190     if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) {
3191         QString name =
3192             static_cast<QQmlJS::AST::IdentifierExpression *>(node)->name.toString();
3193         return QStringList() << name;
3194     } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) {
3195         QQmlJS::AST::FieldMemberExpression *expr = static_cast<QQmlJS::AST::FieldMemberExpression *>(node);
3196
3197         QStringList rv = astNodeToStringList(expr->base);
3198         if (rv.isEmpty())
3199             return rv;
3200         rv.append(expr->name.toString());
3201         return rv;
3202     }
3203     return QStringList();
3204 }
3205
3206 bool QQmlCompiler::compileAlias(QFastMetaBuilder &builder,
3207                                         QByteArray &data,
3208                                         QQmlScript::Object *obj,
3209                                         int propIndex, int aliasIndex,
3210                                         Object::DynamicProperty &prop)
3211 {
3212     Q_ASSERT(!prop.nameRef.isEmpty());
3213     if (!prop.defaultValue)
3214         COMPILE_EXCEPTION(obj, tr("No property alias location"));
3215
3216     if (!prop.defaultValue->values.isOne() ||
3217         prop.defaultValue->values.first()->object ||
3218         !prop.defaultValue->values.first()->value.isScript())
3219         COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3220
3221     QQmlJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST();
3222     if (!node)
3223         COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
3224
3225     QStringList alias = astNodeToStringList(node);
3226
3227     if (alias.count() < 1 || alias.count() > 3)
3228         COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
3229
3230     QQmlScript::Object *idObject = compileState->ids.value(alias.at(0));
3231     if (!idObject)
3232         COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
3233
3234     QByteArray typeName;
3235
3236     int propIdx = -1;
3237     int flags = 0;
3238     int type = 0;
3239     bool writable = false;
3240     bool resettable = false;
3241     if (alias.count() == 2 || alias.count() == 3) {
3242         propIdx = indexOfProperty(idObject, alias.at(1));
3243
3244         if (-1 == propIdx) {
3245             COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3246         } else if (propIdx > 0xFFFF) {
3247             COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
3248         }
3249
3250         QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
3251         if (!aliasProperty.isScriptable())
3252             COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3253
3254         writable = aliasProperty.isWritable() && !prop.isReadOnly;
3255         resettable = aliasProperty.isResettable() && !prop.isReadOnly;
3256
3257         type = aliasProperty.userType();
3258
3259         if (alias.count() == 3) {
3260             QQmlValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
3261             if (!valueType)
3262                 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3263
3264             propIdx |= ((unsigned int)aliasProperty.type()) << 24;
3265
3266             int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
3267             if (valueTypeIndex == -1)
3268                 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3269             Q_ASSERT(valueTypeIndex <= 0xFF);
3270             
3271             aliasProperty = valueType->metaObject()->property(valueTypeIndex);
3272             propIdx |= (valueTypeIndex << 16);
3273
3274             // update the property type
3275             type = aliasProperty.userType();
3276         }
3277
3278         if (aliasProperty.isEnumType()) 
3279             typeName = "int";  // Avoid introducing a dependency on the aliased metaobject
3280         else
3281             typeName = aliasProperty.typeName();
3282     } else {
3283         Q_ASSERT(idObject->type != -1); // How else did it get an id?
3284
3285         const QQmlCompiledData::TypeReference &ref = output->types.at(idObject->type);
3286         if (ref.type)
3287             typeName = ref.type->typeName();
3288         else
3289             typeName = ref.component->root->className();
3290
3291         typeName += '*';
3292     }
3293
3294     if (typeName.endsWith('*'))
3295         flags |= QML_ALIAS_FLAG_PTR;
3296
3297     if (type == QMetaType::UnknownType) {
3298         Q_ASSERT(!typeName.isEmpty());
3299         type = QMetaType::type(typeName);
3300         Q_ASSERT(type != QMetaType::UnknownType);
3301         Q_ASSERT(type != QMetaType::Void);
3302     }
3303
3304     QQmlVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags };
3305
3306     typedef QQmlVMEMetaData VMD;
3307     VMD *vmd = (QQmlVMEMetaData *)data.data();
3308     *(vmd->aliasData() + aliasIndex) = aliasData;
3309
3310     int propertyFlags = 0;
3311     if (writable)
3312         propertyFlags |= QFastMetaBuilder::Writable;
3313     if (resettable)
3314         propertyFlags |= QFastMetaBuilder::Resettable;
3315
3316     builder.setProperty(propIndex, prop.nameRef, type,
3317                         (QFastMetaBuilder::PropertyFlag)propertyFlags,
3318                         propIndex);
3319
3320     return true;
3321 }
3322
3323 bool QQmlCompiler::buildBinding(QQmlScript::Value *value,
3324                                         QQmlScript::Property *prop,
3325                                         const BindingContext &ctxt)
3326 {
3327     Q_ASSERT(prop->index != -1);
3328     Q_ASSERT(prop->parent);
3329     Q_ASSERT(prop->parent->metaObject());
3330
3331     if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
3332         COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3333
3334     JSBindingReference *reference = pool->New<JSBindingReference>();
3335     reference->expression = value->value;
3336     reference->property = prop;
3337     reference->value = value;
3338     reference->bindingContext = ctxt;
3339     addBindingReference(reference);
3340
3341     return true;
3342 }
3343
3344 bool QQmlCompiler::buildLiteralBinding(QQmlScript::Value *v,
3345                                                QQmlScript::Property *prop,
3346                                                const QQmlCompilerTypes::BindingContext &)
3347 {
3348     Q_ASSERT(v->value.isScript());
3349
3350     if (!prop->core.isWritable())
3351         return false;
3352
3353     AST::Node *binding = v->value.asAST();
3354
3355     if (prop->type == QVariant::String) {
3356         if (AST::CallExpression *e = AST::cast<AST::CallExpression *>(binding)) {
3357             if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(e->base)) {
3358                 if (i->name == qsTrId_string) {
3359                     AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3360                     AST::ArgumentList *arg2 = arg1?arg1->next:0;
3361
3362                     if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3363                         (!arg2 || arg2->expression->kind == AST::Node::Kind_NumericLiteral) &&
3364                         (!arg2 || !arg2->next)) {
3365
3366                         QStringRef text;
3367                         int n = -1;
3368
3369                         text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3370                         if (arg2) n = (int)AST::cast<AST::NumericLiteral *>(arg2->expression)->value;
3371
3372                         TrBindingReference *reference = pool->New<TrBindingReference>();
3373                         reference->dataType = BindingReference::TrId;
3374                         reference->text = text;
3375                         reference->n = n;
3376                         v->bindingReference = reference;
3377                         return true;
3378                     }
3379
3380                 } else if (i->name == qsTr_string) {
3381
3382                     AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3383                     AST::ArgumentList *arg2 = arg1?arg1->next:0;
3384                     AST::ArgumentList *arg3 = arg2?arg2->next:0;
3385
3386                     if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3387                         (!arg2 || arg2->expression->kind == AST::Node::Kind_StringLiteral) &&
3388                         (!arg3 || arg3->expression->kind == AST::Node::Kind_NumericLiteral) &&
3389                         (!arg3 || !arg3->next)) {
3390
3391                         QStringRef text;
3392                         QStringRef comment;
3393                         int n = -1;
3394
3395                         text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3396                         if (arg2) comment = AST::cast<AST::StringLiteral *>(arg2->expression)->value;
3397                         if (arg3) n = (int)AST::cast<AST::NumericLiteral *>(arg3->expression)->value;
3398
3399                         TrBindingReference *reference = pool->New<TrBindingReference>();
3400                         reference->dataType = BindingReference::Tr;
3401                         reference->text = text;
3402                         reference->comment = comment;
3403                         reference->n = n;
3404                         v->bindingReference = reference;
3405                         return true;
3406                     }
3407
3408                 }
3409             }
3410         }
3411
3412     }
3413
3414     return false;
3415 }
3416
3417 void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
3418                                                 QQmlScript::Property *prop,
3419                                                 QQmlScript::Object *obj,
3420                                                 QQmlScript::Property *valueTypeProperty)
3421 {
3422     Q_UNUSED(obj);
3423     Q_ASSERT(binding->bindingReference);
3424
3425     const BindingReference &ref = *binding->bindingReference;
3426     if (ref.dataType == BindingReference::TrId) {
3427         const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3428
3429         Instruction::StoreTrIdString store;
3430         store.propertyIndex = prop->core.coreIndex;
3431         store.text = output->indexForByteArray(tr.text.toUtf8());
3432         store.n = tr.n;
3433         output->addInstruction(store);
3434     } else if (ref.dataType == BindingReference::Tr) {
3435         const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3436
3437         Instruction::StoreTrString store;
3438         store.propertyIndex = prop->core.coreIndex;
3439         store.context = translationContextIndex();
3440         store.text = output->indexForByteArray(tr.text.toUtf8());
3441         store.comment = output->indexForByteArray(tr.comment.toUtf8());
3442         store.n = tr.n;
3443         output->addInstruction(store);
3444     } else if (ref.dataType == BindingReference::V4) {
3445         const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3446
3447         Instruction::StoreV4Binding store;
3448         store.value = js.compiledIndex;
3449         store.context = js.bindingContext.stack;
3450         store.owner = js.bindingContext.owner;
3451         if (valueTypeProperty) {
3452             store.property = (valueTypeProperty->index & 0xFFFF) |
3453                              ((valueTypeProperty->type & 0xFF)) << 16 |
3454                              ((prop->index & 0xFF) << 24);
3455             store.isRoot = (compileState->root == valueTypeProperty->parent);
3456         } else {
3457             store.property = prop->index;
3458             store.isRoot = (compileState->root == obj);
3459         }
3460         store.line = binding->location.start.line;
3461         store.column = binding->location.start.column;
3462         output->addInstruction(store);
3463     } else if (ref.dataType == BindingReference::V8) {
3464         const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3465
3466         Instruction::StoreV8Binding store;
3467         store.value = js.compiledIndex;
3468         store.context = js.bindingContext.stack;
3469         store.owner = js.bindingContext.owner;
3470         if (valueTypeProperty) {
3471             store.isRoot = (compileState->root == valueTypeProperty->parent);
3472         } else {
3473             store.isRoot = (compileState->root == obj);
3474         }
3475         store.line = binding->location.start.line;
3476         store.column = binding->location.start.column;
3477
3478         Q_ASSERT(js.bindingContext.owner == 0 ||
3479                  (js.bindingContext.owner != 0 && valueTypeProperty));
3480         if (js.bindingContext.owner) {
3481             store.property = genValueTypeData(prop, valueTypeProperty);
3482         } else {
3483             store.property = prop->core;
3484         }
3485
3486         output->addInstruction(store);
3487     } else if (ref.dataType == BindingReference::QtScript) {
3488         const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3489
3490         QQmlInstruction store;
3491         store.assignBinding.value = output->indexForString(js.rewrittenExpression);
3492         store.assignBinding.context = js.bindingContext.stack;
3493         store.assignBinding.owner = js.bindingContext.owner;
3494         store.assignBinding.line = binding->location.start.line;
3495         store.assignBinding.column = binding->location.start.column;
3496
3497         if (valueTypeProperty) {
3498             store.assignBinding.isRoot = (compileState->root == valueTypeProperty->parent);
3499         } else {
3500             store.assignBinding.isRoot = (compileState->root == obj);
3501         }
3502
3503         Q_ASSERT(js.bindingContext.owner == 0 ||
3504                  (js.bindingContext.owner != 0 && valueTypeProperty));
3505         if (js.bindingContext.owner) {
3506             store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
3507         } else {
3508             store.assignBinding.property = prop->core;
3509         }
3510         output->addInstructionHelper(
3511             !prop->isAlias ? QQmlInstruction::StoreBinding
3512                            : QQmlInstruction::StoreBindingOnAlias
3513             , store);
3514     } else {
3515         Q_ASSERT(!"Unhandled BindingReference::DataType type");
3516     }
3517 }
3518
3519 int QQmlCompiler::genContextCache()
3520 {
3521     if (compileState->ids.count() == 0)
3522         return -1;
3523
3524     QQmlIntegerCache *cache = new QQmlIntegerCache();
3525     cache->reserve(compileState->ids.count());
3526     for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o)) 
3527         cache->add(o->id, o->idIndex);
3528
3529     output->contextCaches.append(cache);
3530     return output->contextCaches.count() - 1;
3531 }
3532
3533 QQmlPropertyData
3534 QQmlCompiler::genValueTypeData(QQmlScript::Property *valueTypeProp, 
3535                                        QQmlScript::Property *prop)
3536 {
3537     typedef QQmlPropertyPrivate QDPP;
3538     return QDPP::saveValueType(prop->parent->metaObject(), prop->index, 
3539                                enginePrivate->valueTypes[prop->type]->metaObject(), 
3540                                valueTypeProp->index, engine);
3541 }
3542
3543 bool QQmlCompiler::completeComponentBuild()
3544 {
3545     if (componentStats)
3546         componentStats->componentStat.ids = compileState->ids.count();
3547
3548     for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject; 
3549          aliasObject = compileState->aliasingObjects.next(aliasObject)) 
3550         COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
3551
3552     QV4Compiler::Expression expr(unit->imports());
3553     expr.component = compileState->root;
3554     expr.ids = &compileState->ids;
3555     expr.importCache = output->importCache;
3556
3557     QV4Compiler bindingCompiler;
3558
3559     QList<JSBindingReference*> sharedBindings;
3560
3561     for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3562
3563         JSBindingReference &binding = *b;
3564
3565         // ### We don't currently optimize for bindings on alias's - because 
3566         // of the solution to QTBUG-13719
3567         if (!binding.property->isAlias) {
3568             expr.context = binding.bindingContext.object;
3569             expr.property = binding.property;
3570             expr.expression = binding.expression;
3571
3572             int index = bindingCompiler.compile(expr, enginePrivate);
3573             if (index != -1) {
3574                 binding.dataType = BindingReference::V4;
3575                 binding.compiledIndex = index;
3576                 if (componentStats)
3577                     componentStats->componentStat.optimizedBindings.append(b->value->location);
3578                 continue;
3579             } 
3580         }
3581
3582         // Pre-rewrite the expression
3583         QString expression = binding.expression.asScript();
3584
3585         QQmlRewrite::RewriteBinding rewriteBinding;
3586         rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3587         bool isSharable = false;
3588         binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3589
3590         if (isSharable && !binding.property->isAlias /* See above re alias */ &&
3591             binding.property->type != qMetaTypeId<QQmlBinding*>()) {
3592             binding.dataType = BindingReference::V8;
3593             sharedBindings.append(b);
3594
3595             if (componentStats)
3596                 componentStats->componentStat.sharedBindings.append(b->value->location);
3597         } else {
3598             binding.dataType = BindingReference::QtScript;
3599
3600             if (componentStats)
3601                 componentStats->componentStat.scriptBindings.append(b->value->location);
3602         }
3603     }
3604
3605     if (!sharedBindings.isEmpty()) {
3606         struct Sort {
3607             static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs)
3608             {
3609                 return lhs->value->location.start.line < rhs->value->location.start.line;
3610             }
3611         };
3612
3613         qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3614
3615         int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3616         int lineNumber = startLineNumber;
3617
3618         QByteArray functionArray("[", 1);
3619         for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3620
3621             JSBindingReference *reference = sharedBindings.at(ii);
3622             QQmlScript::Value *value = reference->value;
3623             const QString &expression = reference->rewrittenExpression;
3624
3625             if (ii != 0) functionArray.append(",", 1);
3626
3627             while (lineNumber < value->location.start.line) {
3628                 lineNumber++;
3629                 functionArray.append("\n", 1);
3630             }
3631
3632             functionArray += expression.toUtf8();
3633             lineNumber += expression.count(QLatin1Char('\n'));
3634             reference->compiledIndex = ii;
3635         }
3636         functionArray.append("]", 1);
3637
3638         compileState->v8BindingProgram = functionArray;
3639         compileState->v8BindingProgramLine = startLineNumber;
3640     }
3641
3642     if (bindingCompiler.isValid()) 
3643         compileState->compiledBindingData = bindingCompiler.program();
3644
3645     // Check pop()'s matched push()'s
3646     Q_ASSERT(compileState->objectDepth.depth() == 0);
3647     Q_ASSERT(compileState->listDepth.depth() == 0);
3648
3649     saveComponentState();
3650
3651     return true;
3652 }
3653
3654 void QQmlCompiler::dumpStats()
3655 {
3656     Q_ASSERT(componentStats);
3657     qWarning().nospace() << "QML Document: " << output->url.toString();
3658     for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3659         const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3660         qWarning().nospace() << "    Component Line " << stat.lineNumber;
3661         qWarning().nospace() << "        Total Objects:      " << stat.objects;
3662         qWarning().nospace() << "        IDs Used:           " << stat.ids;
3663         qWarning().nospace() << "        Optimized Bindings: " << stat.optimizedBindings.count();
3664
3665         {
3666         QByteArray output;
3667         for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3668             if (0 == (ii % 10)) {
3669                 if (ii) output.append("\n");
3670                 output.append("            ");
3671             }
3672
3673             output.append("(");
3674             output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3675             output.append(":");
3676             output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3677             output.append(") ");
3678         }
3679         if (!output.isEmpty())
3680             qWarning().nospace() << output.constData();
3681         }
3682
3683         qWarning().nospace() << "        Shared Bindings:    " << stat.sharedBindings.count();
3684         {
3685         QByteArray output;
3686         for (int ii = 0; ii < stat.sharedBindings.count(); ++ii) {
3687             if (0 == (ii % 10)) {
3688                 if (ii) output.append("\n");
3689                 output.append("            ");
3690             }
3691
3692             output.append("(");
3693             output.append(QByteArray::number(stat.sharedBindings.at(ii).start.line));
3694             output.append(":");
3695             output.append(QByteArray::number(stat.sharedBindings.at(ii).start.column));
3696             output.append(") ");
3697         }
3698         if (!output.isEmpty())
3699             qWarning().nospace() << output.constData();
3700         }
3701
3702         qWarning().nospace() << "        QScript Bindings:   " << stat.scriptBindings.count();
3703         {
3704         QByteArray output;
3705         for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3706             if (0 == (ii % 10)) {
3707                 if (ii) output.append("\n");
3708                 output.append("            ");
3709             }
3710
3711             output.append("(");
3712             output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3713             output.append(":");
3714             output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3715             output.append(") ");
3716         }
3717         if (!output.isEmpty())
3718             qWarning().nospace() << output.constData();
3719         }
3720     }
3721 }
3722
3723 /*!
3724     Returns true if from can be assigned to a (QObject) property of type
3725     to.
3726 */
3727 bool QQmlCompiler::canCoerce(int to, QQmlScript::Object *from)
3728 {
3729     const QMetaObject *toMo = enginePrivate->rawMetaObjectForType(to);
3730     const QMetaObject *fromMo = from->metaObject();
3731
3732     while (fromMo) {
3733         if (QQmlPropertyPrivate::equal(fromMo, toMo))
3734             return true;
3735         fromMo = fromMo->superClass();
3736     }
3737     return false;
3738 }
3739
3740 /*!
3741     Returns the element name, as written in the QML file, for o.
3742 */
3743 QString QQmlCompiler::elementName(QQmlScript::Object *o)
3744 {
3745     Q_ASSERT(o);
3746     if (o->type != -1) {
3747         return output->types.at(o->type).className;
3748     } else {
3749         return QString();
3750     }
3751 }
3752
3753 QQmlType *QQmlCompiler::toQmlType(QQmlScript::Object *from)
3754 {
3755     // ### Optimize
3756     const QMetaObject *mo = from->metatype;
3757     QQmlType *type = 0;
3758     while (!type && mo) {
3759         type = QQmlMetaType::qmlType(mo);
3760         mo = mo->superClass();
3761     }
3762    return type;
3763 }
3764
3765 QStringList QQmlCompiler::deferredProperties(QQmlScript::Object *obj)
3766 {
3767     const QMetaObject *mo = obj->metatype;
3768
3769     int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3770     if (idx == -1)
3771         return QStringList();
3772
3773     QMetaClassInfo classInfo = mo->classInfo(idx);
3774     QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3775     return rv;
3776 }
3777
3778 QQmlPropertyData *
3779 QQmlCompiler::property(QQmlScript::Object *object, int index)
3780 {
3781     QQmlPropertyCache *cache = 0;
3782
3783     if (object->synthCache)
3784         cache = object->synthCache;
3785     else if (object->type != -1)
3786         cache = output->types[object->type].createPropertyCache(engine);
3787     else
3788         cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3789
3790     return cache->property(index);
3791 }
3792
3793 QQmlPropertyData *
3794 QQmlCompiler::property(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3795 {
3796     if (notInRevision) *notInRevision = false;
3797
3798     QQmlPropertyCache *cache = 0;
3799
3800     if (object->synthCache)
3801         cache = object->synthCache;
3802     else if (object->type != -1)
3803         cache = output->types[object->type].createPropertyCache(engine);
3804     else
3805         cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3806
3807     QQmlPropertyData *d = cache->property(name);
3808
3809     // Find the first property
3810     while (d && d->isFunction())
3811         d = cache->overrideData(d);
3812
3813     if (d && !cache->isAllowedInRevision(d)) {
3814         if (notInRevision) *notInRevision = true;
3815         return 0;
3816     } else {
3817         return d;
3818     }
3819 }
3820
3821 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3822 QQmlPropertyData *
3823 QQmlCompiler::signal(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3824 {
3825     if (notInRevision) *notInRevision = false;
3826
3827     QQmlPropertyCache *cache = 0;
3828
3829     if (object->synthCache)
3830         cache = object->synthCache;
3831     else if (object->type != -1)
3832         cache = output->types[object->type].createPropertyCache(engine);
3833     else
3834         cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
3835
3836
3837     QQmlPropertyData *d = cache->property(name);
3838     if (notInRevision) *notInRevision = false;
3839
3840     while (d && !(d->isFunction()))
3841         d = cache->overrideData(d);
3842
3843     if (d && !cache->isAllowedInRevision(d)) {
3844         if (notInRevision) *notInRevision = true;
3845         return 0;
3846     } else if (d) {
3847         return d;
3848     }
3849
3850     if (name.endsWith(Changed_string)) {
3851         QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3852
3853         d = property(object, propName, notInRevision);
3854         if (d) 
3855             return cache->method(d->notifyIndex);
3856     }
3857
3858     return 0;
3859 }
3860
3861 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3862 int QQmlCompiler::indexOfSignal(QQmlScript::Object *object, const QString &name, 
3863                                         bool *notInRevision)
3864 {
3865     QQmlPropertyData *d = signal(object, QStringRef(&name), notInRevision);
3866     return d?d->coreIndex:-1;
3867 }
3868
3869 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QString &name, 
3870                                           bool *notInRevision)
3871 {
3872     return indexOfProperty(object, QStringRef(&name), notInRevision);
3873 }
3874
3875 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QHashedStringRef &name, 
3876                                           bool *notInRevision)
3877 {
3878     QQmlPropertyData *d = property(object, name, notInRevision);
3879     return d?d->coreIndex:-1;
3880 }
3881
3882 QT_END_NAMESPACE