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