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