Use V4 binding for non-final properties where possible
[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     genPropertyAssignment(prop, obj);
1418 }
1419
1420 void QQmlCompiler::genComponent(QQmlScript::Object *obj)
1421 {
1422     QQmlScript::Object *root = obj->defaultProperty->values.first()->object;
1423     Q_ASSERT(root);
1424
1425     Instruction::CreateComponent create;
1426     create.line = root->location.start.line;
1427     create.column = root->location.start.column;
1428     create.endLine = root->location.end.line;
1429     create.isRoot = (compileState->root == obj);
1430     int createInstruction = output->addInstruction(create);
1431     int nextInstructionIndex = output->nextInstructionIndex();
1432
1433     ComponentCompileState *oldCompileState = compileState;
1434     compileState = componentState(root);
1435
1436     Instruction::Init init;
1437     init.bindingsSize = compileState->totalBindingsCount;
1438     init.parserStatusSize = compileState->parserStatusCount;
1439     init.contextCache = genContextCache();
1440     init.objectStackSize = compileState->objectDepth.maxDepth();
1441     init.listStackSize = compileState->listDepth.maxDepth();
1442     if (compileState->compiledBindingData.isEmpty())
1443         init.compiledBinding = -1;
1444     else
1445         init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
1446     output->addInstruction(init);
1447
1448     if (!compileState->v8BindingProgram.isEmpty()) {
1449         Instruction::InitV8Bindings bindings;
1450         int index = output->programs.count();
1451
1452         typedef QQmlCompiledData::V8Program V8Program;
1453         output->programs.append(V8Program(compileState->v8BindingProgram, output));
1454
1455         bindings.programIndex = index;
1456         bindings.line = compileState->v8BindingProgramLine;
1457         output->addInstruction(bindings);
1458     }
1459
1460     genObject(root);
1461
1462     Instruction::SetDefault def;
1463     output->addInstruction(def);
1464
1465     Instruction::Done done;
1466     output->addInstruction(done);
1467
1468     output->instruction(createInstruction)->createComponent.count = 
1469         output->nextInstructionIndex() - nextInstructionIndex;
1470
1471     compileState = oldCompileState;
1472
1473     if (!obj->id.isEmpty()) {
1474         Instruction::SetId id;
1475         id.value = output->indexForString(obj->id);
1476         id.index = obj->idIndex;
1477         output->addInstruction(id);
1478     }
1479
1480     if (obj == unitRoot) {
1481         output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1482         output->rootPropertyCache->addref();
1483     }
1484 }
1485
1486 bool QQmlCompiler::buildComponent(QQmlScript::Object *obj,
1487                                  const BindingContext &ctxt)
1488 {
1489     // The special "Component" element can only have the id property and a
1490     // default property, that actually defines the component's tree
1491
1492     compileState->objectDepth.push();
1493
1494     // Find, check and set the "id" property (if any)
1495     Property *idProp = 0;
1496     if (obj->properties.isMany() ||
1497        (obj->properties.isOne() && obj->properties.first()->name() != id_string))
1498         COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
1499        
1500     if (!obj->properties.isEmpty())
1501         idProp = obj->properties.first();
1502
1503     if (idProp) {
1504        if (idProp->value || idProp->values.isMany() || idProp->values.first()->object) 
1505            COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1506        COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1507
1508         QString idVal = idProp->values.first()->primitive();
1509
1510         if (compileState->ids.value(idVal))
1511             COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1512
1513         obj->id = idVal;
1514         addId(idVal, obj);
1515     }
1516
1517     // Check the Component tree is well formed
1518     if (obj->defaultProperty &&
1519        (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
1520         (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
1521         COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1522
1523     if (!obj->dynamicProperties.isEmpty())
1524         COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1525     if (!obj->dynamicSignals.isEmpty())
1526         COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1527     if (!obj->dynamicSlots.isEmpty())
1528         COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1529
1530     QQmlScript::Object *root = 0;
1531     if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
1532         root = obj->defaultProperty->values.first()->object;
1533
1534     if (!root)
1535         COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1536
1537     // Build the component tree
1538     COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1539
1540     compileState->objectDepth.pop();
1541
1542     return true;
1543 }
1544
1545 bool QQmlCompiler::buildComponentFromRoot(QQmlScript::Object *obj,
1546                                          const BindingContext &ctxt)
1547 {
1548     ComponentCompileState *oldComponentCompileState = compileState;
1549     compileState = pool->New<ComponentCompileState>();
1550     compileState->root = obj;
1551     compileState->nested = true;
1552
1553     if (componentStats) {
1554         ComponentStat oldComponentStat = componentStats->componentStat;
1555
1556         componentStats->componentStat = ComponentStat();
1557         componentStats->componentStat.lineNumber = obj->location.start.line;
1558
1559         if (obj)
1560             COMPILE_CHECK(buildObject(obj, ctxt));
1561
1562         COMPILE_CHECK(completeComponentBuild());
1563
1564         componentStats->componentStat = oldComponentStat;
1565     } else {
1566         if (obj)
1567             COMPILE_CHECK(buildObject(obj, ctxt));
1568
1569         COMPILE_CHECK(completeComponentBuild());
1570     }
1571
1572     compileState = oldComponentCompileState;
1573
1574     return true;
1575 }
1576
1577
1578 // Build a sub-object.  A sub-object is one that was not created directly by
1579 // QML - such as a grouped property object, or an attached object.  Sub-object's
1580 // can't have an id, involve a custom parser, have attached properties etc.
1581 bool QQmlCompiler::buildSubObject(QQmlScript::Object *obj, const BindingContext &ctxt)
1582 {
1583     Q_ASSERT(obj->metatype);
1584     Q_ASSERT(!obj->defaultProperty);
1585     Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1586                                    // sub-context
1587
1588     for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1589         if (isSignalPropertyName(prop->name())) {
1590             COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1591         } else {
1592             COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1593         }
1594     }
1595
1596     return true;
1597 }
1598
1599 int QQmlCompiler::componentTypeRef()
1600 {
1601     if (cachedComponentTypeRef == -1) {
1602         QQmlType *t = QQmlMetaType::qmlType(Component_string, Component_module_string, 1, 0);
1603         for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1604             if (output->types.at(ii).type == t) {
1605                 cachedComponentTypeRef = ii;
1606                 return ii;
1607             }
1608         }
1609         QQmlCompiledData::TypeReference ref;
1610         ref.type = t;
1611         output->types << ref;
1612         cachedComponentTypeRef = output->types.count() - 1;
1613     }
1614     return cachedComponentTypeRef;
1615 }
1616
1617 int QQmlCompiler::translationContextIndex()
1618 {
1619     if (cachedTranslationContextIndex == -1) {
1620         // This code must match that in the qsTr() implementation
1621         const QString &path = output->name;
1622         int lastSlash = path.lastIndexOf(QLatin1Char('/'));
1623         QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) :
1624                                              QString();
1625         QByteArray contextUtf8 = context.toUtf8();
1626         cachedTranslationContextIndex = output->indexForByteArray(contextUtf8);
1627     }
1628     return cachedTranslationContextIndex;
1629 }
1630
1631 bool QQmlCompiler::buildSignal(QQmlScript::Property *prop, QQmlScript::Object *obj,
1632                                        const BindingContext &ctxt)
1633 {
1634     Q_ASSERT(obj->metatype);
1635
1636     const QHashedStringRef &propName = prop->name();
1637
1638     Q_ASSERT(propName.startsWith(on_string));
1639     QString name = propName.mid(2, -1).toString();
1640
1641     // Note that the property name could start with any alpha or '_' or '$' character,
1642     // so we need to do the lower-casing of the first alpha character.
1643     for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1644         if (name.at(firstAlphaIndex).isUpper()) {
1645             name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1646             break;
1647         }
1648     }
1649
1650     bool notInRevision = false;
1651
1652     QQmlPropertyData *sig = signal(obj, QStringRef(&name), &notInRevision);
1653
1654     if (sig == 0) {
1655
1656         if (notInRevision && 0 == property(obj, propName, 0)) {
1657             Q_ASSERT(obj->type != -1);
1658             const QList<QQmlTypeData::TypeReference>  &resolvedTypes = unit->resolvedTypes();
1659             const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1660             if (type.type) {
1661                 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));
1662             } else {
1663                 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1664             }
1665         }
1666
1667         // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1668         // property.
1669         COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1670
1671     }  else {
1672
1673         if (prop->value || !prop->values.isOne())
1674             COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1675
1676         prop->index = propertyCacheForObject(obj)->methodIndexToSignalIndex(sig->coreIndex);
1677         prop->core = *sig;
1678
1679         obj->addSignalProperty(prop);
1680
1681         if (prop->values.first()->object) {
1682             COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1683             prop->values.first()->type = Value::SignalObject;
1684         } else {
1685             prop->values.first()->type = Value::SignalExpression;
1686
1687             if (!prop->values.first()->value.isScript())
1688                 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1689
1690             QString script = prop->values.first()->value.asScript().trimmed();
1691             if (script.isEmpty())
1692                 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1693
1694             prop->values.first()->signalExpressionContextStack = ctxt.stack;
1695         }
1696     }
1697
1698     return true;
1699 }
1700
1701
1702 /*!
1703     Returns true if (value) property \a prop exists on obj, false otherwise.
1704 */
1705 bool QQmlCompiler::doesPropertyExist(QQmlScript::Property *prop,
1706                                              QQmlScript::Object *obj)
1707 {
1708     if (prop->name().isEmpty())
1709         return false;
1710     if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1711         return true;
1712
1713     return property(obj, prop->name()) != 0;
1714 }
1715
1716 bool QQmlCompiler::buildProperty(QQmlScript::Property *prop,
1717                                          QQmlScript::Object *obj,
1718                                          const BindingContext &ctxt)
1719 {
1720     if (prop->isEmpty()) 
1721         COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1722
1723     if (isAttachedPropertyName(prop->name())) {
1724         // Setup attached property data
1725
1726         if (ctxt.isSubContext()) {
1727             // Attached properties cannot be used on sub-objects.  Sub-objects
1728             // always exist in a binding sub-context, which is what we test
1729             // for here.
1730             COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1731         }
1732
1733         QQmlType *type = 0;
1734         QQmlImportNamespace *typeNamespace = 0;
1735         unit->imports().resolveType(prop->name(), &type, 0, 0, 0, &typeNamespace);
1736
1737         if (typeNamespace) {
1738             COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj, 
1739                                                    ctxt));
1740             return true;
1741         } else if (!type || !type->attachedPropertiesType())  {
1742             COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1743         }
1744
1745         if (!prop->value)
1746             COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1747
1748         Q_ASSERT(type->attachedPropertiesFunction());
1749         prop->index = type->attachedPropertiesId();
1750         prop->value->metatype = enginePrivate->cache(type->attachedPropertiesType());
1751     } else {
1752         // Setup regular property data
1753         bool notInRevision = false;
1754         QQmlPropertyData *d =
1755             prop->name().isEmpty()?0:property(obj, prop->name(), &notInRevision);
1756
1757         if (d == 0 && notInRevision) {
1758             const QList<QQmlTypeData::TypeReference>  &resolvedTypes = unit->resolvedTypes();
1759             const QQmlTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1760             if (type.type) {
1761                 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));
1762             } else {
1763                 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1764             }
1765         } else if (d) {
1766             prop->index = d->coreIndex;
1767             prop->core = *d;
1768         } else if (prop->isDefault) {
1769             QString defaultPropertyName = obj->metatype->defaultPropertyName();
1770
1771             if (!defaultPropertyName.isEmpty()) {
1772                 prop->setName(defaultPropertyName);
1773                 prop->core = *obj->metatype->defaultProperty();
1774                 prop->index = prop->core.coreIndex;
1775             }
1776         }
1777
1778         // We can't error here as the "id" property does not require a
1779         // successful index resolution
1780         if (prop->index != -1) 
1781             prop->type = prop->core.propType;
1782
1783         // Check if this is an alias
1784         if (prop->index != -1 && 
1785             prop->parent && 
1786             prop->parent->type != -1 && 
1787             output->types.at(prop->parent->type).component) {
1788
1789             QQmlPropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1790             if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1791                 prop->isAlias = true;
1792         }
1793
1794         if (prop->index != -1 && !prop->values.isEmpty()) 
1795             prop->parent->setBindingBit(prop->index);
1796     }
1797
1798     if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1799
1800         // The magic "id" behavior doesn't apply when "id" is resolved as a
1801         // default property or to sub-objects (which are always in binding
1802         // sub-contexts)
1803         COMPILE_CHECK(buildIdProperty(prop, obj));
1804         if (prop->type == QVariant::String &&
1805             prop->values.first()->value.isString())
1806             COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1807
1808     } else if (isAttachedPropertyName(prop->name())) {
1809
1810         COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1811
1812     } else if (prop->index == -1) {
1813
1814         if (prop->isDefault) {
1815             COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1816         } else {
1817             COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1818         }
1819
1820     } else if (prop->value) {
1821
1822         COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1823
1824     } else if (prop->core.isQList()) {
1825
1826         COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1827
1828     } else if (prop->type == qMetaTypeId<QQmlScriptString>()) {
1829
1830         COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1831
1832     } else {
1833
1834         COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1835
1836     }
1837
1838     return true;
1839 }
1840
1841 bool QQmlCompiler::buildPropertyInNamespace(QQmlImportNamespace *ns,
1842                                             QQmlScript::Property *nsProp,
1843                                             QQmlScript::Object *obj,
1844                                             const BindingContext &ctxt)
1845 {
1846     if (!nsProp->value)
1847         COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1848
1849     for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1850
1851         if (!isAttachedPropertyName(prop->name()))
1852             COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1853
1854         // Setup attached property data
1855
1856         QQmlType *type = 0;
1857         unit->imports().resolveType(ns, prop->name(), &type, 0, 0, 0);
1858
1859         if (!type || !type->attachedPropertiesType()) 
1860             COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1861
1862         if (!prop->value)
1863             COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1864
1865         Q_ASSERT(type->attachedPropertiesFunction());
1866         prop->index = type->index();
1867         prop->value->metatype = enginePrivate->cache(type->attachedPropertiesType());
1868
1869         COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1870     }
1871
1872     return true;
1873 }
1874
1875 void QQmlCompiler::genValueProperty(QQmlScript::Property *prop,
1876                                    QQmlScript::Object *obj)
1877 {
1878     if (prop->core.isQList()) {
1879         genListProperty(prop, obj);
1880     } else {
1881         genPropertyAssignment(prop, obj);
1882     }
1883 }
1884
1885 void QQmlCompiler::genListProperty(QQmlScript::Property *prop,
1886                                   QQmlScript::Object *obj)
1887 {
1888     int listType = enginePrivate->listType(prop->type);
1889
1890     Instruction::FetchQList fetch;
1891     fetch.property = prop->index;
1892     bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
1893     fetch.type = listType;
1894     output->addInstruction(fetch);
1895
1896     for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1897
1898         if (v->type == Value::CreatedObject) {
1899
1900             genObject(v->object);
1901             if (listTypeIsInterface) {
1902                 Instruction::AssignObjectList assign;
1903                 assign.line = prop->location.start.line;
1904                 output->addInstruction(assign);
1905             } else {
1906                 Instruction::StoreObjectQList store;
1907                 output->addInstruction(store);
1908             }
1909
1910         } else if (v->type == Value::PropertyBinding) {
1911
1912             genBindingAssignment(v, prop, obj);
1913
1914         }
1915
1916     }
1917
1918     Instruction::PopQList pop;
1919     output->addInstruction(pop);
1920 }
1921
1922 void QQmlCompiler::genPropertyAssignment(QQmlScript::Property *prop,
1923                                         QQmlScript::Object *obj,
1924                                         QQmlScript::Property *valueTypeProperty)
1925 {
1926     for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1927
1928         Q_ASSERT(v->type == Value::CreatedObject ||
1929                  v->type == Value::PropertyBinding ||
1930                  v->type == Value::Literal);
1931
1932         if (v->type == Value::CreatedObject) {
1933
1934             genObject(v->object);
1935
1936             if (QQmlMetaType::isInterface(prop->type)) {
1937
1938                 Instruction::StoreInterface store;
1939                 store.line = v->object->location.start.line;
1940                 store.propertyIndex = prop->index;
1941                 output->addInstruction(store);
1942
1943             } else if (prop->type == QMetaType::QVariant) {
1944
1945                 if (prop->core.isVarProperty()) {
1946                     Instruction::StoreVarObject store;
1947                     store.line = v->object->location.start.line;
1948                     store.propertyIndex = prop->index;
1949                     output->addInstruction(store);
1950                 } else {
1951                     Instruction::StoreVariantObject store;
1952                     store.line = v->object->location.start.line;
1953                     store.propertyIndex = prop->index;
1954                     output->addInstruction(store);
1955                 }
1956
1957
1958             } else {
1959
1960                 Instruction::StoreObject store;
1961                 store.line = v->object->location.start.line;
1962                 store.propertyIndex = prop->index;
1963                 output->addInstruction(store);
1964
1965             }
1966         } else if (v->type == Value::PropertyBinding) {
1967
1968             genBindingAssignment(v, prop, obj, valueTypeProperty);
1969
1970         } else if (v->type == Value::Literal) {
1971
1972             genLiteralAssignment(prop, v);
1973
1974         }
1975
1976     }
1977
1978     for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
1979
1980         Q_ASSERT(v->type == Value::ValueSource ||
1981                  v->type == Value::ValueInterceptor);
1982
1983         if (v->type == Value::ValueSource) {
1984             genObject(v->object, valueTypeProperty?true:false);
1985
1986             Instruction::StoreValueSource store;
1987             if (valueTypeProperty)
1988                 store.property = genValueTypeData(prop, valueTypeProperty);
1989             else
1990                 store.property = prop->core;
1991             QQmlType *valueType = toQmlType(v->object);
1992             store.castValue = valueType->propertyValueSourceCast();
1993             output->addInstruction(store);
1994
1995         } else if (v->type == Value::ValueInterceptor) {
1996             genObject(v->object, valueTypeProperty?true:false);
1997
1998             Instruction::StoreValueInterceptor store;
1999             if (valueTypeProperty)
2000                 store.property = genValueTypeData(prop, valueTypeProperty);
2001             else
2002                 store.property = prop->core;
2003             QQmlType *valueType = toQmlType(v->object);
2004             store.castValue = valueType->propertyValueInterceptorCast();
2005             output->addInstruction(store);
2006         }
2007
2008     }
2009 }
2010
2011 bool QQmlCompiler::buildIdProperty(QQmlScript::Property *prop,
2012                                   QQmlScript::Object *obj)
2013 {
2014     if (prop->value ||
2015         prop->values.isMany() ||
2016         prop->values.first()->object)
2017         COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
2018
2019     QQmlScript::Value *idValue = prop->values.first();
2020     QString val = idValue->primitive();
2021
2022     COMPILE_CHECK(checkValidId(idValue, val));
2023
2024     if (compileState->ids.value(val))
2025         COMPILE_EXCEPTION(prop, tr("id is not unique"));
2026
2027     prop->values.first()->type = Value::Id;
2028
2029     obj->id = val;
2030     addId(val, obj);
2031
2032     return true;
2033 }
2034
2035 void QQmlCompiler::addId(const QString &id, QQmlScript::Object *obj)
2036 {
2037     Q_UNUSED(id);
2038     Q_ASSERT(!compileState->ids.value(id));
2039     Q_ASSERT(obj->id == id);
2040     obj->idIndex = compileState->ids.count();
2041     compileState->ids.append(obj);
2042 }
2043
2044 void QQmlCompiler::addBindingReference(JSBindingReference *ref)
2045 {
2046     Q_ASSERT(ref->value && !ref->value->bindingReference);
2047     ref->value->bindingReference = ref;
2048     compileState->totalBindingsCount++;
2049     compileState->bindings.prepend(ref);
2050 }
2051
2052 void QQmlCompiler::saveComponentState()
2053 {
2054     Q_ASSERT(compileState->root);
2055     Q_ASSERT(compileState->root->componentCompileState == 0);
2056
2057     compileState->root->componentCompileState = compileState;
2058
2059     if (componentStats) 
2060         componentStats->savedComponentStats.append(componentStats->componentStat);
2061 }
2062
2063 QQmlCompilerTypes::ComponentCompileState *
2064 QQmlCompiler::componentState(QQmlScript::Object *obj)
2065 {
2066     Q_ASSERT(obj->componentCompileState);
2067     return obj->componentCompileState;
2068 }
2069
2070 // Build attached property object.  In this example,
2071 // Text {
2072 //    GridView.row: 10
2073 // }
2074 // GridView is an attached property object.
2075 bool QQmlCompiler::buildAttachedProperty(QQmlScript::Property *prop,
2076                                         QQmlScript::Object *obj,
2077                                         const BindingContext &ctxt)
2078 {
2079     Q_ASSERT(prop->value);
2080     Q_ASSERT(prop->index != -1); // This is set in buildProperty()
2081
2082     compileState->objectDepth.push();
2083
2084     obj->addAttachedProperty(prop);
2085
2086     COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2087
2088     compileState->objectDepth.pop();
2089
2090     return true;
2091 }
2092
2093
2094 // Build "grouped" properties. In this example:
2095 // Text {
2096 //     font.pointSize: 12
2097 //     font.family: "Helvetica"
2098 // }
2099 // font is a nested property.  pointSize and family are not.
2100 bool QQmlCompiler::buildGroupedProperty(QQmlScript::Property *prop,
2101                                                 QQmlScript::Object *obj,
2102                                                 const BindingContext &ctxt)
2103 {
2104     Q_ASSERT(prop->type != 0);
2105     Q_ASSERT(prop->index != -1);
2106
2107     if (QQmlValueTypeFactory::isValueType(prop->type)) {
2108         if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
2109
2110             if (!prop->values.isEmpty()) {
2111                 // Only error if we are assigning values, and not e.g. a property interceptor
2112                 for (Property *dotProp = prop->value->properties.first(); dotProp; dotProp = prop->value->properties.next(dotProp)) {
2113                     if (!dotProp->values.isEmpty()) {
2114                         if (prop->values.first()->location < prop->value->location) {
2115                             COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
2116                         } else {
2117                             COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
2118                         }
2119                     }
2120                 }
2121             }
2122
2123             if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) {
2124                 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2125             }
2126
2127             if (prop->isAlias) {
2128                 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
2129                     vtProp->isAlias = true;
2130                 }
2131             }
2132
2133             COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
2134                                                  prop->value, obj, ctxt.incr()));
2135
2136             // When building a value type where sub components are declared, this
2137             // code path is followed from buildProperty, even if there is a previous
2138             // assignment to the value type as a whole. Therefore we need to look
2139             // for (and build) assignments to the entire value type before looking
2140             // for any onValue assignments.
2141             for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2142                 if (v->object) {
2143                     COMPILE_EXCEPTION(v->object, tr("Objects cannot be assigned to value types"));
2144                 }
2145                 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2146             }
2147
2148             for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2149                 Q_ASSERT(v->object);
2150                 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2151             }
2152
2153             obj->addValueTypeProperty(prop);
2154
2155         } else {
2156             COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2157         }
2158
2159     } else {
2160         // Load the nested property's meta type
2161         prop->value->metatype = enginePrivate->propertyCacheForType(prop->type);
2162         if (!prop->value->metatype)
2163             COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2164
2165         if (!prop->values.isEmpty()) 
2166             COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
2167
2168         obj->addGroupedProperty(prop);
2169
2170         compileState->objectDepth.push();
2171
2172         COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2173
2174         compileState->objectDepth.pop();
2175     }
2176
2177     return true;
2178 }
2179
2180 bool QQmlCompiler::buildValueTypeProperty(QObject *type,
2181                                                   QQmlScript::Object *obj,
2182                                                   QQmlScript::Object *baseObj,
2183                                                   const BindingContext &ctxt)
2184 {
2185     compileState->objectDepth.push();
2186
2187     if (obj->defaultProperty)
2188         COMPILE_EXCEPTION(obj, tr("Invalid property use"));
2189     obj->metatype = enginePrivate->cache(type);
2190
2191     for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
2192
2193         QQmlPropertyData *d = property(obj, prop->name());
2194         if (d == 0) 
2195             COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
2196
2197         prop->index = d->coreIndex;
2198         prop->type = d->propType;
2199         prop->core = *d;
2200         prop->isValueTypeSubProperty = true;
2201
2202         if (prop->value)
2203             COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
2204
2205         if (prop->values.isMany()) {
2206             COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
2207         } else if (!prop->values.isEmpty()) {
2208             QQmlScript::Value *value = prop->values.first();
2209
2210             if (value->object) {
2211                 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
2212             } else if (value->value.isScript()) {
2213                 // ### Check for writability
2214
2215                 //optimization for <Type>.<EnumValue> enum assignments
2216                 bool isEnumAssignment = false;
2217
2218                 if (prop->core.isEnum() || prop->core.propType == QMetaType::Int)
2219                     COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, value, &isEnumAssignment));
2220
2221                 if (isEnumAssignment) {
2222                     value->type = Value::Literal;
2223                 } else {
2224                     JSBindingReference *reference = pool->New<JSBindingReference>();
2225                     reference->expression = value->value;
2226                     reference->property = prop;
2227                     reference->value = value;
2228                     reference->bindingContext = ctxt;
2229                     reference->bindingContext.owner++;
2230                     addBindingReference(reference);
2231                     value->type = Value::PropertyBinding;
2232                 }
2233             } else  {
2234                 COMPILE_CHECK(testLiteralAssignment(prop, value));
2235                 value->type = Value::Literal;
2236             }
2237         }
2238
2239         for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2240             Q_ASSERT(v->object);
2241
2242             COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt)); 
2243         }
2244
2245         obj->addValueProperty(prop);
2246     }
2247
2248     compileState->objectDepth.pop();
2249
2250     return true;
2251 }
2252
2253 // Build assignments to QML lists.  QML lists are properties of type
2254 // QQmlListProperty<T>.  List properties can accept a list of 
2255 // objects, or a single binding.
2256 bool QQmlCompiler::buildListProperty(QQmlScript::Property *prop,
2257                                              QQmlScript::Object *obj,
2258                                              const BindingContext &ctxt)
2259 {
2260     Q_ASSERT(prop->core.isQList());
2261
2262     compileState->listDepth.push();
2263
2264     int t = prop->type;
2265
2266     obj->addValueProperty(prop);
2267
2268     int listType = enginePrivate->listType(t);
2269     bool listTypeIsInterface = QQmlMetaType::isInterface(listType);
2270
2271     bool assignedBinding = false;
2272     for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2273         if (v->object) {
2274             v->type = Value::CreatedObject;
2275             COMPILE_CHECK(buildObject(v->object, ctxt));
2276
2277             // We check object coercian here.  We check interface assignment
2278             // at runtime.
2279             if (!listTypeIsInterface) {
2280                 if (!canCoerce(listType, v->object)) {
2281                     COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2282                 }
2283             }
2284
2285         } else if (v->value.isScript()) {
2286             if (assignedBinding)
2287                 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2288
2289             assignedBinding = true;
2290             COMPILE_CHECK(buildBinding(v, prop, ctxt));
2291             v->type = Value::PropertyBinding;
2292         } else {
2293             COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2294         }
2295     }
2296
2297     compileState->listDepth.pop();
2298
2299     return true;
2300 }
2301
2302 // Compiles an assignment to a QQmlScriptString property
2303 bool QQmlCompiler::buildScriptStringProperty(QQmlScript::Property *prop,
2304                                             QQmlScript::Object *obj,
2305                                             const BindingContext &ctxt)
2306 {
2307     if (prop->values.isMany())
2308         COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2309
2310     if (prop->values.first()->object)
2311         COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2312
2313     prop->scriptStringScope = ctxt.stack;
2314     obj->addScriptStringProperty(prop);
2315
2316     return true;
2317 }
2318
2319 // Compile regular property assignments of the form "property: <value>"
2320 bool QQmlCompiler::buildPropertyAssignment(QQmlScript::Property *prop,
2321                                           QQmlScript::Object *obj,
2322                                           const BindingContext &ctxt)
2323 {
2324     obj->addValueProperty(prop);
2325
2326     if (prop->values.isMany())
2327         COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2328
2329     for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2330         if (v->object) {
2331
2332             COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2333
2334         } else {
2335
2336             COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2337
2338         }
2339     }
2340
2341     for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2342         Q_ASSERT(v->object);
2343         COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2344     }
2345
2346     return true;
2347 }
2348
2349 // Compile assigning a single object instance to a regular property
2350 bool QQmlCompiler::buildPropertyObjectAssignment(QQmlScript::Property *prop,
2351                                                          QQmlScript::Object *obj,
2352                                                          QQmlScript::Value *v,
2353                                                          const BindingContext &ctxt)
2354 {
2355     Q_ASSERT(prop->index != -1);
2356     Q_ASSERT(v->object->type != -1);
2357
2358     if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2359         COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2360
2361     if (QQmlMetaType::isInterface(prop->type)) {
2362
2363         // Assigning an object to an interface ptr property
2364         COMPILE_CHECK(buildObject(v->object, ctxt));
2365
2366         v->type = Value::CreatedObject;
2367
2368     } else if (prop->type == QMetaType::QVariant) {
2369
2370         // Assigning an object to a QVariant
2371         COMPILE_CHECK(buildObject(v->object, ctxt));
2372
2373         v->type = Value::CreatedObject;
2374     } else {
2375         // Normally buildObject() will set this up, but we need the static
2376         // meta object earlier to test for assignability.  It doesn't matter
2377         // that there may still be outstanding synthesized meta object changes
2378         // on this type, as they are not relevant for assignability testing
2379         v->object->metatype = output->types[v->object->type].createPropertyCache(engine);
2380         Q_ASSERT(v->object->metatype);
2381
2382         // We want to raw metaObject here as the raw metaobject is the
2383         // actual property type before we applied any extensions that might
2384         // effect the properties on the type, but don't effect assignability
2385         QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(prop->type);
2386
2387         // Will be true if the assgned type inherits propertyMetaObject
2388         bool isAssignable = false;
2389         // Determine isAssignable value
2390         if (propertyMetaObject) {
2391             QQmlPropertyCache *c = v->object->metatype;
2392             while (c && !isAssignable) {
2393                 isAssignable |= c == propertyMetaObject;
2394                 c = c->parent();
2395             }
2396         }
2397
2398         if (isAssignable) {
2399             // Simple assignment
2400             COMPILE_CHECK(buildObject(v->object, ctxt));
2401
2402             v->type = Value::CreatedObject;
2403         } else if (propertyMetaObject && propertyMetaObject->metaObject() == &QQmlComponent::staticMetaObject) {
2404             // Automatic "Component" insertion
2405             QQmlScript::Object *root = v->object;
2406             QQmlScript::Object *component = pool->New<Object>();
2407             component->type = componentTypeRef();
2408             component->metatype = enginePrivate->cache(&QQmlComponent::staticMetaObject);
2409             component->location = root->location;
2410             QQmlScript::Value *componentValue = pool->New<Value>();
2411             componentValue->object = root;
2412             component->getDefaultProperty()->addValue(componentValue);
2413             v->object = component;
2414             COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2415         } else {
2416             COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2417         }
2418     }
2419
2420     return true;
2421 }
2422
2423 // Compile assigning a single object instance to a regular property using the "on" syntax.
2424 //
2425 // For example:
2426 //     Item {
2427 //         NumberAnimation on x { }
2428 //     }
2429 bool QQmlCompiler::buildPropertyOnAssignment(QQmlScript::Property *prop,
2430                                                      QQmlScript::Object *obj,
2431                                                      QQmlScript::Object *baseObj,
2432                                                      QQmlScript::Value *v,
2433                                                      const BindingContext &ctxt)
2434 {
2435     Q_ASSERT(prop->index != -1);
2436     Q_ASSERT(v->object->type != -1);
2437
2438     Q_UNUSED(obj);
2439
2440     if (!prop->core.isWritable())
2441         COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2442
2443
2444     // Normally buildObject() will set this up, but we need the static
2445     // meta object earlier to test for assignability.  It doesn't matter
2446     // that there may still be outstanding synthesized meta object changes
2447     // on this type, as they are not relevant for assignability testing
2448     v->object->metatype = output->types[v->object->type].createPropertyCache(engine);
2449     Q_ASSERT(v->object->metatype);
2450
2451     // Will be true if the assigned type inherits QQmlPropertyValueSource
2452     bool isPropertyValue = false;
2453     // Will be true if the assigned type inherits QQmlPropertyValueInterceptor
2454     bool isPropertyInterceptor = false;
2455     if (QQmlType *valueType = toQmlType(v->object)) {
2456         isPropertyValue = valueType->propertyValueSourceCast() != -1;
2457         isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2458     }
2459
2460     if (isPropertyValue || isPropertyInterceptor) {
2461         // Assign as a property value source
2462         COMPILE_CHECK(buildObject(v->object, ctxt));
2463
2464         if (isPropertyInterceptor && baseObj->synthdata.isEmpty())
2465             buildDynamicMeta(baseObj, ForceCreation);
2466         v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2467     } else {
2468         COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(elementName(v->object)).arg(prop->name().toString()));
2469     }
2470
2471     return true;
2472 }
2473
2474 // Compile assigning a literal or binding to a regular property
2475 bool QQmlCompiler::buildPropertyLiteralAssignment(QQmlScript::Property *prop,
2476                                                           QQmlScript::Object *obj,
2477                                                           QQmlScript::Value *v,
2478                                                           const BindingContext &ctxt)
2479 {
2480     Q_ASSERT(prop->index != -1);
2481
2482     if (v->value.isScript()) {
2483
2484         //optimization for <Type>.<EnumValue> enum assignments
2485         if (prop->core.isEnum() || prop->core.propType == QMetaType::Int) {
2486             bool isEnumAssignment = false;
2487             COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, v, &isEnumAssignment));
2488             if (isEnumAssignment) {
2489                 v->type = Value::Literal;
2490                 return true;
2491             }
2492         }
2493
2494         // Test for other binding optimizations
2495         if (!buildLiteralBinding(v, prop, ctxt))
2496             COMPILE_CHECK(buildBinding(v, prop, ctxt));
2497
2498         v->type = Value::PropertyBinding;
2499
2500     } else {
2501
2502         COMPILE_CHECK(testLiteralAssignment(prop, v));
2503
2504         v->type = Value::Literal;
2505     }
2506
2507     return true;
2508 }
2509
2510 struct StaticQtMetaObject : public QObject
2511 {
2512     static const QMetaObject *get()
2513         { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2514 };
2515
2516 bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
2517                                                        QQmlScript::Object *obj,
2518                                                        QQmlScript::Value *v,
2519                                                        bool *isAssignment)
2520 {
2521     bool isIntProp = (prop->core.propType == QMetaType::Int) && !prop->core.isEnum();
2522     *isAssignment = false;
2523     if (!prop->core.isEnum() && !isIntProp)
2524         return true;
2525
2526     QMetaProperty mprop = obj->metatype->firstCppMetaObject()->property(prop->index);
2527
2528     if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2529         COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2530
2531     QString string = v->value.asString();
2532     if (!string.at(0).isUpper())
2533         return true;
2534
2535     int dot = string.indexOf(QLatin1Char('.'));
2536     if (dot == -1 || dot == string.length()-1)
2537         return true;
2538
2539     if (string.indexOf(QLatin1Char('.'), dot+1) != -1)
2540         return true;
2541
2542     QHashedStringRef typeName(string.constData(), dot);
2543     QString enumValue = string.mid(dot+1);
2544
2545     if (isIntProp) {
2546         // Allow enum assignment to ints.
2547         bool ok;
2548         int enumval = evaluateEnum(typeName, enumValue.toUtf8(), &ok);
2549         if (ok) {
2550             v->type = Value::Literal;
2551             v->value = QQmlScript::Variant((double)enumval);
2552             *isAssignment = true;
2553         }
2554         return true;
2555     }
2556
2557     QQmlType *type = 0;
2558     unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
2559
2560     if (!type && typeName != QLatin1String("Qt"))
2561         return true;
2562
2563     int value = 0;
2564     bool ok = false;
2565
2566     if (type && toQmlType(obj) == type) {
2567         // When these two match, we can short cut the search
2568         if (mprop.isFlagType()) {
2569             value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
2570         } else {
2571             value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
2572         }
2573     } else {
2574         // Otherwise we have to search the whole type
2575         if (type) {
2576             value = type->enumValue(QHashedStringRef(enumValue), &ok);
2577         } else {
2578             QByteArray enumName = enumValue.toUtf8();
2579             const QMetaObject *metaObject = StaticQtMetaObject::get();
2580             for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
2581                 QMetaEnum e = metaObject->enumerator(ii);
2582                 value = e.keyToValue(enumName.constData(), &ok);
2583             }
2584         }
2585     }
2586
2587     if (!ok)
2588         return true;
2589
2590     v->type = Value::Literal;
2591     v->value = QQmlScript::Variant((double)value);
2592     *isAssignment = true;
2593
2594     return true;
2595 }
2596
2597 // Similar logic to above, but not knowing target property.
2598 int QQmlCompiler::evaluateEnum(const QHashedStringRef &scope, const QByteArray& enumValue, bool *ok) const
2599 {
2600     Q_ASSERT_X(ok, "QQmlCompiler::evaluateEnum", "ok must not be a null pointer");
2601     *ok = false;
2602
2603     if (scope != QLatin1String("Qt")) {
2604         QQmlType *type = 0;
2605         unit->imports().resolveType(scope, &type, 0, 0, 0, 0);
2606         return type ? type->enumValue(QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1;
2607     }
2608
2609     const QMetaObject *mo = StaticQtMetaObject::get();
2610     int i = mo->enumeratorCount();
2611     while (i--) {
2612         int v = mo->enumerator(i).keyToValue(enumValue.constData(), ok);
2613         if (*ok)
2614             return v;
2615     }
2616     return -1;
2617 }
2618
2619 const QMetaObject *QQmlCompiler::resolveType(const QString& name) const
2620 {
2621     QQmlType *qmltype = 0;
2622     if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2623         return 0;
2624     if (!qmltype)
2625         return 0;
2626     return qmltype->metaObject();
2627 }
2628
2629 // similar to logic of completeComponentBuild, but also sticks data
2630 // into primitives at the end
2631 int QQmlCompiler::rewriteBinding(const QQmlScript::Variant& value, const QString& name)
2632 {
2633     QQmlRewrite::RewriteBinding rewriteBinding;
2634     rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1));
2635
2636     QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0);
2637
2638     return output->indexForString(rewrite);
2639 }
2640
2641 QString QQmlCompiler::rewriteSignalHandler(const QQmlScript::Variant& value, const QString &name)
2642 {
2643     QQmlRewrite::RewriteSignalHandler rewriteSignalHandler;
2644     return rewriteSignalHandler(value.asAST(), value.asScript(), name);
2645 }
2646
2647 // Ensures that the dynamic meta specification on obj is valid
2648 bool QQmlCompiler::checkDynamicMeta(QQmlScript::Object *obj)
2649 {
2650     bool seenDefaultProperty = false;
2651
2652     // We use a coarse grain, 31 bit hash to check if there are duplicates.
2653     // Calculating the hash for the names is not a waste as we have to test
2654     // them against the illegalNames set anyway.
2655     QHashField propNames;
2656     QHashField methodNames;
2657
2658     // Check properties
2659     for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2660         const QQmlScript::Object::DynamicProperty &prop = *p;
2661
2662         if (prop.isDefaultProperty) {
2663             if (seenDefaultProperty)
2664                 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2665             seenDefaultProperty = true;
2666         }
2667
2668         if (propNames.testAndSet(prop.name.hash())) {
2669             for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p; 
2670                  p2 = obj->dynamicProperties.next(p2)) {
2671                 if (p2->name == prop.name) {
2672                     COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2673                                                prop.nameLocation.column,
2674                                                tr("Duplicate property name"));
2675                 }
2676             }
2677         }
2678
2679         if (prop.name.at(0).isUpper()) {
2680             COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2681                                        prop.nameLocation.column,
2682                                        tr("Property names cannot begin with an upper case letter"));
2683         }
2684
2685         if (enginePrivate->v8engine()->illegalNames().contains(prop.name)) {
2686             COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2687                                        prop.nameLocation.column,
2688                                        tr("Illegal property name"));
2689         }
2690     }
2691
2692     for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2693         const QQmlScript::Object::DynamicSignal &currSig = *s;
2694
2695         if (methodNames.testAndSet(currSig.name.hash())) {
2696             for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2697                  s2 = obj->dynamicSignals.next(s2)) {
2698                 if (s2->name == currSig.name)
2699                     COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2700             }
2701         }
2702
2703         if (currSig.name.at(0).isUpper())
2704             COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2705         if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2706             COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2707     }
2708
2709     for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2710         const QQmlScript::Object::DynamicSlot &currSlot = *s;
2711
2712         if (methodNames.testAndSet(currSlot.name.hash())) {
2713             for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2714                  s2 = obj->dynamicSignals.next(s2)) {
2715                 if (s2->name == currSlot.name)
2716                     COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2717             }
2718             for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2719                  s2 = obj->dynamicSlots.next(s2)) {
2720                 if (s2->name == currSlot.name)
2721                     COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2722             }
2723         }
2724
2725         if (currSlot.name.at(0).isUpper())
2726             COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2727         if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2728             COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2729     }
2730
2731     return true;
2732 }
2733
2734 bool QQmlCompiler::mergeDynamicMetaProperties(QQmlScript::Object *obj)
2735 {
2736     for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2737          p = obj->dynamicProperties.next(p)) {
2738
2739         if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2740             continue;
2741
2742         Property *property = 0;
2743         if (p->isDefaultProperty) {
2744             property = obj->getDefaultProperty();
2745         } else {
2746             property = obj->getProperty(p->name);
2747             if (!property->values.isEmpty()) 
2748                 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2749         }
2750
2751         if (p->isReadOnly)
2752             property->isReadOnlyDeclaration = true;
2753
2754         if (property->value)
2755             COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2756
2757         property->values.append(p->defaultValue->values);
2758     }
2759     return true;
2760 }
2761
2762 #include <private/qqmljsparser_p.h>
2763
2764 static QStringList astNodeToStringList(QQmlJS::AST::Node *node)
2765 {
2766     if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) {
2767         QString name =
2768             static_cast<QQmlJS::AST::IdentifierExpression *>(node)->name.toString();
2769         return QStringList() << name;
2770     } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) {
2771         QQmlJS::AST::FieldMemberExpression *expr = static_cast<QQmlJS::AST::FieldMemberExpression *>(node);
2772
2773         QStringList rv = astNodeToStringList(expr->base);
2774         if (rv.isEmpty())
2775             return rv;
2776         rv.append(expr->name.toString());
2777         return rv;
2778     }
2779     return QStringList();
2780 }
2781
2782 static QAtomicInt classIndexCounter(0);
2783
2784 bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mode)
2785 {
2786     Q_ASSERT(obj);
2787     Q_ASSERT(obj->metatype);
2788
2789     if (mode != ForceCreation &&
2790         obj->dynamicProperties.isEmpty() &&
2791         obj->dynamicSignals.isEmpty() &&
2792         obj->dynamicSlots.isEmpty())
2793         return true;
2794
2795     Q_ASSERT(obj->synthCache == 0);
2796
2797     struct TypeData {
2798         Object::DynamicProperty::Type dtype;
2799         int metaType;
2800     } builtinTypes[] = {
2801         { Object::DynamicProperty::Var, QMetaType::QVariant },
2802         { Object::DynamicProperty::Variant, QMetaType::QVariant },
2803         { Object::DynamicProperty::Int, QMetaType::Int },
2804         { Object::DynamicProperty::Bool, QMetaType::Bool },
2805         { Object::DynamicProperty::Real, QMetaType::Double },
2806         { Object::DynamicProperty::String, QMetaType::QString },
2807         { Object::DynamicProperty::Url, QMetaType::QUrl },
2808         { Object::DynamicProperty::Color, QMetaType::QColor },
2809         { Object::DynamicProperty::Time, QMetaType::QTime },
2810         { Object::DynamicProperty::Date, QMetaType::QDate },
2811         { Object::DynamicProperty::DateTime, QMetaType::QDateTime },
2812         { Object::DynamicProperty::Rect, QMetaType::QRectF },
2813     };
2814     static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2815
2816     QByteArray newClassName;
2817
2818     if (compileState->root == obj && !compileState->nested) {
2819         QString path = output->url.path();
2820         int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2821         if (lastSlash > -1) {
2822             QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2823             if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2824                 newClassName = nameBase.toUtf8() + "_QMLTYPE_" +
2825                                QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
2826         }
2827     }
2828     if (newClassName.isEmpty()) {
2829         newClassName = QQmlMetaObject(obj->metatype).className();
2830         newClassName.append("_QML_");
2831         newClassName.append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)));
2832     }
2833     QQmlPropertyCache *cache = obj->metatype->copyAndReserve(engine, obj->dynamicProperties.count(),
2834                                                              obj->dynamicProperties.count() +
2835                                                              obj->dynamicSignals.count() +
2836                                                              obj->dynamicSlots.count(),
2837                                                              obj->dynamicProperties.count() +
2838                                                              obj->dynamicSignals.count());
2839
2840     cache->_dynamicClassName = newClassName;
2841
2842     int cStringNameCount = 0;
2843
2844     int aliasCount = 0;
2845     int varPropCount = 0;
2846
2847     for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2848          p = obj->dynamicProperties.next(p)) {
2849
2850         if (p->type == Object::DynamicProperty::Alias)
2851             aliasCount++;
2852         else if (p->type == Object::DynamicProperty::Var)
2853             varPropCount++;
2854
2855         if (p->name.isLatin1()) {
2856             p->nameIndex = cStringNameCount;
2857             cStringNameCount += p->name.length() + 7 /* strlen("Changed") */;
2858         }
2859
2860         // No point doing this for both the alias and non alias cases
2861         QQmlPropertyData *d = property(obj, p->name);
2862         if (d && d->isFinal())
2863             COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2864     }
2865
2866     for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2867         if (s->name.isLatin1()) {
2868             s->nameIndex = cStringNameCount;
2869             cStringNameCount += s->name.length();
2870         }
2871     }
2872
2873     for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2874         if (s->name.isLatin1()) {
2875             s->nameIndex = cStringNameCount;
2876             cStringNameCount += s->name.length();
2877         }
2878     }
2879
2880     char *cStringData = 0;
2881     if (cStringNameCount) {
2882         cache->_dynamicStringData.resize(cStringNameCount);
2883         cStringData = cache->_dynamicStringData.data();
2884
2885         for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2886              p = obj->dynamicProperties.next(p)) {
2887
2888             if (p->nameIndex == -1) continue;
2889
2890             char *myData = cStringData + p->nameIndex;
2891             for (int ii = 0; ii < p->name.length(); ++ii)
2892                 *myData++ = p->name.at(ii).unicode();
2893             *myData++ = 'C'; *myData++ = 'h'; *myData++ = 'a'; *myData++ = 'n';
2894             *myData++ = 'g'; *myData++ = 'e'; *myData++ = 'd';
2895         }
2896
2897         for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2898
2899             if (s->nameIndex == -1) continue;
2900
2901             char *myData = cStringData + s->nameIndex;
2902             for (int ii = 0; ii < s->name.length(); ++ii)
2903                 *myData++ = s->name.at(ii).unicode();
2904         }
2905
2906         for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s;
2907              s = obj->dynamicSignals.next(s)) {
2908
2909             if (s->nameIndex == -1) continue;
2910
2911             char *myData = cStringData + s->nameIndex;
2912             for (int ii = 0; ii < s->name.length(); ++ii)
2913                 *myData++ = s->name.at(ii).unicode();
2914         }
2915     }
2916
2917     QByteArray dynamicData;
2918     typedef QQmlVMEMetaData VMD;
2919
2920     dynamicData = QByteArray(sizeof(QQmlVMEMetaData) +
2921                              obj->dynamicProperties.count() * sizeof(VMD::PropertyData) +
2922                              obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2923                              aliasCount * sizeof(VMD::AliasData), 0);
2924
2925     int effectivePropertyIndex = cache->propertyIndexCacheStart;
2926     int effectiveMethodIndex = cache->methodIndexCacheStart;
2927
2928     // First set up notify signals for properties - first normal, then var, then alias
2929     enum { NSS_Normal = 0, NSS_Var = 1, NSS_Alias = 2 };
2930     for (int ii = NSS_Normal; ii <= NSS_Alias; ++ii) { // 0 == normal, 1 == var, 2 == alias
2931
2932         if (ii == NSS_Var && varPropCount == 0) continue;
2933         else if (ii == NSS_Alias && aliasCount == 0) continue;
2934
2935         for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2936              p = obj->dynamicProperties.next(p)) {
2937
2938             if ((ii == NSS_Normal && (p->type == Object::DynamicProperty::Alias ||
2939                                       p->type == Object::DynamicProperty::Var)) ||
2940                 ((ii == NSS_Var) && (p->type != Object::DynamicProperty::Var)) ||
2941                 ((ii == NSS_Alias) && (p->type != Object::DynamicProperty::Alias)))
2942                 continue;
2943
2944             quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
2945                             QQmlPropertyData::IsVMESignal;
2946
2947             if (p->nameIndex != -1) {
2948                 QHashedCStringRef changedSignalName(cStringData + p->nameIndex,
2949                                                     p->name.length() + 7 /* strlen("Changed") */);
2950                 cache->appendSignal(changedSignalName, flags, effectiveMethodIndex++);
2951             } else {
2952                 QString changedSignalName = p->name.toString() + QLatin1String("Changed");
2953
2954                 cache->appendSignal(changedSignalName, flags, effectiveMethodIndex++);
2955             }
2956         }
2957     }
2958
2959     // Dynamic signals
2960     for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2961         int paramCount = s->parameterNames.count();
2962
2963         QList<QByteArray> names;
2964         QVarLengthArray<int, 10> paramTypes(paramCount?(paramCount + 1):0);
2965
2966         if (paramCount) {
2967             paramTypes[0] = paramCount;
2968
2969             for (int i = 0; i < paramCount; ++i) {
2970                 Q_ASSERT(s->parameterTypes.at(i) < builtinTypeCount);
2971                 paramTypes[i + 1] = builtinTypes[s->parameterTypes.at(i)].metaType;
2972                 names.append(s->parameterNames.at(i).toString().toUtf8());
2973             }
2974         }
2975
2976         ((QQmlVMEMetaData *)dynamicData.data())->signalCount++;
2977
2978         quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
2979                         QQmlPropertyData::IsVMESignal;
2980         if (paramCount)
2981             flags |= QQmlPropertyData::HasArguments;
2982
2983         if (s->nameIndex != -1) {
2984             QHashedCStringRef name(cStringData + s->nameIndex, s->name.length(), s->name.hash());
2985             cache->appendSignal(name, flags, effectiveMethodIndex++,
2986                                 paramCount?paramTypes.constData():0, names);
2987         } else {
2988             QString name = s->name.toString();
2989             cache->appendSignal(name, flags, effectiveMethodIndex++,
2990                                 paramCount?paramTypes.constData():0, names);
2991         }
2992     }
2993
2994
2995     // Dynamic slots
2996     for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2997         int paramCount = s->parameterNames.count();
2998
2999         quint32 flags = QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMEFunction;
3000
3001         if (paramCount)
3002             flags |= QQmlPropertyData::HasArguments;
3003
3004         if (s->nameIndex != -1) {
3005             QHashedCStringRef name(cStringData + s->nameIndex, s->name.length(), s->name.hash());
3006             cache->appendMethod(name, flags, effectiveMethodIndex++, s->parameterNames);
3007         } else {
3008             QString name = s->name.toString();
3009             cache->appendMethod(name, flags, effectiveMethodIndex++, s->parameterNames);
3010         }
3011     }
3012
3013
3014     // Dynamic properties (except var and aliases)
3015     int effectiveSignalIndex = cache->signalHandlerIndexCacheStart;
3016     for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
3017          p = obj->dynamicProperties.next(p)) {
3018
3019         if (p->type == Object::DynamicProperty::Alias ||
3020             p->type == Object::DynamicProperty::Var)
3021             continue;
3022
3023         int propertyType = 0;
3024         int vmePropertyType = 0;
3025         quint32 propertyFlags = 0;
3026
3027         if (p->type < builtinTypeCount) {
3028             propertyType = builtinTypes[p->type].metaType;
3029             vmePropertyType = propertyType;
3030
3031             if (p->type == Object::DynamicProperty::Variant)
3032                 propertyFlags |= QQmlPropertyData::IsQVariant;
3033         } else {
3034             Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
3035                      p->type == Object::DynamicProperty::Custom);
3036
3037             QQmlType *qmltype = 0;
3038             QString url;
3039             if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
3040                 COMPILE_EXCEPTION(p, tr("Invalid property type"));
3041
3042             if (!qmltype) {
3043                 QQmlTypeData *tdata = enginePrivate->typeLoader.getType(QUrl(url));
3044                 Q_ASSERT(tdata);
3045                 Q_ASSERT(tdata->isComplete());
3046
3047                 QQmlCompiledData *data = tdata->compiledData();
3048
3049                 if (p->type == Object::DynamicProperty::Custom) {
3050                     propertyType = data->metaTypeId;
3051                     vmePropertyType = QMetaType::QObjectStar;
3052                 } else {
3053                     propertyType = data->listMetaTypeId;
3054                     vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >();
3055                 }
3056
3057                 tdata->release();
3058             } else {
3059                 if (p->type == Object::DynamicProperty::Custom) {
3060                     propertyType = qmltype->typeId();
3061                     vmePropertyType = QMetaType::QObjectStar;
3062                 } else {
3063                     propertyType = qmltype->qListTypeId();
3064                     vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >();
3065                 }
3066             }
3067
3068             if (p->type == Object::DynamicProperty::Custom)
3069                 propertyFlags |= QQmlPropertyData::IsQObjectDerived;
3070             else
3071                 propertyFlags |= QQmlPropertyData::IsQList;
3072         }
3073
3074         if (!p->isReadOnly && p->type != Object::DynamicProperty::CustomList)
3075             propertyFlags |= QQmlPropertyData::IsWritable;
3076
3077         if (p->nameIndex != -1) {
3078             QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(),
3079                                            p->name.hash());
3080             if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16();
3081             cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3082                                   propertyType, effectiveSignalIndex);
3083         } else {
3084             QString propertyName = p->name.toString();
3085             if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName;
3086             cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3087                                   propertyType, effectiveSignalIndex);
3088         }
3089
3090         effectiveSignalIndex++;
3091
3092         VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3093         (vmd->propertyData() + vmd->propertyCount)->propertyType = vmePropertyType;
3094         vmd->propertyCount++;
3095     }
3096
3097     // Now do var properties
3098     for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p && varPropCount;
3099          p = obj->dynamicProperties.next(p)) {
3100
3101         if (p->type != Object::DynamicProperty::Var)
3102             continue;
3103
3104         quint32 propertyFlags = QQmlPropertyData::IsVarProperty;
3105         if (!p->isReadOnly)
3106             propertyFlags |= QQmlPropertyData::IsWritable;
3107
3108         VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3109         (vmd->propertyData() + vmd->propertyCount)->propertyType = QMetaType::QVariant;
3110         vmd->propertyCount++;
3111         ((QQmlVMEMetaData *)dynamicData.data())->varPropertyCount++;
3112
3113         if (p->nameIndex != -1) {
3114             QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(),
3115                                            p->name.hash());
3116             if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16();
3117             cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3118                                   QMetaType::QVariant, effectiveSignalIndex);
3119         } else {
3120             QString propertyName = p->name.toString();
3121             if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName;
3122             cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3123                                   QMetaType::QVariant, effectiveSignalIndex);
3124         }
3125
3126         effectiveSignalIndex++;
3127     }
3128
3129     // Alias property count.  Actual data is setup in buildDynamicMetaAliases
3130     ((QQmlVMEMetaData *)dynamicData.data())->aliasCount = aliasCount;
3131
3132     // Dynamic slot data - comes after the property data
3133     for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3134         int paramCount = s->parameterNames.count();
3135
3136         QString funcScript;
3137         int namesSize = 0;
3138         if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
3139         funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ +
3140                            namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
3141         funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
3142         for (int jj = 0; jj < paramCount; ++jj) {
3143             if (jj) funcScript.append(QLatin1Char(','));
3144             funcScript.append(QLatin1String(s->parameterNames.at(jj)));
3145         }
3146         funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
3147
3148         QByteArray utf8 = funcScript.toUtf8();
3149         VMD::MethodData methodData = { s->parameterNames.count(),
3150                                        dynamicData.size(),
3151                                        utf8.length(),
3152                                        s->location.start.line };
3153
3154         VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3155         VMD::MethodData &md = *(vmd->methodData() + vmd->methodCount);
3156         vmd->methodCount++;
3157         md = methodData;
3158
3159         dynamicData.append((const char *)utf8.constData(), utf8.length());
3160     }
3161
3162     if (aliasCount)
3163         compileState->aliasingObjects.append(obj);
3164
3165     obj->synthdata = dynamicData;
3166     obj->synthCache = cache;
3167     obj->metatype = cache;
3168
3169     return true;
3170 }
3171
3172 bool QQmlCompiler::buildDynamicMetaAliases(QQmlScript::Object *obj)
3173 {
3174     Q_ASSERT(obj->synthCache);
3175
3176     QByteArray &dynamicData = obj->synthdata;
3177
3178     QQmlPropertyCache *cache = obj->synthCache;
3179     char *cStringData = cache->_dynamicStringData.data();
3180
3181     int effectiveSignalIndex = cache->signalHandlerIndexCacheStart + cache->propertyIndexCache.count();
3182     int effectivePropertyIndex = cache->propertyIndexCacheStart + cache->propertyIndexCache.count();
3183     int effectiveAliasIndex = 0;
3184
3185     for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
3186          p = obj->dynamicProperties.next(p)) {
3187
3188         if (p->type != Object::DynamicProperty::Alias)
3189             continue;
3190
3191         if (!p->defaultValue)
3192             COMPILE_EXCEPTION(obj, tr("No property alias location"));
3193
3194         if (!p->defaultValue->values.isOne() ||
3195             p->defaultValue->values.first()->object ||
3196             !p->defaultValue->values.first()->value.isScript())
3197             COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3198
3199         QQmlJS::AST::Node *node = p->defaultValue->values.first()->value.asAST();
3200         Q_ASSERT(node);
3201
3202         QStringList alias = astNodeToStringList(node);
3203         if (alias.count() < 1 || alias.count() > 3)
3204             COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
3205
3206         QQmlScript::Object *idObject = compileState->ids.value(alias.at(0));
3207         if (!idObject)
3208             COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
3209
3210         int propIdx = -1;
3211         int notifySignal = -1;
3212         int flags = 0;
3213         int type = 0;
3214         bool writable = false;
3215         bool resettable = false;
3216
3217         quint32 propertyFlags = QQmlPropertyData::IsAlias;
3218
3219         if (alias.count() == 2 || alias.count() == 3) {
3220             QQmlPropertyData *property = this->property(idObject, alias.at(1));
3221
3222             if (!property || property->coreIndex > 0xFFFF)
3223                 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3224
3225             propIdx = property->coreIndex;
3226             type = property->propType;
3227
3228             writable = property->isWritable();
3229             resettable = property->isResettable();
3230             notifySignal = property->notifyIndex;
3231
3232             if (alias.count() == 3) {
3233                 QQmlValueType *valueType = enginePrivate->valueTypes[type]; // XXX threadsafe?
3234                 if (!valueType)
3235                     COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3236
3237                 propIdx |= ((unsigned int)type) << 24;
3238                 int valueTypeIndex =
3239                     valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
3240                 if (valueTypeIndex == -1)
3241                     COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3242                 Q_ASSERT(valueTypeIndex <= 0xFF);
3243
3244                 propIdx |= (valueTypeIndex << 16);
3245                 if (valueType->metaObject()->property(valueTypeIndex).isEnumType())
3246                     type = QVariant::Int;
3247                 else
3248                     type = valueType->metaObject()->property(valueTypeIndex).userType();
3249
3250             } else {
3251                 if (property->isEnum()) {
3252                     type = QVariant::Int;
3253                 } else {
3254                     // Copy type flags
3255                     propertyFlags |= property->getFlags() & QQmlPropertyData::PropTypeFlagMask;
3256
3257                     if (property->isVarProperty())
3258                         propertyFlags |= QQmlPropertyData::IsQVariant;
3259
3260                     if (property->isQObject())
3261                         flags |= QML_ALIAS_FLAG_PTR;
3262                 }
3263             }
3264         } else {
3265             Q_ASSERT(idObject->type != -1); // How else did it get an id?
3266
3267             const QQmlCompiledData::TypeReference &ref = output->types.at(idObject->type);
3268             if (ref.type)
3269                 type = ref.type->typeId();
3270             else
3271                 type = ref.component->metaTypeId;
3272
3273             flags |= QML_ALIAS_FLAG_PTR;
3274             propertyFlags |= QQmlPropertyData::IsQObjectDerived;
3275         }
3276
3277         QQmlVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags, notifySignal };
3278
3279         typedef QQmlVMEMetaData VMD;
3280         VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3281         *(vmd->aliasData() + effectiveAliasIndex++) = aliasData;
3282
3283         if (!p->isReadOnly && writable)
3284             propertyFlags |= QQmlPropertyData::IsWritable;
3285         else
3286             propertyFlags &= ~QQmlPropertyData::IsWritable;
3287
3288         if (resettable)
3289             propertyFlags |= QQmlPropertyData::IsResettable;
3290         else
3291             propertyFlags &= ~QQmlPropertyData::IsResettable;
3292
3293         if (p->nameIndex != -1) {
3294             QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(),
3295                                            p->name.hash());
3296             if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16();
3297             cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3298                                   type, effectiveSignalIndex++);
3299         } else {
3300             QString propertyName = p->name.toString();
3301             if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName;
3302             cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3303                                   type, effectiveSignalIndex++);
3304         }
3305     }
3306
3307     return true;
3308 }
3309
3310 bool QQmlCompiler::checkValidId(QQmlScript::Value *v, const QString &val)
3311 {
3312     if (val.isEmpty())
3313         COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
3314
3315     QChar ch = val.at(0);
3316     if (ch.isLetter() && !ch.isLower())
3317         COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
3318
3319     QChar u(QLatin1Char('_'));
3320     if (!ch.isLetter() && ch != u)
3321         COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
3322
3323     for (int ii = 1; ii < val.count(); ++ii) {
3324         ch = val.at(ii);
3325         if (!ch.isLetterOrNumber() && ch != u)
3326             COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
3327     }
3328
3329     if (enginePrivate->v8engine()->illegalNames().contains(val))
3330         COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
3331
3332     return true;
3333 }
3334
3335 bool QQmlCompiler::buildBinding(QQmlScript::Value *value,
3336                                         QQmlScript::Property *prop,
3337                                         const BindingContext &ctxt)
3338 {
3339     Q_ASSERT(prop->index != -1);
3340     Q_ASSERT(prop->parent);
3341     Q_ASSERT(prop->parent->metatype);
3342
3343     if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
3344         COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3345
3346     JSBindingReference *reference = pool->New<JSBindingReference>();
3347     reference->expression = value->value;
3348     reference->property = prop;
3349     reference->value = value;
3350     reference->bindingContext = ctxt;
3351     addBindingReference(reference);
3352
3353     return true;
3354 }
3355
3356 bool QQmlCompiler::buildLiteralBinding(QQmlScript::Value *v,
3357                                                QQmlScript::Property *prop,
3358                                                const QQmlCompilerTypes::BindingContext &)
3359 {
3360     Q_ASSERT(v->value.isScript());
3361
3362     if (!prop->core.isWritable())
3363         return false;
3364
3365     AST::Node *binding = v->value.asAST();
3366
3367     if (prop->type == QVariant::String) {
3368         if (AST::CallExpression *e = AST::cast<AST::CallExpression *>(binding)) {
3369             if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(e->base)) {
3370                 if (i->name == qsTrId_string) {
3371                     AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3372                     AST::ArgumentList *arg2 = arg1?arg1->next:0;
3373
3374                     if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3375                         (!arg2 || arg2->expression->kind == AST::Node::Kind_NumericLiteral) &&
3376                         (!arg2 || !arg2->next)) {
3377
3378                         QStringRef text;
3379                         int n = -1;
3380
3381                         text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3382                         if (arg2) n = (int)AST::cast<AST::NumericLiteral *>(arg2->expression)->value;
3383
3384                         TrBindingReference *reference = pool->New<TrBindingReference>();
3385                         reference->dataType = BindingReference::TrId;
3386                         reference->text = text;
3387                         reference->n = n;
3388                         v->bindingReference = reference;
3389                         return true;
3390                     }
3391
3392                 } else if (i->name == qsTr_string) {
3393
3394                     AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3395                     AST::ArgumentList *arg2 = arg1?arg1->next:0;
3396                     AST::ArgumentList *arg3 = arg2?arg2->next:0;
3397
3398                     if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3399                         (!arg2 || arg2->expression->kind == AST::Node::Kind_StringLiteral) &&
3400                         (!arg3 || arg3->expression->kind == AST::Node::Kind_NumericLiteral) &&
3401                         (!arg3 || !arg3->next)) {
3402
3403                         QStringRef text;
3404                         QStringRef comment;
3405                         int n = -1;
3406
3407                         text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3408                         if (arg2) comment = AST::cast<AST::StringLiteral *>(arg2->expression)->value;
3409                         if (arg3) n = (int)AST::cast<AST::NumericLiteral *>(arg3->expression)->value;
3410
3411                         TrBindingReference *reference = pool->New<TrBindingReference>();
3412                         reference->dataType = BindingReference::Tr;
3413                         reference->text = text;
3414                         reference->comment = comment;
3415                         reference->n = n;
3416                         v->bindingReference = reference;
3417                         return true;
3418                     }
3419
3420                 }
3421             }
3422         }
3423
3424     }
3425
3426     return false;
3427 }
3428
3429 void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
3430                                                 QQmlScript::Property *prop,
3431                                                 QQmlScript::Object *obj,
3432                                                 QQmlScript::Property *valueTypeProperty)
3433 {
3434     Q_UNUSED(obj);
3435     Q_ASSERT(binding->bindingReference);
3436
3437     const BindingReference &ref = *binding->bindingReference;
3438     if (ref.dataType == BindingReference::TrId) {
3439         const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3440
3441         Instruction::StoreTrIdString store;
3442         store.propertyIndex = prop->core.coreIndex;
3443         store.text = output->indexForByteArray(tr.text.toUtf8());
3444         store.n = tr.n;
3445         output->addInstruction(store);
3446     } else if (ref.dataType == BindingReference::Tr) {
3447         const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3448
3449         Instruction::StoreTrString store;
3450         store.propertyIndex = prop->core.coreIndex;
3451         store.context = translationContextIndex();
3452         store.text = output->indexForByteArray(tr.text.toUtf8());
3453         store.comment = output->indexForByteArray(tr.comment.toUtf8());
3454         store.n = tr.n;
3455         output->addInstruction(store);
3456     } else if (ref.dataType == BindingReference::V4) {
3457         const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3458
3459         Instruction::StoreV4Binding store;
3460         store.value = js.compiledIndex;
3461         store.fallbackValue = js.sharedIndex;
3462         store.context = js.bindingContext.stack;
3463         store.owner = js.bindingContext.owner;
3464         store.isAlias = prop->isAlias;
3465         if (valueTypeProperty) {
3466             store.property = (valueTypeProperty->index & 0xFFFF) |
3467                              ((valueTypeProperty->type & 0xFF)) << 16 |
3468                              ((prop->index & 0xFF) << 24);
3469             store.isRoot = (compileState->root == valueTypeProperty->parent);
3470         } else {
3471             store.property = prop->index;
3472             store.isRoot = (compileState->root == obj);
3473         }
3474         store.line = binding->location.start.line;
3475         store.column = binding->location.start.column;
3476         output->addInstruction(store);
3477
3478         if (store.fallbackValue > -1) {
3479             //also create v8 instruction (needed to properly configure the fallback v8 binding)
3480             JSBindingReference &js = static_cast<JSBindingReference &>(*binding->bindingReference);
3481             js.dataType = BindingReference::V8;
3482             genBindingAssignment(binding, prop, obj, valueTypeProperty);
3483         }
3484     } else if (ref.dataType == BindingReference::V8) {
3485         const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3486
3487         Instruction::StoreV8Binding store;
3488         store.value = js.sharedIndex;
3489         store.context = js.bindingContext.stack;
3490         store.owner = js.bindingContext.owner;
3491         store.isAlias = prop->isAlias;
3492         if (valueTypeProperty) {
3493             store.isRoot = (compileState->root == valueTypeProperty->parent);
3494         } else {
3495             store.isRoot = (compileState->root == obj);
3496         }
3497         store.isFallback = js.compiledIndex > -1;
3498         store.line = binding->location.start.line;
3499         store.column = binding->location.start.column;
3500
3501         Q_ASSERT(js.bindingContext.owner == 0 ||
3502                  (js.bindingContext.owner != 0 && valueTypeProperty));
3503         if (js.bindingContext.owner) {
3504             store.property = genValueTypeData(prop, valueTypeProperty);
3505         } else {
3506             store.property = prop->core;
3507         }
3508
3509         output->addInstruction(store);
3510     } else if (ref.dataType == BindingReference::QtScript) {
3511         const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3512
3513         Instruction::StoreBinding store;
3514         store.value = output->indexForString(js.rewrittenExpression);
3515         store.context = js.bindingContext.stack;
3516         store.owner = js.bindingContext.owner;
3517         store.line = binding->location.start.line;
3518         store.column = binding->location.start.column;
3519         store.isAlias = prop->isAlias;
3520
3521         if (valueTypeProperty) {
3522             store.isRoot = (compileState->root == valueTypeProperty->parent);
3523         } else {
3524             store.isRoot = (compileState->root == obj);
3525         }
3526         store.isFallback = false;
3527
3528         Q_ASSERT(js.bindingContext.owner == 0 ||
3529                  (js.bindingContext.owner != 0 && valueTypeProperty));
3530         if (js.bindingContext.owner) {
3531             store.property = genValueTypeData(prop, valueTypeProperty);
3532         } else {
3533             store.property = prop->core;
3534         }
3535
3536         output->addInstruction(store);
3537     } else {
3538         Q_ASSERT(!"Unhandled BindingReference::DataType type");
3539     }
3540 }
3541
3542 int QQmlCompiler::genContextCache()
3543 {
3544     if (compileState->ids.count() == 0)
3545         return -1;
3546
3547     QQmlIntegerCache *cache = new QQmlIntegerCache();
3548     cache->reserve(compileState->ids.count());
3549     for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o)) 
3550         cache->add(o->id, o->idIndex);
3551
3552     output->contextCaches.append(cache);
3553     return output->contextCaches.count() - 1;
3554 }
3555
3556 QQmlPropertyData
3557 QQmlCompiler::genValueTypeData(QQmlScript::Property *valueTypeProp, 
3558                                        QQmlScript::Property *prop)
3559 {
3560     typedef QQmlPropertyPrivate QDPP;
3561     return QDPP::saveValueType(prop->core, enginePrivate->valueTypes[prop->type]->metaObject(),
3562                                valueTypeProp->index, engine);
3563 }
3564
3565 bool QQmlCompiler::completeComponentBuild()
3566 {
3567     if (componentStats)
3568         componentStats->componentStat.ids = compileState->ids.count();
3569
3570     for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject; 
3571          aliasObject = compileState->aliasingObjects.next(aliasObject)) 
3572         COMPILE_CHECK(buildDynamicMetaAliases(aliasObject));
3573
3574     QV4Compiler::Expression expr(unit->imports());
3575     expr.component = compileState->root;
3576     expr.ids = &compileState->ids;
3577     expr.importCache = output->importCache;
3578
3579     QV4Compiler bindingCompiler;
3580
3581     QList<JSBindingReference*> sharedBindings;
3582
3583     for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3584
3585         JSBindingReference &binding = *b;
3586
3587         // First try v4
3588         expr.context = binding.bindingContext.object;
3589         expr.property = binding.property;
3590         expr.expression = binding.expression;
3591
3592         bool needsFallback = false;
3593         int index = bindingCompiler.compile(expr, enginePrivate, &needsFallback);
3594         if (index != -1) {
3595             // Ensure the index value fits within the available space
3596             Q_ASSERT(index < (1 << 15));
3597
3598             binding.dataType = BindingReference::V4;
3599             binding.compiledIndex = index;
3600             binding.sharedIndex = -1;
3601             if (componentStats)
3602                 componentStats->componentStat.optimizedBindings.append(b->value->location);
3603
3604             if (!needsFallback)
3605                 continue;
3606
3607             // Drop through. We need to create a V8 binding in case the V4 binding is invalidated
3608         }
3609
3610         // Pre-rewrite the expression
3611         QString expression = binding.expression.asScript();
3612
3613         QQmlRewrite::RewriteBinding rewriteBinding;
3614         rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3615         bool isSharable = false;
3616         binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3617
3618         if (isSharable && binding.property->type != qMetaTypeId<QQmlBinding*>()) {
3619             sharedBindings.append(b);
3620
3621             if (!needsFallback) {
3622                 binding.dataType = BindingReference::V8;
3623                 binding.compiledIndex = -1;
3624
3625                 if (componentStats)
3626                     componentStats->componentStat.sharedBindings.append(b->value->location);
3627             }
3628         } else {
3629             Q_ASSERT(!needsFallback);
3630             binding.dataType = BindingReference::QtScript;
3631
3632             if (componentStats)
3633                 componentStats->componentStat.scriptBindings.append(b->value->location);
3634         }
3635     }
3636
3637     if (!sharedBindings.isEmpty()) {
3638         struct Sort {
3639             static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs)
3640             {
3641                 return lhs->value->location.start.line < rhs->value->location.start.line;
3642             }
3643         };
3644
3645         qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3646
3647         int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3648         int lineNumber = startLineNumber;
3649
3650         QByteArray functionArray("[", 1);
3651         for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3652
3653             JSBindingReference *reference = sharedBindings.at(ii);
3654             QQmlScript::Value *value = reference->value;
3655             const QString &expression = reference->rewrittenExpression;
3656
3657             if (ii != 0) functionArray.append(",", 1);
3658
3659             while (lineNumber < value->location.start.line) {
3660                 lineNumber++;
3661                 functionArray.append("\n", 1);
3662             }
3663
3664             functionArray += expression.toUtf8();
3665             lineNumber += expression.count(QLatin1Char('\n'));
3666
3667             // Ensure the index value fits within the available space
3668             Q_ASSERT(ii < (1 << 15));
3669             reference->sharedIndex = ii;
3670         }
3671         functionArray.append("]", 1);
3672
3673         compileState->v8BindingProgram = functionArray;
3674         compileState->v8BindingProgramLine = startLineNumber;
3675     }
3676
3677     if (bindingCompiler.isValid()) 
3678         compileState->compiledBindingData = bindingCompiler.program();
3679
3680     // Check pop()'s matched push()'s
3681     Q_ASSERT(compileState->objectDepth.depth() == 0);
3682     Q_ASSERT(compileState->listDepth.depth() == 0);
3683
3684     saveComponentState();
3685
3686     return true;
3687 }
3688
3689 void QQmlCompiler::dumpStats()
3690 {
3691     Q_ASSERT(componentStats);
3692     qWarning().nospace() << "QML Document: " << output->url.toString();
3693     for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3694         const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3695         qWarning().nospace() << "    Component Line " << stat.lineNumber;
3696         qWarning().nospace() << "        Total Objects:      " << stat.objects;
3697         qWarning().nospace() << "        IDs Used:           " << stat.ids;
3698         qWarning().nospace() << "        Optimized Bindings: " << stat.optimizedBindings.count();
3699
3700         {
3701         QByteArray output;
3702         for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3703             if (0 == (ii % 10)) {
3704                 if (ii) output.append("\n");
3705                 output.append("            ");
3706             }
3707
3708             output.append('(');
3709             output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3710             output.append(':');
3711             output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3712             output.append(") ");
3713         }
3714         if (!output.isEmpty())
3715             qWarning().nospace() << output.constData();
3716         }
3717
3718         qWarning().nospace() << "        Shared Bindings:    " << stat.sharedBindings.count();
3719         {
3720         QByteArray output;
3721         for (int ii = 0; ii < stat.sharedBindings.count(); ++ii) {
3722             if (0 == (ii % 10)) {
3723                 if (ii) output.append('\n');
3724                 output.append("            ");
3725             }
3726
3727             output.append('(');
3728             output.append(QByteArray::number(stat.sharedBindings.at(ii).start.line));
3729             output.append(':');
3730             output.append(QByteArray::number(stat.sharedBindings.at(ii).start.column));
3731             output.append(") ");
3732         }
3733         if (!output.isEmpty())
3734             qWarning().nospace() << output.constData();
3735         }
3736
3737         qWarning().nospace() << "        QScript Bindings:   " << stat.scriptBindings.count();
3738         {
3739         QByteArray output;
3740         for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3741             if (0 == (ii % 10)) {
3742                 if (ii) output.append('\n');
3743                 output.append("            ");
3744             }
3745
3746             output.append('(');
3747             output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3748             output.append(':');
3749             output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3750             output.append(") ");
3751         }
3752         if (!output.isEmpty())
3753             qWarning().nospace() << output.constData();
3754         }
3755     }
3756 }
3757
3758 /*!
3759     Returns true if from can be assigned to a (QObject) property of type
3760     to.
3761 */
3762 bool QQmlCompiler::canCoerce(int to, QQmlScript::Object *from)
3763 {
3764     QQmlPropertyCache *toMo = enginePrivate->rawPropertyCacheForType(to);
3765     QQmlPropertyCache *fromMo = from->metatype;
3766
3767     while (fromMo) {
3768         if (fromMo == toMo)
3769             return true;
3770         fromMo = fromMo->parent();
3771     }
3772     return false;
3773 }
3774
3775 /*!
3776     Returns the element name, as written in the QML file, for o.
3777 */
3778 QString QQmlCompiler::elementName(QQmlScript::Object *o)
3779 {
3780     Q_ASSERT(o);
3781     if (o->type != -1) {
3782         return unit->parser().referencedTypes().at(o->type)->name;
3783     } else {
3784         return QString();
3785     }
3786 }
3787
3788 QQmlType *QQmlCompiler::toQmlType(QQmlScript::Object *from)
3789 {
3790     if (from->type != -1 && output->types.at(from->type).type)
3791         return output->types.at(from->type).type;
3792
3793     const QMetaObject *mo = from->metatype->firstCppMetaObject();
3794     QQmlType *type = 0;
3795     while (!type && mo) {
3796         type = QQmlMetaType::qmlType(mo);
3797         mo = mo->superClass();
3798     }
3799    return type;
3800 }
3801
3802 QStringList QQmlCompiler::deferredProperties(QQmlScript::Object *obj)
3803 {
3804     const QMetaObject *mo = obj->metatype->firstCppMetaObject();
3805
3806     int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3807     if (idx == -1)
3808         return QStringList();
3809
3810     QMetaClassInfo classInfo = mo->classInfo(idx);
3811     QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3812     return rv;
3813 }
3814
3815 QQmlPropertyCache *
3816 QQmlCompiler::propertyCacheForObject(QQmlScript::Object *object)
3817  {
3818      if (object->synthCache)
3819         return object->synthCache;
3820      else if (object->type != -1)
3821         return output->types[object->type].createPropertyCache(engine);
3822      else
3823         return object->metatype;
3824 }
3825
3826 QQmlPropertyData *
3827 QQmlCompiler::property(QQmlScript::Object *object, int index)
3828 {
3829     QQmlPropertyCache *cache = propertyCacheForObject(object);
3830
3831     return cache->property(index);
3832 }
3833
3834 QQmlPropertyData *
3835 QQmlCompiler::property(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3836 {
3837     if (notInRevision) *notInRevision = false;
3838
3839     QQmlPropertyCache *cache = propertyCacheForObject(object);
3840
3841     QQmlPropertyData *d = cache->property(name);
3842
3843     // Find the first property
3844     while (d && d->isFunction())
3845         d = cache->overrideData(d);
3846
3847     if (d && !cache->isAllowedInRevision(d)) {
3848         if (notInRevision) *notInRevision = true;
3849         return 0;
3850     } else {
3851         return d;
3852     }
3853 }
3854
3855 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3856 QQmlPropertyData *
3857 QQmlCompiler::signal(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3858 {
3859     if (notInRevision) *notInRevision = false;
3860
3861     QQmlPropertyCache *cache = propertyCacheForObject(object);
3862
3863
3864     QQmlPropertyData *d = cache->property(name);
3865     if (notInRevision) *notInRevision = false;
3866
3867     while (d && !(d->isFunction()))
3868         d = cache->overrideData(d);
3869
3870     if (d && !cache->isAllowedInRevision(d)) {
3871         if (notInRevision) *notInRevision = true;
3872         return 0;
3873     } else if (d && d->isSignal()) {
3874         return d;
3875     }
3876
3877     if (name.endsWith(Changed_string)) {
3878         QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3879
3880         d = property(object, propName, notInRevision);
3881         if (d) 
3882             return cache->signal(d->notifyIndex);
3883     }
3884
3885     return 0;
3886 }
3887
3888 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3889 int QQmlCompiler::indexOfSignal(QQmlScript::Object *object, const QString &name, 
3890                                         bool *notInRevision)
3891 {
3892     QQmlPropertyData *d = signal(object, QStringRef(&name), notInRevision);
3893     return d?d->coreIndex:-1;
3894 }
3895
3896 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QString &name, 
3897                                           bool *notInRevision)
3898 {
3899     return indexOfProperty(object, QStringRef(&name), notInRevision);
3900 }
3901
3902 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QHashedStringRef &name, 
3903                                           bool *notInRevision)
3904 {
3905     QQmlPropertyData *d = property(object, name, notInRevision);
3906     return d?d->coreIndex:-1;
3907 }
3908
3909 QT_END_NAMESPACE