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