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