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