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