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