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