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