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