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