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