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