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