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