Adapt to connection-related changes in qtbase
[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 bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
2484                                                        QQmlScript::Object *obj,
2485                                                        QQmlScript::Value *v,
2486                                                        bool *isAssignment)
2487 {
2488     bool isIntProp = (prop->core.propType == QMetaType::Int) && !prop->core.isEnum();
2489     *isAssignment = false;
2490     if (!prop->core.isEnum() && !isIntProp)
2491         return true;
2492
2493     QMetaProperty mprop = obj->metatype->firstCppMetaObject()->property(prop->index);
2494
2495     if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2496         COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2497
2498     QString string = v->value.asString();
2499     if (!string.at(0).isUpper())
2500         return true;
2501
2502     int dot = string.indexOf(QLatin1Char('.'));
2503     if (dot == -1 || dot == string.length()-1)
2504         return true;
2505
2506     if (string.indexOf(QLatin1Char('.'), dot+1) != -1)
2507         return true;
2508
2509     QHashedStringRef typeName(string.constData(), dot);
2510     QString enumValue = string.mid(dot+1);
2511
2512     if (isIntProp) {
2513         // Allow enum assignment to ints.
2514         int enumval = evaluateEnum(typeName, enumValue.toUtf8());
2515         if (enumval != -1) {
2516             v->type = Value::Literal;
2517             v->value = QQmlScript::Variant((double)enumval);
2518             *isAssignment = true;
2519         }
2520         return true;
2521     }
2522
2523     QQmlType *type = 0;
2524     unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
2525
2526     if (!type)
2527         return true;
2528
2529     int value = 0;
2530     bool ok;
2531
2532     if (toQmlType(obj) == type) {
2533         // When these two match, we can short cut the search
2534         if (mprop.isFlagType()) {
2535             value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
2536         } else {
2537             value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
2538         }
2539     } else {
2540         // Otherwise we have to search the whole type
2541         // This matches the logic in QV8TypeWrapper
2542         QByteArray enumName = enumValue.toUtf8();
2543         const QMetaObject *metaObject = type->baseMetaObject();
2544         ok = false;
2545         for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
2546             QMetaEnum e = metaObject->enumerator(ii);
2547             value = e.keyToValue(enumName.constData(), &ok);
2548         }
2549     }
2550
2551     if (!ok)
2552         return true;
2553
2554     v->type = Value::Literal;
2555     v->value = QQmlScript::Variant((double)value);
2556     *isAssignment = true;
2557
2558     return true;
2559 }
2560
2561 struct StaticQtMetaObject : public QObject
2562 {
2563     static const QMetaObject *get()
2564         { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2565 };
2566
2567 // Similar logic to above, but not knowing target property.
2568 int QQmlCompiler::evaluateEnum(const QHashedStringRef &scope, const QByteArray& enumValue) const
2569 {
2570     QQmlType *type = 0;
2571     if (scope != QLatin1String("Qt")) {
2572         unit->imports().resolveType(scope, &type, 0, 0, 0, 0);
2573         if (!type)
2574             return -1;
2575
2576     }
2577     const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2578     int i = mo->enumeratorCount();
2579     while (i--) {
2580         bool ok;
2581         int v = mo->enumerator(i).keyToValue(enumValue.constData(), &ok);
2582         if (ok)
2583             return v;
2584     }
2585     return -1;
2586 }
2587
2588 const QMetaObject *QQmlCompiler::resolveType(const QString& name) const
2589 {
2590     QQmlType *qmltype = 0;
2591     if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2592         return 0;
2593     if (!qmltype)
2594         return 0;
2595     return qmltype->metaObject();
2596 }
2597
2598 // similar to logic of completeComponentBuild, but also sticks data
2599 // into primitives at the end
2600 int QQmlCompiler::rewriteBinding(const QQmlScript::Variant& value, const QString& name)
2601 {
2602     QQmlRewrite::RewriteBinding rewriteBinding;
2603     rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1));
2604
2605     QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0);
2606
2607     return output->indexForString(rewrite);
2608 }
2609
2610 QString QQmlCompiler::rewriteSignalHandler(const QQmlScript::Variant& value, const QString &name)
2611 {
2612     QQmlRewrite::RewriteSignalHandler rewriteSignalHandler;
2613     return rewriteSignalHandler(value.asAST(), value.asScript(), name);
2614 }
2615
2616 // Ensures that the dynamic meta specification on obj is valid
2617 bool QQmlCompiler::checkDynamicMeta(QQmlScript::Object *obj)
2618 {
2619     bool seenDefaultProperty = false;
2620
2621     // We use a coarse grain, 31 bit hash to check if there are duplicates.
2622     // Calculating the hash for the names is not a waste as we have to test
2623     // them against the illegalNames set anyway.
2624     QHashField propNames;
2625     QHashField methodNames;
2626
2627     // Check properties
2628     for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2629         const QQmlScript::Object::DynamicProperty &prop = *p;
2630
2631         if (prop.isDefaultProperty) {
2632             if (seenDefaultProperty)
2633                 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2634             seenDefaultProperty = true;
2635         }
2636
2637         if (propNames.testAndSet(prop.name.hash())) {
2638             for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p; 
2639                  p2 = obj->dynamicProperties.next(p2)) {
2640                 if (p2->name == prop.name) {
2641                     COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2642                                                prop.nameLocation.column,
2643                                                tr("Duplicate property name"));
2644                 }
2645             }
2646         }
2647
2648         if (prop.name.at(0).isUpper()) {
2649             COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2650                                        prop.nameLocation.column,
2651                                        tr("Property names cannot begin with an upper case letter"));
2652         }
2653
2654         if (enginePrivate->v8engine()->illegalNames().contains(prop.name)) {
2655             COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
2656                                        prop.nameLocation.column,
2657                                        tr("Illegal property name"));
2658         }
2659     }
2660
2661     for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2662         const QQmlScript::Object::DynamicSignal &currSig = *s;
2663
2664         if (methodNames.testAndSet(currSig.name.hash())) {
2665             for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2666                  s2 = obj->dynamicSignals.next(s2)) {
2667                 if (s2->name == currSig.name)
2668                     COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2669             }
2670         }
2671
2672         if (currSig.name.at(0).isUpper())
2673             COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2674         if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2675             COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2676     }
2677
2678     for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2679         const QQmlScript::Object::DynamicSlot &currSlot = *s;
2680
2681         if (methodNames.testAndSet(currSlot.name.hash())) {
2682             for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2683                  s2 = obj->dynamicSignals.next(s2)) {
2684                 if (s2->name == currSlot.name)
2685                     COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2686             }
2687             for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2688                  s2 = obj->dynamicSlots.next(s2)) {
2689                 if (s2->name == currSlot.name)
2690                     COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2691             }
2692         }
2693
2694         if (currSlot.name.at(0).isUpper())
2695             COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2696         if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2697             COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2698     }
2699
2700     return true;
2701 }
2702
2703 bool QQmlCompiler::mergeDynamicMetaProperties(QQmlScript::Object *obj)
2704 {
2705     for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2706          p = obj->dynamicProperties.next(p)) {
2707
2708         if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2709             continue;
2710
2711         Property *property = 0;
2712         if (p->isDefaultProperty) {
2713             property = obj->getDefaultProperty();
2714         } else {
2715             property = obj->getProperty(p->name);
2716             if (!property->values.isEmpty()) 
2717                 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2718         }
2719
2720         if (p->isReadOnly)
2721             property->isReadOnlyDeclaration = true;
2722
2723         if (property->value)
2724             COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2725
2726         property->values.append(p->defaultValue->values);
2727     }
2728     return true;
2729 }
2730
2731 #include <private/qqmljsparser_p.h>
2732
2733 static QStringList astNodeToStringList(QQmlJS::AST::Node *node)
2734 {
2735     if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) {
2736         QString name =
2737             static_cast<QQmlJS::AST::IdentifierExpression *>(node)->name.toString();
2738         return QStringList() << name;
2739     } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) {
2740         QQmlJS::AST::FieldMemberExpression *expr = static_cast<QQmlJS::AST::FieldMemberExpression *>(node);
2741
2742         QStringList rv = astNodeToStringList(expr->base);
2743         if (rv.isEmpty())
2744             return rv;
2745         rv.append(expr->name.toString());
2746         return rv;
2747     }
2748     return QStringList();
2749 }
2750
2751 static QAtomicInt classIndexCounter(0);
2752
2753 bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mode)
2754 {
2755     Q_ASSERT(obj);
2756     Q_ASSERT(obj->metatype);
2757
2758     if (mode != ForceCreation &&
2759         obj->dynamicProperties.isEmpty() &&
2760         obj->dynamicSignals.isEmpty() &&
2761         obj->dynamicSlots.isEmpty())
2762         return true;
2763
2764     Q_ASSERT(obj->synthCache == 0);
2765
2766     struct TypeData {
2767         Object::DynamicProperty::Type dtype;
2768         int metaType;
2769     } builtinTypes[] = {
2770         { Object::DynamicProperty::Var, QMetaType::QVariant },
2771         { Object::DynamicProperty::Variant, QMetaType::QVariant },
2772         { Object::DynamicProperty::Int, QMetaType::Int },
2773         { Object::DynamicProperty::Bool, QMetaType::Bool },
2774         { Object::DynamicProperty::Real, QMetaType::Double },
2775         { Object::DynamicProperty::String, QMetaType::QString },
2776         { Object::DynamicProperty::Url, QMetaType::QUrl },
2777         { Object::DynamicProperty::Color, QMetaType::QColor },
2778         { Object::DynamicProperty::Time, QMetaType::QTime },
2779         { Object::DynamicProperty::Date, QMetaType::QDate },
2780         { Object::DynamicProperty::DateTime, QMetaType::QDateTime },
2781         { Object::DynamicProperty::Rect, QMetaType::QRectF },
2782     };
2783     static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2784
2785     QByteArray newClassName;
2786
2787     if (compileState->root == obj && !compileState->nested) {
2788         QString path = output->url.path();
2789         int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2790         if (lastSlash > -1) {
2791             QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2792             if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2793                 newClassName = nameBase.toUtf8() + "_QMLTYPE_" +
2794                                QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
2795         }
2796     }
2797     if (newClassName.isEmpty()) {
2798         newClassName = QQmlMetaObject(obj->metatype).className();
2799         newClassName.append("_QML_");
2800         newClassName.append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)));
2801     }
2802     QQmlPropertyCache *cache = obj->metatype->copyAndReserve(engine, obj->dynamicProperties.count(),
2803                                                              obj->dynamicProperties.count() +
2804                                                              obj->dynamicSignals.count() +
2805                                                              obj->dynamicSlots.count(),
2806                                                              obj->dynamicProperties.count() +
2807                                                              obj->dynamicSignals.count());
2808
2809     cache->_dynamicClassName = newClassName;
2810
2811     int cStringNameCount = 0;
2812
2813     int aliasCount = 0;
2814     int varPropCount = 0;
2815
2816     for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2817          p = obj->dynamicProperties.next(p)) {
2818
2819         if (p->type == Object::DynamicProperty::Alias)
2820             aliasCount++;
2821         else if (p->type == Object::DynamicProperty::Var)
2822             varPropCount++;
2823
2824         if (p->name.isLatin1()) {
2825             p->nameIndex = cStringNameCount;
2826             cStringNameCount += p->name.length() + 7 /* strlen("Changed") */;
2827         }
2828
2829         // No point doing this for both the alias and non alias cases
2830         QQmlPropertyData *d = property(obj, p->name);
2831         if (d && d->isFinal())
2832             COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2833     }
2834
2835     for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2836         if (s->name.isLatin1()) {
2837             s->nameIndex = cStringNameCount;
2838             cStringNameCount += s->name.length();
2839         }
2840     }
2841
2842     for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2843         if (s->name.isLatin1()) {
2844             s->nameIndex = cStringNameCount;
2845             cStringNameCount += s->name.length();
2846         }
2847     }
2848
2849     char *cStringData = 0;
2850     if (cStringNameCount) {
2851         cache->_dynamicStringData.resize(cStringNameCount);
2852         cStringData = cache->_dynamicStringData.data();
2853
2854         for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2855              p = obj->dynamicProperties.next(p)) {
2856
2857             if (p->nameIndex == -1) continue;
2858
2859             char *myData = cStringData + p->nameIndex;
2860             for (int ii = 0; ii < p->name.length(); ++ii)
2861                 *myData++ = p->name.at(ii).unicode();
2862             *myData++ = 'C'; *myData++ = 'h'; *myData++ = 'a'; *myData++ = 'n';
2863             *myData++ = 'g'; *myData++ = 'e'; *myData++ = 'd';
2864         }
2865
2866         for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2867
2868             if (s->nameIndex == -1) continue;
2869
2870             char *myData = cStringData + s->nameIndex;
2871             for (int ii = 0; ii < s->name.length(); ++ii)
2872                 *myData++ = s->name.at(ii).unicode();
2873         }
2874
2875         for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s;
2876              s = obj->dynamicSignals.next(s)) {
2877
2878             if (s->nameIndex == -1) continue;
2879
2880             char *myData = cStringData + s->nameIndex;
2881             for (int ii = 0; ii < s->name.length(); ++ii)
2882                 *myData++ = s->name.at(ii).unicode();
2883         }
2884     }
2885
2886     QByteArray dynamicData;
2887     typedef QQmlVMEMetaData VMD;
2888
2889     dynamicData = QByteArray(sizeof(QQmlVMEMetaData) +
2890                              obj->dynamicProperties.count() * sizeof(VMD::PropertyData) +
2891                              obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2892                              aliasCount * sizeof(VMD::AliasData), 0);
2893
2894     int effectivePropertyIndex = cache->propertyIndexCacheStart;
2895     int effectiveMethodIndex = cache->methodIndexCacheStart;
2896
2897     // First set up notify signals for properties - first normal, then var, then alias
2898     enum { NSS_Normal = 0, NSS_Var = 1, NSS_Alias = 2 };
2899     for (int ii = NSS_Normal; ii <= NSS_Alias; ++ii) { // 0 == normal, 1 == var, 2 == alias
2900
2901         if (ii == NSS_Var && varPropCount == 0) continue;
2902         else if (ii == NSS_Alias && aliasCount == 0) continue;
2903
2904         for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2905              p = obj->dynamicProperties.next(p)) {
2906
2907             if ((ii == NSS_Normal && (p->type == Object::DynamicProperty::Alias ||
2908                                       p->type == Object::DynamicProperty::Var)) ||
2909                 ((ii == NSS_Var) && (p->type != Object::DynamicProperty::Var)) ||
2910                 ((ii == NSS_Alias) && (p->type != Object::DynamicProperty::Alias)))
2911                 continue;
2912
2913             quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
2914                             QQmlPropertyData::IsVMESignal;
2915
2916             if (p->nameIndex != -1) {
2917                 QHashedCStringRef changedSignalName(cStringData + p->nameIndex,
2918                                                     p->name.length() + 7 /* strlen("Changed") */);
2919                 cache->appendSignal(changedSignalName, flags, effectiveMethodIndex++);
2920             } else {
2921                 QString changedSignalName = p->name.toString() + QLatin1String("Changed");
2922
2923                 cache->appendSignal(changedSignalName, flags, effectiveMethodIndex++);
2924             }
2925         }
2926     }
2927
2928     // Dynamic signals
2929     for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2930         int paramCount = s->parameterNames.count();
2931
2932         QList<QByteArray> names;
2933         QVarLengthArray<int, 10> paramTypes(paramCount?(paramCount + 1):0);
2934
2935         if (paramCount) {
2936             paramTypes[0] = paramCount;
2937
2938             for (int i = 0; i < paramCount; ++i) {
2939                 Q_ASSERT(s->parameterTypes.at(i) < builtinTypeCount);
2940                 paramTypes[i + 1] = builtinTypes[s->parameterTypes.at(i)].metaType;
2941                 names.append(s->parameterNames.at(i).toString().toUtf8());
2942             }
2943         }
2944
2945         ((QQmlVMEMetaData *)dynamicData.data())->signalCount++;
2946
2947         quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
2948                         QQmlPropertyData::IsVMESignal;
2949         if (paramCount)
2950             flags |= QQmlPropertyData::HasArguments;
2951
2952         if (s->nameIndex != -1) {
2953             QHashedCStringRef name(cStringData + s->nameIndex, s->name.length(), s->name.hash());
2954             cache->appendSignal(name, flags, effectiveMethodIndex++,
2955                                 paramCount?paramTypes.constData():0, names);
2956         } else {
2957             QString name = s->name.toString();
2958             cache->appendSignal(name, flags, effectiveMethodIndex++,
2959                                 paramCount?paramTypes.constData():0, names);
2960         }
2961     }
2962
2963
2964     // Dynamic slots
2965     for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2966         int paramCount = s->parameterNames.count();
2967
2968         quint32 flags = QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMEFunction;
2969
2970         if (paramCount)
2971             flags |= QQmlPropertyData::HasArguments;
2972
2973         if (s->nameIndex != -1) {
2974             QHashedCStringRef name(cStringData + s->nameIndex, s->name.length(), s->name.hash());
2975             cache->appendMethod(name, flags, effectiveMethodIndex++, s->parameterNames);
2976         } else {
2977             QString name = s->name.toString();
2978             cache->appendMethod(name, flags, effectiveMethodIndex++, s->parameterNames);
2979         }
2980     }
2981
2982
2983     // Dynamic properties (except var and aliases)
2984     int effectiveSignalIndex = cache->signalHandlerIndexCacheStart;
2985     for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2986          p = obj->dynamicProperties.next(p)) {
2987
2988         if (p->type == Object::DynamicProperty::Alias ||
2989             p->type == Object::DynamicProperty::Var)
2990             continue;
2991
2992         int propertyType = 0;
2993         int vmePropertyType = 0;
2994         quint32 propertyFlags = 0;
2995
2996         if (p->type < builtinTypeCount) {
2997             propertyType = builtinTypes[p->type].metaType;
2998             vmePropertyType = propertyType;
2999
3000             if (p->type == Object::DynamicProperty::Variant)
3001                 propertyFlags |= QQmlPropertyData::IsQVariant;
3002         } else {
3003             Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
3004                      p->type == Object::DynamicProperty::Custom);
3005
3006             QQmlType *qmltype = 0;
3007             QString url;
3008             if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
3009                 COMPILE_EXCEPTION(p, tr("Invalid property type"));
3010
3011             if (!qmltype) {
3012                 QQmlTypeData *tdata = enginePrivate->typeLoader.getType(QUrl(url));
3013                 Q_ASSERT(tdata);
3014                 Q_ASSERT(tdata->isComplete());
3015
3016                 QQmlCompiledData *data = tdata->compiledData();
3017
3018                 if (p->type == Object::DynamicProperty::Custom) {
3019                     propertyType = data->metaTypeId;
3020                     vmePropertyType = QMetaType::QObjectStar;
3021                 } else {
3022                     propertyType = data->listMetaTypeId;
3023                     vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >();
3024                 }
3025
3026                 tdata->release();
3027             } else {
3028                 if (p->type == Object::DynamicProperty::Custom) {
3029                     propertyType = qmltype->typeId();
3030                     vmePropertyType = QMetaType::QObjectStar;
3031                 } else {
3032                     propertyType = qmltype->qListTypeId();
3033                     vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >();
3034                 }
3035             }
3036
3037             if (p->type == Object::DynamicProperty::Custom)
3038                 propertyFlags |= QQmlPropertyData::IsQObjectDerived;
3039             else
3040                 propertyFlags |= QQmlPropertyData::IsQList;
3041         }
3042
3043         if (!p->isReadOnly && p->type != Object::DynamicProperty::CustomList)
3044             propertyFlags |= QQmlPropertyData::IsWritable;
3045
3046         if (p->nameIndex != -1) {
3047             QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(),
3048                                            p->name.hash());
3049             if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16();
3050             cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3051                                   propertyType, effectiveSignalIndex);
3052         } else {
3053             QString propertyName = p->name.toString();
3054             if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName;
3055             cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3056                                   propertyType, effectiveSignalIndex);
3057         }
3058
3059         effectiveSignalIndex++;
3060
3061         VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3062         (vmd->propertyData() + vmd->propertyCount)->propertyType = vmePropertyType;
3063         vmd->propertyCount++;
3064     }
3065
3066     // Now do var properties
3067     for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p && varPropCount;
3068          p = obj->dynamicProperties.next(p)) {
3069
3070         if (p->type != Object::DynamicProperty::Var)
3071             continue;
3072
3073         quint32 propertyFlags = QQmlPropertyData::IsVarProperty;
3074         if (!p->isReadOnly)
3075             propertyFlags |= QQmlPropertyData::IsWritable;
3076
3077         VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3078         (vmd->propertyData() + vmd->propertyCount)->propertyType = QMetaType::QVariant;
3079         vmd->propertyCount++;
3080         ((QQmlVMEMetaData *)dynamicData.data())->varPropertyCount++;
3081
3082         if (p->nameIndex != -1) {
3083             QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(),
3084                                            p->name.hash());
3085             if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16();
3086             cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3087                                   QMetaType::QVariant, effectiveSignalIndex);
3088         } else {
3089             QString propertyName = p->name.toString();
3090             if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName;
3091             cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3092                                   QMetaType::QVariant, effectiveSignalIndex);
3093         }
3094
3095         effectiveSignalIndex++;
3096     }
3097
3098     // Alias property count.  Actual data is setup in buildDynamicMetaAliases
3099     ((QQmlVMEMetaData *)dynamicData.data())->aliasCount = aliasCount;
3100
3101     // Dynamic slot data - comes after the property data
3102     for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
3103         int paramCount = s->parameterNames.count();
3104
3105         QString funcScript;
3106         int namesSize = 0;
3107         if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
3108         funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ +
3109                            namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
3110         funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
3111         for (int jj = 0; jj < paramCount; ++jj) {
3112             if (jj) funcScript.append(QLatin1Char(','));
3113             funcScript.append(QLatin1String(s->parameterNames.at(jj)));
3114         }
3115         funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
3116
3117         QByteArray utf8 = funcScript.toUtf8();
3118         VMD::MethodData methodData = { s->parameterNames.count(),
3119                                        dynamicData.size(),
3120                                        utf8.length(),
3121                                        s->location.start.line };
3122
3123         VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3124         VMD::MethodData &md = *(vmd->methodData() + vmd->methodCount);
3125         vmd->methodCount++;
3126         md = methodData;
3127
3128         dynamicData.append((const char *)utf8.constData(), utf8.length());
3129     }
3130
3131     if (aliasCount)
3132         compileState->aliasingObjects.append(obj);
3133
3134     obj->synthdata = dynamicData;
3135     obj->synthCache = cache;
3136     obj->metatype = cache;
3137
3138     return true;
3139 }
3140
3141 bool QQmlCompiler::buildDynamicMetaAliases(QQmlScript::Object *obj)
3142 {
3143     Q_ASSERT(obj->synthCache);
3144
3145     QByteArray &dynamicData = obj->synthdata;
3146
3147     QQmlPropertyCache *cache = obj->synthCache;
3148     char *cStringData = cache->_dynamicStringData.data();
3149
3150     int effectiveSignalIndex = cache->signalHandlerIndexCacheStart + cache->propertyIndexCache.count();
3151     int effectivePropertyIndex = cache->propertyIndexCacheStart + cache->propertyIndexCache.count();
3152     int effectiveAliasIndex = 0;
3153
3154     for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
3155          p = obj->dynamicProperties.next(p)) {
3156
3157         if (p->type != Object::DynamicProperty::Alias)
3158             continue;
3159
3160         if (!p->defaultValue)
3161             COMPILE_EXCEPTION(obj, tr("No property alias location"));
3162
3163         if (!p->defaultValue->values.isOne() ||
3164             p->defaultValue->values.first()->object ||
3165             !p->defaultValue->values.first()->value.isScript())
3166             COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3167
3168         QQmlJS::AST::Node *node = p->defaultValue->values.first()->value.asAST();
3169         Q_ASSERT(node);
3170
3171         QStringList alias = astNodeToStringList(node);
3172         if (alias.count() < 1 || alias.count() > 3)
3173             COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
3174
3175         QQmlScript::Object *idObject = compileState->ids.value(alias.at(0));
3176         if (!idObject)
3177             COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
3178
3179         int propIdx = -1;
3180         int notifySignal = -1;
3181         int flags = 0;
3182         int type = 0;
3183         bool writable = false;
3184         bool resettable = false;
3185
3186         quint32 propertyFlags = QQmlPropertyData::IsAlias;
3187
3188         if (alias.count() == 2 || alias.count() == 3) {
3189             QQmlPropertyData *property = this->property(idObject, alias.at(1));
3190
3191             if (!property || property->coreIndex > 0xFFFF)
3192                 COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3193
3194             propIdx = property->coreIndex;
3195             type = property->propType;
3196
3197             writable = property->isWritable();
3198             resettable = property->isResettable();
3199             notifySignal = property->notifyIndex;
3200
3201             if (alias.count() == 3) {
3202                 QQmlValueType *valueType = enginePrivate->valueTypes[type]; // XXX threadsafe?
3203                 if (!valueType)
3204                     COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3205
3206                 propIdx |= ((unsigned int)type) << 24;
3207                 int valueTypeIndex =
3208                     valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
3209                 if (valueTypeIndex == -1)
3210                     COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location"));
3211                 Q_ASSERT(valueTypeIndex <= 0xFF);
3212
3213                 propIdx |= (valueTypeIndex << 16);
3214                 if (valueType->metaObject()->property(valueTypeIndex).isEnumType())
3215                     type = QVariant::Int;
3216                 else
3217                     type = valueType->metaObject()->property(valueTypeIndex).userType();
3218
3219             } else {
3220                 if (property->isEnum()) {
3221                     type = QVariant::Int;
3222                 } else {
3223                     // Copy type flags
3224                     propertyFlags |= property->getFlags() & QQmlPropertyData::PropTypeFlagMask;
3225
3226                     if (property->isVarProperty())
3227                         propertyFlags |= QQmlPropertyData::IsQVariant;
3228
3229                     if (property->isQObject())
3230                         flags |= QML_ALIAS_FLAG_PTR;
3231                 }
3232             }
3233         } else {
3234             Q_ASSERT(idObject->type != -1); // How else did it get an id?
3235
3236             const QQmlCompiledData::TypeReference &ref = output->types.at(idObject->type);
3237             if (ref.type)
3238                 type = ref.type->typeId();
3239             else
3240                 type = ref.component->metaTypeId;
3241
3242             flags |= QML_ALIAS_FLAG_PTR;
3243             propertyFlags |= QQmlPropertyData::IsQObjectDerived;
3244         }
3245
3246         QQmlVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags, notifySignal };
3247
3248         typedef QQmlVMEMetaData VMD;
3249         VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
3250         *(vmd->aliasData() + effectiveAliasIndex++) = aliasData;
3251
3252         if (!p->isReadOnly && writable)
3253             propertyFlags |= QQmlPropertyData::IsWritable;
3254         else
3255             propertyFlags &= ~QQmlPropertyData::IsWritable;
3256
3257         if (resettable)
3258             propertyFlags |= QQmlPropertyData::IsResettable;
3259         else
3260             propertyFlags &= ~QQmlPropertyData::IsResettable;
3261
3262         if (p->nameIndex != -1) {
3263             QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(),
3264                                            p->name.hash());
3265             if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16();
3266             cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3267                                   type, effectiveSignalIndex++);
3268         } else {
3269             QString propertyName = p->name.toString();
3270             if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName;
3271             cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
3272                                   type, effectiveSignalIndex++);
3273         }
3274     }
3275
3276     return true;
3277 }
3278
3279 bool QQmlCompiler::checkValidId(QQmlScript::Value *v, const QString &val)
3280 {
3281     if (val.isEmpty())
3282         COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
3283
3284     QChar ch = val.at(0);
3285     if (ch.isLetter() && !ch.isLower())
3286         COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
3287
3288     QChar u(QLatin1Char('_'));
3289     if (!ch.isLetter() && ch != u)
3290         COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
3291
3292     for (int ii = 1; ii < val.count(); ++ii) {
3293         ch = val.at(ii);
3294         if (!ch.isLetterOrNumber() && ch != u)
3295             COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
3296     }
3297
3298     if (enginePrivate->v8engine()->illegalNames().contains(val))
3299         COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
3300
3301     return true;
3302 }
3303
3304 bool QQmlCompiler::buildBinding(QQmlScript::Value *value,
3305                                         QQmlScript::Property *prop,
3306                                         const BindingContext &ctxt)
3307 {
3308     Q_ASSERT(prop->index != -1);
3309     Q_ASSERT(prop->parent);
3310     Q_ASSERT(prop->parent->metatype);
3311
3312     if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
3313         COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3314
3315     JSBindingReference *reference = pool->New<JSBindingReference>();
3316     reference->expression = value->value;
3317     reference->property = prop;
3318     reference->value = value;
3319     reference->bindingContext = ctxt;
3320     addBindingReference(reference);
3321
3322     return true;
3323 }
3324
3325 bool QQmlCompiler::buildLiteralBinding(QQmlScript::Value *v,
3326                                                QQmlScript::Property *prop,
3327                                                const QQmlCompilerTypes::BindingContext &)
3328 {
3329     Q_ASSERT(v->value.isScript());
3330
3331     if (!prop->core.isWritable())
3332         return false;
3333
3334     AST::Node *binding = v->value.asAST();
3335
3336     if (prop->type == QVariant::String) {
3337         if (AST::CallExpression *e = AST::cast<AST::CallExpression *>(binding)) {
3338             if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(e->base)) {
3339                 if (i->name == qsTrId_string) {
3340                     AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3341                     AST::ArgumentList *arg2 = arg1?arg1->next:0;
3342
3343                     if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3344                         (!arg2 || arg2->expression->kind == AST::Node::Kind_NumericLiteral) &&
3345                         (!arg2 || !arg2->next)) {
3346
3347                         QStringRef text;
3348                         int n = -1;
3349
3350                         text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3351                         if (arg2) n = (int)AST::cast<AST::NumericLiteral *>(arg2->expression)->value;
3352
3353                         TrBindingReference *reference = pool->New<TrBindingReference>();
3354                         reference->dataType = BindingReference::TrId;
3355                         reference->text = text;
3356                         reference->n = n;
3357                         v->bindingReference = reference;
3358                         return true;
3359                     }
3360
3361                 } else if (i->name == qsTr_string) {
3362
3363                     AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
3364                     AST::ArgumentList *arg2 = arg1?arg1->next:0;
3365                     AST::ArgumentList *arg3 = arg2?arg2->next:0;
3366
3367                     if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
3368                         (!arg2 || arg2->expression->kind == AST::Node::Kind_StringLiteral) &&
3369                         (!arg3 || arg3->expression->kind == AST::Node::Kind_NumericLiteral) &&
3370                         (!arg3 || !arg3->next)) {
3371
3372                         QStringRef text;
3373                         QStringRef comment;
3374                         int n = -1;
3375
3376                         text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
3377                         if (arg2) comment = AST::cast<AST::StringLiteral *>(arg2->expression)->value;
3378                         if (arg3) n = (int)AST::cast<AST::NumericLiteral *>(arg3->expression)->value;
3379
3380                         TrBindingReference *reference = pool->New<TrBindingReference>();
3381                         reference->dataType = BindingReference::Tr;
3382                         reference->text = text;
3383                         reference->comment = comment;
3384                         reference->n = n;
3385                         v->bindingReference = reference;
3386                         return true;
3387                     }
3388
3389                 }
3390             }
3391         }
3392
3393     }
3394
3395     return false;
3396 }
3397
3398 void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
3399                                                 QQmlScript::Property *prop,
3400                                                 QQmlScript::Object *obj,
3401                                                 QQmlScript::Property *valueTypeProperty)
3402 {
3403     Q_UNUSED(obj);
3404     Q_ASSERT(binding->bindingReference);
3405
3406     const BindingReference &ref = *binding->bindingReference;
3407     if (ref.dataType == BindingReference::TrId) {
3408         const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3409
3410         Instruction::StoreTrIdString store;
3411         store.propertyIndex = prop->core.coreIndex;
3412         store.text = output->indexForByteArray(tr.text.toUtf8());
3413         store.n = tr.n;
3414         output->addInstruction(store);
3415     } else if (ref.dataType == BindingReference::Tr) {
3416         const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
3417
3418         Instruction::StoreTrString store;
3419         store.propertyIndex = prop->core.coreIndex;
3420         store.context = translationContextIndex();
3421         store.text = output->indexForByteArray(tr.text.toUtf8());
3422         store.comment = output->indexForByteArray(tr.comment.toUtf8());
3423         store.n = tr.n;
3424         output->addInstruction(store);
3425     } else if (ref.dataType == BindingReference::V4) {
3426         const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3427
3428         Instruction::StoreV4Binding store;
3429         store.value = js.compiledIndex;
3430         store.context = js.bindingContext.stack;
3431         store.owner = js.bindingContext.owner;
3432         store.isAlias = prop->isAlias;
3433         if (valueTypeProperty) {
3434             store.property = (valueTypeProperty->index & 0xFFFF) |
3435                              ((valueTypeProperty->type & 0xFF)) << 16 |
3436                              ((prop->index & 0xFF) << 24);
3437             store.isRoot = (compileState->root == valueTypeProperty->parent);
3438         } else {
3439             store.property = prop->index;
3440             store.isRoot = (compileState->root == obj);
3441         }
3442         store.line = binding->location.start.line;
3443         store.column = binding->location.start.column;
3444         output->addInstruction(store);
3445     } else if (ref.dataType == BindingReference::V8) {
3446         const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3447
3448         Instruction::StoreV8Binding store;
3449         store.value = js.compiledIndex;
3450         store.context = js.bindingContext.stack;
3451         store.owner = js.bindingContext.owner;
3452         store.isAlias = prop->isAlias;
3453         if (valueTypeProperty) {
3454             store.isRoot = (compileState->root == valueTypeProperty->parent);
3455         } else {
3456             store.isRoot = (compileState->root == obj);
3457         }
3458         store.line = binding->location.start.line;
3459         store.column = binding->location.start.column;
3460
3461         Q_ASSERT(js.bindingContext.owner == 0 ||
3462                  (js.bindingContext.owner != 0 && valueTypeProperty));
3463         if (js.bindingContext.owner) {
3464             store.property = genValueTypeData(prop, valueTypeProperty);
3465         } else {
3466             store.property = prop->core;
3467         }
3468
3469         output->addInstruction(store);
3470     } else if (ref.dataType == BindingReference::QtScript) {
3471         const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
3472
3473         Instruction::StoreBinding store;
3474         store.value = output->indexForString(js.rewrittenExpression);
3475         store.context = js.bindingContext.stack;
3476         store.owner = js.bindingContext.owner;
3477         store.line = binding->location.start.line;
3478         store.column = binding->location.start.column;
3479         store.isAlias = prop->isAlias;
3480
3481         if (valueTypeProperty) {
3482             store.isRoot = (compileState->root == valueTypeProperty->parent);
3483         } else {
3484             store.isRoot = (compileState->root == obj);
3485         }
3486
3487         Q_ASSERT(js.bindingContext.owner == 0 ||
3488                  (js.bindingContext.owner != 0 && valueTypeProperty));
3489         if (js.bindingContext.owner) {
3490             store.property = genValueTypeData(prop, valueTypeProperty);
3491         } else {
3492             store.property = prop->core;
3493         }
3494
3495         output->addInstruction(store);
3496     } else {
3497         Q_ASSERT(!"Unhandled BindingReference::DataType type");
3498     }
3499 }
3500
3501 int QQmlCompiler::genContextCache()
3502 {
3503     if (compileState->ids.count() == 0)
3504         return -1;
3505
3506     QQmlIntegerCache *cache = new QQmlIntegerCache();
3507     cache->reserve(compileState->ids.count());
3508     for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o)) 
3509         cache->add(o->id, o->idIndex);
3510
3511     output->contextCaches.append(cache);
3512     return output->contextCaches.count() - 1;
3513 }
3514
3515 QQmlPropertyData
3516 QQmlCompiler::genValueTypeData(QQmlScript::Property *valueTypeProp, 
3517                                        QQmlScript::Property *prop)
3518 {
3519     typedef QQmlPropertyPrivate QDPP;
3520     return QDPP::saveValueType(prop->core, enginePrivate->valueTypes[prop->type]->metaObject(),
3521                                valueTypeProp->index, engine);
3522 }
3523
3524 bool QQmlCompiler::completeComponentBuild()
3525 {
3526     if (componentStats)
3527         componentStats->componentStat.ids = compileState->ids.count();
3528
3529     for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject; 
3530          aliasObject = compileState->aliasingObjects.next(aliasObject)) 
3531         COMPILE_CHECK(buildDynamicMetaAliases(aliasObject));
3532
3533     QV4Compiler::Expression expr(unit->imports());
3534     expr.component = compileState->root;
3535     expr.ids = &compileState->ids;
3536     expr.importCache = output->importCache;
3537
3538     QV4Compiler bindingCompiler;
3539
3540     QList<JSBindingReference*> sharedBindings;
3541
3542     for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3543
3544         JSBindingReference &binding = *b;
3545
3546         // First try v4
3547         expr.context = binding.bindingContext.object;
3548         expr.property = binding.property;
3549         expr.expression = binding.expression;
3550
3551         int index = bindingCompiler.compile(expr, enginePrivate);
3552         if (index != -1) {
3553             binding.dataType = BindingReference::V4;
3554             binding.compiledIndex = index;
3555             if (componentStats)
3556                 componentStats->componentStat.optimizedBindings.append(b->value->location);
3557             continue;
3558         }
3559
3560         // Pre-rewrite the expression
3561         QString expression = binding.expression.asScript();
3562
3563         QQmlRewrite::RewriteBinding rewriteBinding;
3564         rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3565         bool isSharable = false;
3566         binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3567
3568         if (isSharable && binding.property->type != qMetaTypeId<QQmlBinding*>()) {
3569             binding.dataType = BindingReference::V8;
3570             sharedBindings.append(b);
3571
3572             if (componentStats)
3573                 componentStats->componentStat.sharedBindings.append(b->value->location);
3574         } else {
3575             binding.dataType = BindingReference::QtScript;
3576
3577             if (componentStats)
3578                 componentStats->componentStat.scriptBindings.append(b->value->location);
3579         }
3580     }
3581
3582     if (!sharedBindings.isEmpty()) {
3583         struct Sort {
3584             static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs)
3585             {
3586                 return lhs->value->location.start.line < rhs->value->location.start.line;
3587             }
3588         };
3589
3590         qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3591
3592         int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3593         int lineNumber = startLineNumber;
3594
3595         QByteArray functionArray("[", 1);
3596         for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3597
3598             JSBindingReference *reference = sharedBindings.at(ii);
3599             QQmlScript::Value *value = reference->value;
3600             const QString &expression = reference->rewrittenExpression;
3601
3602             if (ii != 0) functionArray.append(",", 1);
3603
3604             while (lineNumber < value->location.start.line) {
3605                 lineNumber++;
3606                 functionArray.append("\n", 1);
3607             }
3608
3609             functionArray += expression.toUtf8();
3610             lineNumber += expression.count(QLatin1Char('\n'));
3611             reference->compiledIndex = ii;
3612         }
3613         functionArray.append("]", 1);
3614
3615         compileState->v8BindingProgram = functionArray;
3616         compileState->v8BindingProgramLine = startLineNumber;
3617     }
3618
3619     if (bindingCompiler.isValid()) 
3620         compileState->compiledBindingData = bindingCompiler.program();
3621
3622     // Check pop()'s matched push()'s
3623     Q_ASSERT(compileState->objectDepth.depth() == 0);
3624     Q_ASSERT(compileState->listDepth.depth() == 0);
3625
3626     saveComponentState();
3627
3628     return true;
3629 }
3630
3631 void QQmlCompiler::dumpStats()
3632 {
3633     Q_ASSERT(componentStats);
3634     qWarning().nospace() << "QML Document: " << output->url.toString();
3635     for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3636         const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3637         qWarning().nospace() << "    Component Line " << stat.lineNumber;
3638         qWarning().nospace() << "        Total Objects:      " << stat.objects;
3639         qWarning().nospace() << "        IDs Used:           " << stat.ids;
3640         qWarning().nospace() << "        Optimized Bindings: " << stat.optimizedBindings.count();
3641
3642         {
3643         QByteArray output;
3644         for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3645             if (0 == (ii % 10)) {
3646                 if (ii) output.append("\n");
3647                 output.append("            ");
3648             }
3649
3650             output.append('(');
3651             output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3652             output.append(':');
3653             output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3654             output.append(") ");
3655         }
3656         if (!output.isEmpty())
3657             qWarning().nospace() << output.constData();
3658         }
3659
3660         qWarning().nospace() << "        Shared Bindings:    " << stat.sharedBindings.count();
3661         {
3662         QByteArray output;
3663         for (int ii = 0; ii < stat.sharedBindings.count(); ++ii) {
3664             if (0 == (ii % 10)) {
3665                 if (ii) output.append('\n');
3666                 output.append("            ");
3667             }
3668
3669             output.append('(');
3670             output.append(QByteArray::number(stat.sharedBindings.at(ii).start.line));
3671             output.append(':');
3672             output.append(QByteArray::number(stat.sharedBindings.at(ii).start.column));
3673             output.append(") ");
3674         }
3675         if (!output.isEmpty())
3676             qWarning().nospace() << output.constData();
3677         }
3678
3679         qWarning().nospace() << "        QScript Bindings:   " << stat.scriptBindings.count();
3680         {
3681         QByteArray output;
3682         for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3683             if (0 == (ii % 10)) {
3684                 if (ii) output.append('\n');
3685                 output.append("            ");
3686             }
3687
3688             output.append('(');
3689             output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3690             output.append(':');
3691             output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3692             output.append(") ");
3693         }
3694         if (!output.isEmpty())
3695             qWarning().nospace() << output.constData();
3696         }
3697     }
3698 }
3699
3700 /*!
3701     Returns true if from can be assigned to a (QObject) property of type
3702     to.
3703 */
3704 bool QQmlCompiler::canCoerce(int to, QQmlScript::Object *from)
3705 {
3706     QQmlPropertyCache *toMo = enginePrivate->rawPropertyCacheForType(to);
3707     QQmlPropertyCache *fromMo = from->metatype;
3708
3709     while (fromMo) {
3710         if (fromMo == toMo)
3711             return true;
3712         fromMo = fromMo->parent();
3713     }
3714     return false;
3715 }
3716
3717 /*!
3718     Returns the element name, as written in the QML file, for o.
3719 */
3720 QString QQmlCompiler::elementName(QQmlScript::Object *o)
3721 {
3722     Q_ASSERT(o);
3723     if (o->type != -1) {
3724         return unit->parser().referencedTypes().at(o->type)->name;
3725     } else {
3726         return QString();
3727     }
3728 }
3729
3730 QQmlType *QQmlCompiler::toQmlType(QQmlScript::Object *from)
3731 {
3732     if (from->type != -1 && output->types.at(from->type).type)
3733         return output->types.at(from->type).type;
3734
3735     const QMetaObject *mo = from->metatype->firstCppMetaObject();
3736     QQmlType *type = 0;
3737     while (!type && mo) {
3738         type = QQmlMetaType::qmlType(mo);
3739         mo = mo->superClass();
3740     }
3741    return type;
3742 }
3743
3744 QStringList QQmlCompiler::deferredProperties(QQmlScript::Object *obj)
3745 {
3746     const QMetaObject *mo = obj->metatype->firstCppMetaObject();
3747
3748     int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3749     if (idx == -1)
3750         return QStringList();
3751
3752     QMetaClassInfo classInfo = mo->classInfo(idx);
3753     QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3754     return rv;
3755 }
3756
3757 QQmlPropertyCache *
3758 QQmlCompiler::propertyCacheForObject(QQmlScript::Object *object)
3759  {
3760      if (object->synthCache)
3761         return object->synthCache;
3762      else if (object->type != -1)
3763         return output->types[object->type].createPropertyCache(engine);
3764      else
3765         return object->metatype;
3766 }
3767
3768 QQmlPropertyData *
3769 QQmlCompiler::property(QQmlScript::Object *object, int index)
3770 {
3771     QQmlPropertyCache *cache = propertyCacheForObject(object);
3772
3773     return cache->property(index);
3774 }
3775
3776 QQmlPropertyData *
3777 QQmlCompiler::property(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3778 {
3779     if (notInRevision) *notInRevision = false;
3780
3781     QQmlPropertyCache *cache = propertyCacheForObject(object);
3782
3783     QQmlPropertyData *d = cache->property(name);
3784
3785     // Find the first property
3786     while (d && d->isFunction())
3787         d = cache->overrideData(d);
3788
3789     if (d && !cache->isAllowedInRevision(d)) {
3790         if (notInRevision) *notInRevision = true;
3791         return 0;
3792     } else {
3793         return d;
3794     }
3795 }
3796
3797 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3798 QQmlPropertyData *
3799 QQmlCompiler::signal(QQmlScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3800 {
3801     if (notInRevision) *notInRevision = false;
3802
3803     QQmlPropertyCache *cache = propertyCacheForObject(object);
3804
3805
3806     QQmlPropertyData *d = cache->property(name);
3807     if (notInRevision) *notInRevision = false;
3808
3809     while (d && !(d->isFunction()))
3810         d = cache->overrideData(d);
3811
3812     if (d && !cache->isAllowedInRevision(d)) {
3813         if (notInRevision) *notInRevision = true;
3814         return 0;
3815     } else if (d) {
3816         return d;
3817     }
3818
3819     if (name.endsWith(Changed_string)) {
3820         QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3821
3822         d = property(object, propName, notInRevision);
3823         if (d) 
3824             return cache->signal(d->notifyIndex);
3825     }
3826
3827     return 0;
3828 }
3829
3830 // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
3831 int QQmlCompiler::indexOfSignal(QQmlScript::Object *object, const QString &name, 
3832                                         bool *notInRevision)
3833 {
3834     QQmlPropertyData *d = signal(object, QStringRef(&name), notInRevision);
3835     return d?d->coreIndex:-1;
3836 }
3837
3838 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QString &name, 
3839                                           bool *notInRevision)
3840 {
3841     return indexOfProperty(object, QStringRef(&name), notInRevision);
3842 }
3843
3844 int QQmlCompiler::indexOfProperty(QQmlScript::Object *object, const QHashedStringRef &name, 
3845                                           bool *notInRevision)
3846 {
3847     QQmlPropertyData *d = property(object, name, notInRevision);
3848     return d?d->coreIndex:-1;
3849 }
3850
3851 QT_END_NAMESPACE