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