Use strings more conservatively
[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(QHashedStringRef(&name));
129 }
130
131 bool QDeclarativeCompiler::isAttachedPropertyName(const QHashedStringRef &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 QHashedStringRef &name)
153 {
154     if (name.length() < 3) return false;
155     if (!name.startsWith(on_string)) return false;
156     int ns = name.length();
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 QHashedStringRef &string)
781 {
782     for (int ii = 0; ii < list.count(); ++ii)
783         if (string == list.at(ii))
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     const QHashedStringRef &propName = prop->name();
1417
1418     Q_ASSERT(propName.startsWith(on_string));
1419     QString name = propName.mid(2, -1).toString();
1420
1421     // Note that the property name could start with any alpha or '_' or '$' character,
1422     // so we need to do the lower-casing of the first alpha character.
1423     for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1424         if (QDeclarativeUtils::isUpper(name.at(firstAlphaIndex))) {
1425             name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1426             break;
1427         }
1428     }
1429
1430     bool notInRevision = false;
1431
1432     QDeclarativePropertyCache::Data *sig = signal(obj, QStringRef(&name), &notInRevision);
1433
1434     if (sig == 0) {
1435
1436         if (notInRevision && 0 == property(obj, propName, 0)) {
1437             Q_ASSERT(obj->type != -1);
1438             const QList<QDeclarativeTypeData::TypeReference>  &resolvedTypes = unit->resolvedTypes();
1439             const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1440             if (type.type) {
1441                 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));
1442             } else {
1443                 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1444             }
1445         }
1446
1447         // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1448         // property.
1449         COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1450
1451     }  else {
1452
1453         if (prop->value || !prop->values.isOne())
1454             COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1455
1456         prop->index = sig->coreIndex;
1457         prop->core = *sig;
1458
1459         obj->addSignalProperty(prop);
1460
1461         if (prop->values.first()->object) {
1462             COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1463             prop->values.first()->type = Value::SignalObject;
1464         } else {
1465             prop->values.first()->type = Value::SignalExpression;
1466
1467             if (!prop->values.first()->value.isScript())
1468                 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1469
1470             QString script = prop->values.first()->value.asScript().trimmed();
1471             if (script.isEmpty())
1472                 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1473
1474             prop->values.first()->signalExpressionContextStack = ctxt.stack;
1475         }
1476     }
1477
1478     return true;
1479 }
1480
1481
1482 /*!
1483     Returns true if (value) property \a prop exists on obj, false otherwise.
1484 */
1485 bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeParser::Property *prop,
1486                                              QDeclarativeParser::Object *obj)
1487 {
1488     if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1489         return true;
1490
1491     if (prop->isDefault) {
1492         const QMetaObject *mo = obj->metaObject();
1493         QMetaProperty p = QDeclarativeMetaType::defaultProperty(mo);
1494         return p.name() != 0;
1495     } else {
1496         return property(obj, prop->name()) != 0;
1497     }
1498 }
1499
1500 bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop,
1501                                          QDeclarativeParser::Object *obj,
1502                                          const BindingContext &ctxt)
1503 {
1504     if (prop->isEmpty()) 
1505         COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1506
1507     const QMetaObject *metaObject = obj->metaObject();
1508     Q_ASSERT(metaObject);
1509
1510     if (isAttachedPropertyName(prop->name())) {
1511         // Setup attached property data
1512
1513         if (ctxt.isSubContext()) {
1514             // Attached properties cannot be used on sub-objects.  Sub-objects
1515             // always exist in a binding sub-context, which is what we test
1516             // for here.
1517             COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1518         }
1519
1520         QDeclarativeType *type = 0;
1521         QDeclarativeImportedNamespace *typeNamespace = 0;
1522         unit->imports().resolveType(prop->name().toUtf8(), &type, 0, 0, 0, &typeNamespace);
1523
1524         if (typeNamespace) {
1525             COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj, 
1526                                                    ctxt));
1527             return true;
1528         } else if (!type || !type->attachedPropertiesType())  {
1529             COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1530         }
1531
1532         if (!prop->value)
1533             COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1534
1535         Q_ASSERT(type->attachedPropertiesFunction());
1536         prop->index = type->attachedPropertiesId();
1537         prop->value->metatype = type->attachedPropertiesType();
1538     } else {
1539         // Setup regular property data
1540
1541         if (prop->isDefault) {
1542             QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
1543
1544             if (p.name()) {
1545                 prop->setName(QString::fromLatin1(p.name()));
1546
1547                 QDeclarativePropertyCache::Data *d = property(obj, p.propertyIndex());
1548                 prop->index = d->coreIndex;
1549                 prop->core = *d;
1550             }
1551
1552         } else {
1553             bool notInRevision = false;
1554             QDeclarativePropertyCache::Data *d = property(obj, prop->name(), &notInRevision);
1555
1556             if (d == 0 && notInRevision) {
1557                 const QList<QDeclarativeTypeData::TypeReference>  &resolvedTypes = unit->resolvedTypes();
1558                 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1559                 if (type.type) {
1560                     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));
1561                 } else {
1562                     COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1563                 }
1564             } else if (d) {
1565                 prop->index = d->coreIndex;
1566                 prop->core = *d;
1567             }
1568         }
1569
1570         // We can't error here as the "id" property does not require a
1571         // successful index resolution
1572         if (prop->index != -1) 
1573             prop->type = prop->core.propType;
1574
1575         // Check if this is an alias
1576         if (prop->index != -1 && 
1577             prop->parent && 
1578             prop->parent->type != -1 && 
1579             output->types.at(prop->parent->type).component) {
1580
1581             QDeclarativePropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1582             if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1583                 prop->isAlias = true;
1584         }
1585
1586         if (prop->index != -1 && !prop->values.isEmpty()) 
1587             prop->parent->setBindingBit(prop->index);
1588     }
1589
1590     if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1591
1592         // The magic "id" behavior doesn't apply when "id" is resolved as a
1593         // default property or to sub-objects (which are always in binding
1594         // sub-contexts)
1595         COMPILE_CHECK(buildIdProperty(prop, obj));
1596         if (prop->type == QVariant::String &&
1597             prop->values.first()->value.isString())
1598             COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1599
1600     } else if (isAttachedPropertyName(prop->name())) {
1601
1602         COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1603
1604     } else if (prop->index == -1) {
1605
1606         if (prop->isDefault) {
1607             COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1608         } else {
1609             COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1610         }
1611
1612     } else if (prop->value) {
1613
1614         COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1615
1616     } else if (enginePrivate->isList(prop->type)) {
1617
1618         COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1619
1620     } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) {
1621
1622         COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1623
1624     } else {
1625
1626         COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1627
1628     }
1629
1630     return true;
1631 }
1632
1633 bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
1634                                                     QDeclarativeParser::Property *nsProp, 
1635                                                     QDeclarativeParser::Object *obj, 
1636                                                     const BindingContext &ctxt)
1637 {
1638     if (!nsProp->value)
1639         COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1640
1641     for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1642
1643         if (!isAttachedPropertyName(prop->name()))
1644             COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1645
1646         // Setup attached property data
1647
1648         QDeclarativeType *type = 0;
1649         unit->imports().resolveType(ns, prop->name().toUtf8(), &type, 0, 0, 0);
1650
1651         if (!type || !type->attachedPropertiesType()) 
1652             COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1653
1654         if (!prop->value)
1655             COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1656
1657         Q_ASSERT(type->attachedPropertiesFunction());
1658         prop->index = type->index();
1659         prop->value->metatype = type->attachedPropertiesType();
1660
1661         COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1662     }
1663
1664     return true;
1665 }
1666
1667 void QDeclarativeCompiler::genValueProperty(QDeclarativeParser::Property *prop,
1668                                    QDeclarativeParser::Object *obj)
1669 {
1670     if (enginePrivate->isList(prop->type)) {
1671         genListProperty(prop, obj);
1672     } else {
1673         genPropertyAssignment(prop, obj);
1674     }
1675 }
1676
1677 void QDeclarativeCompiler::genListProperty(QDeclarativeParser::Property *prop,
1678                                   QDeclarativeParser::Object *obj)
1679 {
1680     int listType = enginePrivate->listType(prop->type);
1681
1682     QDeclarativeInstruction fetch;
1683     fetch.setType(QDeclarativeInstruction::FetchQList);
1684     fetch.fetchQmlList.property = prop->index;
1685     bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1686     fetch.fetchQmlList.type = listType;
1687     output->addInstruction(fetch);
1688
1689     for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1690
1691         if (v->type == Value::CreatedObject) {
1692
1693             genObject(v->object);
1694             if (listTypeIsInterface) {
1695                 QDeclarativeInstruction assign;
1696                 assign.setType(QDeclarativeInstruction::AssignObjectList);
1697                 assign.assignObjectList.line = prop->location.start.line;
1698                 output->addInstruction(assign);
1699             } else {
1700                 QDeclarativeInstruction store;
1701                 store.setType(QDeclarativeInstruction::StoreObjectQList);
1702                 output->addInstruction(store);
1703             }
1704
1705         } else if (v->type == Value::PropertyBinding) {
1706
1707             genBindingAssignment(v, prop, obj);
1708
1709         }
1710
1711     }
1712
1713     QDeclarativeInstruction pop;
1714     pop.setType(QDeclarativeInstruction::PopQList);
1715     output->addInstruction(pop);
1716 }
1717
1718 void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *prop,
1719                                         QDeclarativeParser::Object *obj,
1720                                         QDeclarativeParser::Property *valueTypeProperty)
1721 {
1722     for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1723
1724         Q_ASSERT(v->type == Value::CreatedObject ||
1725                  v->type == Value::PropertyBinding ||
1726                  v->type == Value::Literal);
1727
1728         if (v->type == Value::CreatedObject) {
1729
1730             genObject(v->object);
1731
1732             if (QDeclarativeMetaType::isInterface(prop->type)) {
1733
1734                 QDeclarativeInstruction store;
1735                 store.setType(QDeclarativeInstruction::StoreInterface);
1736                 store.storeObject.line = v->object->location.start.line;
1737                 store.storeObject.propertyIndex = prop->index;
1738                 output->addInstruction(store);
1739
1740             } else if (prop->type == QMetaType::QVariant) {
1741
1742                 QDeclarativeInstruction store;
1743                 store.setType(QDeclarativeInstruction::StoreVariantObject);
1744                 store.storeObject.line = v->object->location.start.line;
1745                 store.storeObject.propertyIndex = prop->index;
1746                 output->addInstruction(store);
1747
1748             } else {
1749
1750                 QDeclarativeInstruction store;
1751                 store.setType(QDeclarativeInstruction::StoreObject);
1752                 store.storeObject.line = v->object->location.start.line;
1753                 store.storeObject.propertyIndex = prop->index;
1754                 output->addInstruction(store);
1755
1756             }
1757         } else if (v->type == Value::PropertyBinding) {
1758
1759             genBindingAssignment(v, prop, obj, valueTypeProperty);
1760
1761         } else if (v->type == Value::Literal) {
1762
1763             genLiteralAssignment(prop, v);
1764
1765         }
1766
1767     }
1768
1769     for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
1770
1771         Q_ASSERT(v->type == Value::ValueSource ||
1772                  v->type == Value::ValueInterceptor);
1773
1774         if (v->type == Value::ValueSource) {
1775             genObject(v->object);
1776
1777             QDeclarativeInstruction store;
1778             store.setType(QDeclarativeInstruction::StoreValueSource);
1779             if (valueTypeProperty) {
1780                 store.assignValueSource.property = genValueTypeData(prop, valueTypeProperty);
1781                 store.assignValueSource.owner = 1;
1782             } else {
1783                 store.assignValueSource.property = genPropertyData(prop);
1784                 store.assignValueSource.owner = 0;
1785             }
1786             QDeclarativeType *valueType = toQmlType(v->object);
1787             store.assignValueSource.castValue = valueType->propertyValueSourceCast();
1788             output->addInstruction(store);
1789
1790         } else if (v->type == Value::ValueInterceptor) {
1791             genObject(v->object);
1792
1793             QDeclarativeInstruction store;
1794             store.setType(QDeclarativeInstruction::StoreValueInterceptor);
1795             if (valueTypeProperty) {
1796                 store.assignValueInterceptor.property = genValueTypeData(prop, valueTypeProperty);
1797                 store.assignValueInterceptor.owner = 1;
1798             } else {
1799                 store.assignValueInterceptor.property = genPropertyData(prop);
1800                 store.assignValueInterceptor.owner = 0;
1801             }
1802             QDeclarativeType *valueType = toQmlType(v->object);
1803             store.assignValueInterceptor.castValue = valueType->propertyValueInterceptorCast();
1804             output->addInstruction(store);
1805         }
1806
1807     }
1808 }
1809
1810 bool QDeclarativeCompiler::buildIdProperty(QDeclarativeParser::Property *prop,
1811                                   QDeclarativeParser::Object *obj)
1812 {
1813     if (prop->value ||
1814         prop->values.isMany() ||
1815         prop->values.first()->object)
1816         COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
1817
1818     QDeclarativeParser::Value *idValue = prop->values.first();
1819     QString val = idValue->primitive();
1820
1821     COMPILE_CHECK(checkValidId(idValue, val));
1822
1823     if (compileState->ids.value(val))
1824         COMPILE_EXCEPTION(prop, tr("id is not unique"));
1825
1826     prop->values.first()->type = Value::Id;
1827
1828     obj->id = val;
1829     addId(val, obj);
1830
1831     return true;
1832 }
1833
1834 void QDeclarativeCompiler::addId(const QString &id, QDeclarativeParser::Object *obj)
1835 {
1836     Q_ASSERT(!compileState->ids.value(id));
1837     Q_ASSERT(obj->id == id);
1838     obj->idIndex = compileState->ids.count();
1839     compileState->ids.append(obj);
1840 }
1841
1842 void QDeclarativeCompiler::addBindingReference(BindingReference *ref)
1843 {
1844     Q_ASSERT(ref->value && !ref->value->bindingReference);
1845     ref->value->bindingReference = ref;
1846     compileState->bindings.prepend(ref);
1847 }
1848
1849 void QDeclarativeCompiler::saveComponentState()
1850 {
1851     Q_ASSERT(compileState->root);
1852     Q_ASSERT(compileState->root->componentCompileState == 0);
1853
1854     compileState->root->componentCompileState = compileState;
1855
1856     if (componentStats) 
1857         componentStats->savedComponentStats.append(componentStats->componentStat);
1858 }
1859
1860 QDeclarativeCompilerTypes::ComponentCompileState *
1861 QDeclarativeCompiler::componentState(QDeclarativeParser::Object *obj)
1862 {
1863     Q_ASSERT(obj->componentCompileState);
1864     return obj->componentCompileState;
1865 }
1866
1867 // Build attached property object.  In this example,
1868 // Text {
1869 //    GridView.row: 10
1870 // }
1871 // GridView is an attached property object.
1872 bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeParser::Property *prop,
1873                                         QDeclarativeParser::Object *obj,
1874                                         const BindingContext &ctxt)
1875 {
1876     Q_ASSERT(prop->value);
1877     Q_ASSERT(prop->index != -1); // This is set in buildProperty()
1878
1879     obj->addAttachedProperty(prop);
1880
1881     COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1882
1883     return true;
1884 }
1885
1886
1887 // Build "grouped" properties. In this example:
1888 // Text {
1889 //     font.pointSize: 12
1890 //     font.family: "Helvetica"
1891 // }
1892 // font is a nested property.  pointSize and family are not.
1893 bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeParser::Property *prop,
1894                                                 QDeclarativeParser::Object *obj,
1895                                                 const BindingContext &ctxt)
1896 {
1897     Q_ASSERT(prop->type != 0);
1898     Q_ASSERT(prop->index != -1);
1899
1900     if (QDeclarativeValueTypeFactory::isValueType(prop->type)) {
1901         if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
1902
1903             if (!prop->values.isEmpty()) {
1904                 if (prop->values.first()->location < prop->value->location) {
1905                     COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
1906                 } else {
1907                     COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
1908                 }
1909             }
1910
1911             if (!obj->metaObject()->property(prop->index).isWritable()) {
1912                 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
1913             }
1914
1915
1916             if (prop->isAlias) {
1917                 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
1918                     vtProp->isAlias = true;
1919                 }
1920             }
1921
1922             COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
1923                                                  prop->value, obj, ctxt.incr()));
1924             obj->addValueTypeProperty(prop);
1925         } else {
1926             COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1927         }
1928
1929     } else {
1930         // Load the nested property's meta type
1931         prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
1932         if (!prop->value->metatype)
1933             COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1934
1935         if (!prop->values.isEmpty()) 
1936             COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
1937
1938         obj->addGroupedProperty(prop);
1939
1940         COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1941     }
1942
1943     return true;
1944 }
1945
1946 bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
1947                                                   QDeclarativeParser::Object *obj,
1948                                                   QDeclarativeParser::Object *baseObj,
1949                                                   const BindingContext &ctxt)
1950 {
1951     if (obj->defaultProperty)
1952         COMPILE_EXCEPTION(obj, tr("Invalid property use"));
1953     obj->metatype = type->metaObject();
1954
1955     for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1956
1957         QDeclarativePropertyCache::Data *d = property(obj, prop->name());
1958         if (d == 0) 
1959             COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1960
1961         prop->index = d->coreIndex;
1962         prop->type = d->propType;
1963         prop->core = *d;
1964         prop->isValueTypeSubProperty = true;
1965
1966         if (prop->value)
1967             COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
1968
1969         if (prop->values.isMany()) {
1970             COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
1971         } else if (!prop->values.isEmpty()) {
1972             QDeclarativeParser::Value *value = prop->values.first();
1973
1974             if (value->object) {
1975                 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
1976             } else if (value->value.isScript()) {
1977                 // ### Check for writability
1978
1979                 //optimization for <Type>.<EnumValue> enum assignments
1980                 bool isEnumAssignment = false;
1981
1982                 if (prop->core.isEnum()) 
1983                     COMPILE_CHECK(testQualifiedEnumAssignment(obj->metatype->property(prop->index), obj, 
1984                                                               value, &isEnumAssignment));
1985
1986                 if (isEnumAssignment) {
1987                     value->type = Value::Literal;
1988                 } else {
1989                     BindingReference *reference = pool->New<BindingReference>();
1990                     reference->expression = value->value;
1991                     reference->property = prop;
1992                     reference->value = value;
1993                     reference->bindingContext = ctxt;
1994                     reference->bindingContext.owner++;
1995                     addBindingReference(reference);
1996                     value->type = Value::PropertyBinding;
1997                 }
1998             } else  {
1999                 COMPILE_CHECK(testLiteralAssignment(prop, value));
2000                 value->type = Value::Literal;
2001             }
2002         }
2003
2004         for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2005             Q_ASSERT(v->object);
2006
2007             COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt)); 
2008         }
2009
2010         obj->addValueProperty(prop);
2011     }
2012
2013     return true;
2014 }
2015
2016 // Build assignments to QML lists.  QML lists are properties of type
2017 // QDeclarativeListProperty<T>.  List properties can accept a list of 
2018 // objects, or a single binding.
2019 bool QDeclarativeCompiler::buildListProperty(QDeclarativeParser::Property *prop,
2020                                              QDeclarativeParser::Object *obj,
2021                                              const BindingContext &ctxt)
2022 {
2023     Q_ASSERT(enginePrivate->isList(prop->type));
2024
2025     int t = prop->type;
2026
2027     obj->addValueProperty(prop);
2028
2029     int listType = enginePrivate->listType(t);
2030     bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
2031
2032     bool assignedBinding = false;
2033     for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2034         if (v->object) {
2035             v->type = Value::CreatedObject;
2036             COMPILE_CHECK(buildObject(v->object, ctxt));
2037
2038             // We check object coercian here.  We check interface assignment
2039             // at runtime.
2040             if (!listTypeIsInterface) {
2041                 if (!canCoerce(listType, v->object)) {
2042                     COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2043                 }
2044             }
2045
2046         } else if (v->value.isScript()) {
2047             if (assignedBinding)
2048                 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2049
2050             assignedBinding = true;
2051             COMPILE_CHECK(buildBinding(v, prop, ctxt));
2052             v->type = Value::PropertyBinding;
2053         } else {
2054             COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2055         }
2056     }
2057
2058     return true;
2059 }
2060
2061 // Compiles an assignment to a QDeclarativeScriptString property
2062 bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeParser::Property *prop,
2063                                             QDeclarativeParser::Object *obj,
2064                                             const BindingContext &ctxt)
2065 {
2066     if (prop->values.isMany())
2067         COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2068
2069     if (prop->values.first()->object)
2070         COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2071
2072     prop->scriptStringScope = ctxt.stack;
2073     obj->addScriptStringProperty(prop);
2074
2075     return true;
2076 }
2077
2078 // Compile regular property assignments of the form "property: <value>"
2079 bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeParser::Property *prop,
2080                                           QDeclarativeParser::Object *obj,
2081                                           const BindingContext &ctxt)
2082 {
2083     obj->addValueProperty(prop);
2084
2085     if (prop->values.isMany())
2086         COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2087
2088     for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2089         if (v->object) {
2090
2091             COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2092
2093         } else {
2094
2095             COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2096
2097         }
2098     }
2099
2100     for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2101         Q_ASSERT(v->object);
2102         COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2103     }
2104
2105     return true;
2106 }
2107
2108 // Compile assigning a single object instance to a regular property
2109 bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeParser::Property *prop,
2110                                                          QDeclarativeParser::Object *obj,
2111                                                          QDeclarativeParser::Value *v,
2112                                                          const BindingContext &ctxt)
2113 {
2114     Q_ASSERT(prop->index != -1);
2115     Q_ASSERT(v->object->type != -1);
2116
2117     if (!obj->metaObject()->property(prop->index).isWritable())
2118         COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2119
2120     if (QDeclarativeMetaType::isInterface(prop->type)) {
2121
2122         // Assigning an object to an interface ptr property
2123         COMPILE_CHECK(buildObject(v->object, ctxt));
2124
2125         v->type = Value::CreatedObject;
2126
2127     } else if (prop->type == QMetaType::QVariant) {
2128
2129         // Assigning an object to a QVariant
2130         COMPILE_CHECK(buildObject(v->object, ctxt));
2131
2132         v->type = Value::CreatedObject;
2133     } else {
2134         // Normally buildObject() will set this up, but we need the static
2135         // meta object earlier to test for assignability.  It doesn't matter
2136         // that there may still be outstanding synthesized meta object changes
2137         // on this type, as they are not relevant for assignability testing
2138         v->object->metatype = output->types.at(v->object->type).metaObject();
2139         Q_ASSERT(v->object->metaObject());
2140
2141         // We want to raw metaObject here as the raw metaobject is the
2142         // actual property type before we applied any extensions that might
2143         // effect the properties on the type, but don't effect assignability
2144         const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2145
2146         // Will be true if the assgned type inherits propertyMetaObject
2147         bool isAssignable = false;
2148         // Determine isAssignable value
2149         if (propertyMetaObject) {
2150             const QMetaObject *c = v->object->metatype;
2151             while(c) {
2152                 isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject));
2153                 c = c->superClass();
2154             }
2155         }
2156
2157         if (isAssignable) {
2158             // Simple assignment
2159             COMPILE_CHECK(buildObject(v->object, ctxt));
2160
2161             v->type = Value::CreatedObject;
2162         } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) {
2163             // Automatic "Component" insertion
2164             QDeclarativeParser::Object *root = v->object;
2165             QDeclarativeParser::Object *component = pool->New<Object>();
2166             component->type = componentTypeRef();
2167             component->typeName = "Qt/Component";
2168             component->metatype = &QDeclarativeComponent::staticMetaObject;
2169             component->location = root->location;
2170             QDeclarativeParser::Value *componentValue = pool->New<Value>();
2171             componentValue->object = root;
2172             component->getDefaultProperty()->addValue(componentValue);
2173             v->object = component;
2174             COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2175         } else {
2176             COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2177         }
2178     }
2179
2180     return true;
2181 }
2182
2183 // Compile assigning a single object instance to a regular property using the "on" syntax.
2184 //
2185 // For example:
2186 //     Item {
2187 //         NumberAnimation on x { }
2188 //     }
2189 bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeParser::Property *prop,
2190                                                      QDeclarativeParser::Object *obj,
2191                                                      QDeclarativeParser::Object *baseObj,
2192                                                      QDeclarativeParser::Value *v,
2193                                                      const BindingContext &ctxt)
2194 {
2195     Q_ASSERT(prop->index != -1);
2196     Q_ASSERT(v->object->type != -1);
2197
2198     if (!obj->metaObject()->property(prop->index).isWritable())
2199         COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2200
2201
2202     // Normally buildObject() will set this up, but we need the static
2203     // meta object earlier to test for assignability.  It doesn't matter
2204     // that there may still be outstanding synthesized meta object changes
2205     // on this type, as they are not relevant for assignability testing
2206     v->object->metatype = output->types.at(v->object->type).metaObject();
2207     Q_ASSERT(v->object->metaObject());
2208
2209     // Will be true if the assigned type inherits QDeclarativePropertyValueSource
2210     bool isPropertyValue = false;
2211     // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor
2212     bool isPropertyInterceptor = false;
2213     if (QDeclarativeType *valueType = toQmlType(v->object)) {
2214         isPropertyValue = valueType->propertyValueSourceCast() != -1;
2215         isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2216     }
2217
2218     if (isPropertyValue || isPropertyInterceptor) {
2219         // Assign as a property value source
2220         COMPILE_CHECK(buildObject(v->object, ctxt));
2221
2222         if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2223             buildDynamicMeta(baseObj, ForceCreation);
2224         v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2225     } else {
2226         COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(QString::fromUtf8(v->object->typeName)).arg(prop->name().toString()));
2227     }
2228
2229     return true;
2230 }
2231
2232 // Compile assigning a literal or binding to a regular property
2233 bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeParser::Property *prop,
2234                                                           QDeclarativeParser::Object *obj,
2235                                                           QDeclarativeParser::Value *v,
2236                                                           const BindingContext &ctxt)
2237 {
2238     Q_ASSERT(prop->index != -1);
2239
2240     if (v->value.isScript()) {
2241
2242         //optimization for <Type>.<EnumValue> enum assignments
2243         if (prop->core.isEnum()) {
2244             bool isEnumAssignment = false;
2245             COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj, 
2246                                                       v, &isEnumAssignment));
2247             if (isEnumAssignment) {
2248                 v->type = Value::Literal;
2249                 return true;
2250             }
2251         }
2252
2253         COMPILE_CHECK(buildBinding(v, prop, ctxt));
2254
2255         v->type = Value::PropertyBinding;
2256
2257     } else {
2258
2259         COMPILE_CHECK(testLiteralAssignment(prop, v));
2260
2261         v->type = Value::Literal;
2262     }
2263
2264     return true;
2265 }
2266
2267 bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop,
2268                                                        QDeclarativeParser::Object *obj,
2269                                                        QDeclarativeParser::Value *v,
2270                                                        bool *isAssignment)
2271 {
2272     *isAssignment = false;
2273     if (!prop.isEnumType())
2274         return true;
2275
2276     if (!prop.isWritable())
2277         COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
2278
2279     QString string = v->value.asString();
2280     if (!QDeclarativeUtils::isUpper(string.at(0)))
2281         return true;
2282
2283     QStringList parts = string.split(QLatin1Char('.'));
2284     if (parts.count() != 2)
2285         return true;
2286
2287     QString typeName = parts.at(0);
2288     QDeclarativeType *type = 0;
2289     unit->imports().resolveType(typeName.toUtf8(), &type, 0, 0, 0, 0);
2290
2291     //handle enums on value types (where obj->typeName is empty)
2292     QByteArray objTypeName = obj->typeName;
2293     if (objTypeName.isEmpty()) {
2294         QDeclarativeType *objType = toQmlType(obj);
2295         if (objType)
2296             objTypeName = objType->qmlTypeName();
2297     }
2298
2299     if (!type)
2300         return true;
2301
2302     QString enumValue = parts.at(1);
2303     int value = -1;
2304
2305     if (objTypeName == type->qmlTypeName()) {
2306         // When these two match, we can short cut the search
2307         if (prop.isFlagType()) {
2308             value = prop.enumerator().keysToValue(enumValue.toUtf8().constData());
2309         } else {
2310             value = prop.enumerator().keyToValue(enumValue.toUtf8().constData());
2311         }
2312     } else {
2313         // Otherwise we have to search the whole type
2314         // This matches the logic in QV8TypeWrapper
2315         QByteArray enumName = enumValue.toUtf8();
2316         const QMetaObject *metaObject = type->baseMetaObject();
2317         for (int ii = metaObject->enumeratorCount() - 1; value == -1 && ii >= 0; --ii) {
2318             QMetaEnum e = metaObject->enumerator(ii);
2319             value = e.keyToValue(enumName.constData());
2320         }
2321     }
2322
2323     if (value == -1)
2324         return true;
2325
2326     v->type = Value::Literal;
2327     v->value = QDeclarativeParser::Variant((double)value);
2328     *isAssignment = true;
2329
2330     return true;
2331 }
2332
2333 struct StaticQtMetaObject : public QObject
2334 {
2335     static const QMetaObject *get()
2336         { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2337 };
2338
2339 // Similar logic to above, but not knowing target property.
2340 int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const
2341 {
2342     int dot = script.indexOf('.');
2343     if (dot > 0) {
2344         const QByteArray &scope = script.left(dot);
2345         QDeclarativeType *type = 0;
2346         unit->imports().resolveType(scope, &type, 0, 0, 0, 0);
2347         if (!type && scope != "Qt")
2348             return -1;
2349         const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2350         const char *key = script.constData() + dot+1;
2351         int i = mo->enumeratorCount();
2352         while (i--) {
2353             int v = mo->enumerator(i).keyToValue(key);
2354             if (v >= 0)
2355                 return v;
2356         }
2357     }
2358     return -1;
2359 }
2360
2361 const QMetaObject *QDeclarativeCompiler::resolveType(const QByteArray& name) const
2362 {
2363     QDeclarativeType *qmltype = 0;
2364     if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0)) 
2365         return 0;
2366     if (!qmltype)
2367         return 0;
2368     return qmltype->metaObject();
2369 }
2370
2371 // similar to logic of completeComponentBuild, but also sticks data
2372 // into primitives at the end
2373 int QDeclarativeCompiler::rewriteBinding(const QString& expression, const QString& name)
2374 {
2375     QDeclarativeRewrite::RewriteBinding rewriteBinding;
2376     rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf('.') + 1));
2377
2378     QString rewrite = rewriteBinding(expression, 0, 0);
2379
2380     return output->indexForString(rewrite);
2381 }
2382
2383 // Ensures that the dynamic meta specification on obj is valid
2384 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj)
2385 {
2386     // XXX aakenned - inefficient copying of the string ref
2387     QStringHash<bool> propNames;
2388     QSet<QByteArray> methodNames;
2389     bool seenDefaultProperty = false;
2390
2391     // Check properties
2392     for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2393         const QDeclarativeParser::Object::DynamicProperty &prop =
2394             obj->dynamicProperties.at(ii);
2395
2396         if (prop.isDefaultProperty) {
2397             if (seenDefaultProperty)
2398                 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2399             seenDefaultProperty = true;
2400         }
2401
2402         if (propNames.contains(prop.name))
2403             COMPILE_EXCEPTION(&prop, tr("Duplicate property name"));
2404
2405         if (QDeclarativeUtils::isUpper(prop.name.at(0)))
2406             COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
2407
2408         if (enginePrivate->v8engine()->illegalNames().contains(prop.name))
2409             COMPILE_EXCEPTION(&prop, tr("Illegal property name"));
2410
2411         propNames.insert(prop.name.toString(), true);
2412     }
2413
2414     for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2415         const QDeclarativeScript::Object::DynamicSignal &currSig = *s;
2416
2417         if (methodNames.testAndSet(currSig.name.hash())) {
2418             for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2419                  s2 = obj->dynamicSignals.next(s2)) {
2420                 if (s2->name == currSig.name)
2421                     COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2422             }
2423         }
2424
2425         if (currSig.name.at(0).isUpper())
2426             COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2427         if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2428             COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2429     }
2430
2431     for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2432         const QDeclarativeScript::Object::DynamicSlot &currSlot = *s;
2433
2434         if (methodNames.testAndSet(currSlot.name.hash())) {
2435             for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2436                  s2 = obj->dynamicSignals.next(s2)) {
2437                 if (s2->name == currSlot.name)
2438                     COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2439             }
2440             for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2441                  s2 = obj->dynamicSlots.next(s2)) {
2442                 if (s2->name == currSlot.name)
2443                     COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2444             }
2445         }
2446
2447         if (currSlot.name.at(0).isUpper())
2448             COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2449         if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2450             COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2451     }
2452
2453     return true;
2454 }
2455
2456 bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeParser::Object *obj)
2457 {
2458     for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2459         const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2460
2461         if (!p.defaultValue || p.type == Object::DynamicProperty::Alias)
2462             continue;
2463
2464         Property *property = 0;
2465         if (p.isDefaultProperty) {
2466             property = obj->getDefaultProperty();
2467         } else {
2468             property = obj->getProperty(p.name);
2469             if (!property->values.isEmpty()) 
2470                 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2471         }
2472
2473         if (property->value)
2474             COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2475
2476         property->values.append(p.defaultValue->values);
2477     }
2478     return true;
2479 }
2480
2481 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2482
2483 bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, DynamicMetaMode mode)
2484 {
2485     Q_ASSERT(obj);
2486     Q_ASSERT(obj->metatype);
2487
2488     if (mode != ForceCreation &&
2489         obj->dynamicProperties.isEmpty() &&
2490         obj->dynamicSignals.isEmpty() &&
2491         obj->dynamicSlots.isEmpty())
2492         return true;
2493
2494     bool resolveAlias = (mode == ResolveAliases);
2495
2496     const Object::DynamicProperty *defaultProperty = 0;
2497     int aliasCount = 0;
2498
2499     for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2500         const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2501
2502         if (p.type == Object::DynamicProperty::Alias)
2503             aliasCount++;
2504
2505         if (p.isDefaultProperty && 
2506             (resolveAlias || p.type != Object::DynamicProperty::Alias))
2507             defaultProperty = &p;
2508
2509         if (!resolveAlias) {
2510             // No point doing this for both the alias and non alias cases
2511             QDeclarativePropertyCache::Data *d = property(obj, p.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.utf8length());
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                 // XXX don't double resolve this in the case of an alias run
2602
2603                 QByteArray customTypeName;
2604                 QDeclarativeType *qmltype = 0;
2605                 QString url;
2606                 if (!unit->imports().resolveType(p.customType.toUtf8(), &qmltype, &url, 0, 0, 0)) 
2607                     COMPILE_EXCEPTION(&p, tr("Invalid property type"));
2608
2609                 if (!qmltype) {
2610                     QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(QUrl(url));
2611                     Q_ASSERT(tdata);
2612                     Q_ASSERT(tdata->isComplete());
2613
2614                     QDeclarativeCompiledData *data = tdata->compiledData();
2615                     customTypeName = data->root->className();
2616                     data->release();
2617                     tdata->release();
2618                 } else {
2619                     customTypeName = qmltype->typeName();
2620                 }
2621
2622                 if (p.type == Object::DynamicProperty::Custom) {
2623                     customTypeName += '*';
2624                     propertyType = QMetaType::QObjectStar;
2625                 } else {
2626                     readonly = true;
2627                     customTypeName = QByteArray("QDeclarativeListProperty<") + customTypeName + QByteArray(">");
2628                     propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
2629                 }
2630
2631                 p.resolvedCustomTypeName = pool->NewByteArray(customTypeName);
2632                 p.typeRef = builder.newString(customTypeName.length());
2633                 typeRef = p.typeRef;
2634             }
2635
2636             if (buildData) {
2637                 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2638                 vmd->propertyCount++;
2639                 (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType;
2640             }
2641
2642             if (p.type < builtinTypeCount)
2643                 builder.setProperty(effectivePropertyIndex, p.nameRef, typeRef, (QMetaType::Type)propertyType, 
2644                                     readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable, 
2645                                     effectivePropertyIndex);
2646             else 
2647                 builder.setProperty(effectivePropertyIndex, p.nameRef, typeRef, 
2648                                     readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable, 
2649                                     effectivePropertyIndex);
2650
2651             p.changedSignatureRef = builder.newString(p.name.utf8length() + strlen("Changed()"));
2652             builder.setSignal(effectivePropertyIndex, p.changedSignatureRef);
2653
2654             effectivePropertyIndex++;
2655         }
2656         
2657         if (aliasCount) {
2658             int aliasIndex = 0;
2659             for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2660                 Object::DynamicProperty &p = obj->dynamicProperties[ii];
2661                 if (p.type == Object::DynamicProperty::Alias) {
2662                     if (resolveAlias) {
2663                         Q_ASSERT(buildData);
2664                         ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++;
2665                         COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex, aliasIndex, p));
2666                     }
2667                     // Even if we aren't resolving the alias, we need a fake signal so that the 
2668                     // metaobject remains consistent across the resolve and non-resolve alias runs
2669                     p.changedSignatureRef = builder.newString(p.name.utf8length() + strlen("Changed()"));
2670                     builder.setSignal(effectivePropertyIndex, p.changedSignatureRef);
2671                     effectivePropertyIndex++;
2672                     aliasIndex++;
2673                 }
2674             }
2675         }
2676     }
2677
2678     // Reserve default property
2679     QFastMetaBuilder::StringRef defPropRef;
2680     if (defaultProperty) {
2681         defPropRef = builder.newString(strlen("DefaultProperty"));
2682         builder.setClassInfo(0, defPropRef, defaultProperty->nameRef);
2683     }
2684
2685     // Reserve dynamic signals
2686     for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2687         Object::DynamicSignal &s = obj->dynamicSignals[ii];
2688
2689         int paramCount = s.parameterNames.count();
2690
2691         int signatureSize = s.name.length() + 2 /* paren */;
2692         int namesSize = 0;
2693         if (paramCount) signatureSize += s.parameterTypesLength() + (paramCount - 1) /* commas */;
2694         if (paramCount) namesSize += s.parameterNamesLength() + (paramCount - 1) /* commas */;
2695
2696         s.signatureRef = builder.newString(signatureSize);
2697         if (namesSize) s.parameterNamesRef = builder.newString(namesSize);
2698
2699         if (buildData)
2700             ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++;
2701         
2702         builder.setSignal(ii + obj->dynamicProperties.count(), s.signatureRef, s.parameterNamesRef);
2703     }
2704
2705     // Reserve dynamic slots
2706     if (obj->dynamicSlots.count()) {
2707
2708         // Allocate QVariant string
2709         if (typeRefs[0].isEmpty()) 
2710             typeRefs[0] = builder.newString(strlen(builtinTypes[0].cppType));
2711
2712         typedef QDeclarativeVMEMetaData VMD;
2713
2714         for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2715             Object::DynamicSlot &s = obj->dynamicSlots[ii];
2716             int paramCount = s.parameterNames.count();
2717
2718             int signatureSize = s.name.length() + 2 /* paren */;
2719             int namesSize = 0; 
2720             if (paramCount) signatureSize += (paramCount * strlen("QVariant") + (paramCount - 1));
2721             if (paramCount) namesSize += s.parameterNamesLength() + (paramCount - 1 /* commas */); 
2722
2723             s.signatureRef = builder.newString(signatureSize);
2724             if (namesSize) s.parameterNamesRef = builder.newString(namesSize);
2725
2726             builder.setMethod(ii, s.signatureRef, s.parameterNamesRef, typeRefs[0]);
2727
2728             if (buildData) {
2729                 QString funcScript;
2730                 funcScript.reserve(strlen("(function ") + s.name.length() + 1 /* lparen */ + 
2731                         namesSize + 1 /* rparen */ + s.body.length() + 1 /* rparen */);
2732                 funcScript = QLatin1String("(function ") + s.name + QLatin1Char('(');
2733                 for (int jj = 0; jj < paramCount; ++jj) {
2734                     if (jj) funcScript.append(QLatin1Char(','));
2735                     funcScript.append(QLatin1String(s.parameterNames.at(jj)));
2736                 }
2737                 funcScript += QLatin1Char(')') + s.body + QLatin1Char(')');
2738
2739                 VMD::MethodData methodData = { s.parameterNames.count(), 0, 
2740                                                funcScript.length(), 
2741                                                s.location.start.line };
2742
2743                 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2744                 vmd->methodCount++;
2745
2746                 VMD::MethodData &md = *(vmd->methodData() + ii);
2747                 md = methodData;
2748                 md.bodyOffset = dynamicData.size();
2749
2750                 dynamicData.append((const char *)funcScript.constData(),
2751                                    (funcScript.length() * sizeof(QChar)));
2752             }
2753
2754         }
2755     }
2756
2757     // Now allocate used builtin types
2758     for (int ii = 0; ii < builtinTypeCount; ++ii) {
2759         if (!typeRefs[ii].isEmpty())
2760             typeRefs[ii].load(builtinTypes[ii].cppType);
2761     }
2762
2763     // Now allocate properties
2764     for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2765         Object::DynamicProperty &p = obj->dynamicProperties[ii];
2766
2767         char *d = p.changedSignatureRef.data();
2768         p.name.writeUtf8(d);
2769         strcpy(d + p.name.utf8length(), "Changed()");
2770
2771         if (p.type == Object::DynamicProperty::Alias && !resolveAlias)
2772             continue;
2773
2774         p.nameRef.load(p.name);
2775
2776         if (p.type >= builtinTypeCount) {
2777             Q_ASSERT(p.resolvedCustomTypeName);
2778             p.typeRef.load(*p.resolvedCustomTypeName);
2779         }
2780     }
2781
2782     // Allocate default property if necessary
2783     if (defaultProperty) 
2784         strcpy(defPropRef.data(), "DefaultProperty");
2785
2786     // Now allocate signals
2787     for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2788         Object::DynamicSignal &s = obj->dynamicSignals[ii];
2789
2790         char *d = s.signatureRef.data();
2791         char *d2 = s.parameterNamesRef.isEmpty()?0:s.parameterNamesRef.data();
2792         strcpy(d, s.name.constData());
2793         d += s.name.length();
2794         *d++ = '('; 
2795
2796         for (int jj = 0; jj < s.parameterNames.count(); ++jj) {
2797             if (jj != 0) { *d++ = ','; *d2++ = ','; }
2798             strcpy(d, s.parameterTypes.at(jj).constData());
2799             d += s.parameterTypes.at(jj).length();
2800             strcpy(d2, s.parameterNames.at(jj).constData());
2801             d2 += s.parameterNames.at(jj).length();
2802         }
2803         *d++ = ')';
2804         *d = 0;
2805         if (d2) *d2 = 0;
2806     }
2807
2808     // Now allocate methods
2809     for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2810         Object::DynamicSlot &s = obj->dynamicSlots[ii];
2811         char *d = s.signatureRef.data();
2812         char *d2 = s.parameterNamesRef.isEmpty()?0:s.parameterNamesRef.data();
2813         strcpy(d, s.name.constData());
2814         d += s.name.length();
2815         *d++ = '('; 
2816         for (int jj = 0; jj < s.parameterNames.count(); ++jj) {
2817             if (jj != 0) { *d++ = ','; *d2++ = ','; }
2818             strcpy(d, "QVariant");
2819             d += strlen("QVariant");
2820             strcpy(d2, s.parameterNames.at(jj).constData());
2821             d2 += s.parameterNames.at(jj).length();
2822         }
2823         *d++ = ')';
2824         *d = 0;
2825         if (d2) *d2 = 0;
2826     }
2827
2828     // Now allocate class name
2829     classNameRef.load(newClassName);
2830
2831     obj->metadata = builder.toData();
2832     builder.fromData(&obj->extObject, obj->metatype, obj->metadata);
2833
2834     if (mode == IgnoreAliases && aliasCount) 
2835         compileState->aliasingObjects.append(obj);
2836
2837     obj->synthdata = dynamicData;
2838
2839     if (obj->synthCache) {
2840         obj->synthCache->release();
2841         obj->synthCache = 0;
2842     }
2843
2844     if (obj->type != -1) {
2845         QDeclarativePropertyCache *cache = output->types[obj->type].createPropertyCache(engine)->copy();
2846         cache->append(engine, &obj->extObject, QDeclarativePropertyCache::Data::NoFlags,
2847                       QDeclarativePropertyCache::Data::IsVMEFunction, 
2848                       QDeclarativePropertyCache::Data::IsVMESignal);
2849         obj->synthCache = cache;
2850     }
2851
2852     return true;
2853 }
2854
2855 bool QDeclarativeCompiler::checkValidId(QDeclarativeParser::Value *v, const QString &val)
2856 {
2857     if (val.isEmpty()) 
2858         COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
2859
2860     QChar ch = val.at(0);
2861     if (QDeclarativeUtils::isLetter(ch) && !QDeclarativeUtils::isLower(ch))
2862         COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
2863
2864     QChar u(QLatin1Char('_'));
2865     if (!QDeclarativeUtils::isLetter(ch) && ch != u)
2866         COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
2867
2868     for (int ii = 1; ii < val.count(); ++ii) {
2869         ch = val.at(ii);
2870         if (!QDeclarativeUtils::isLetterOrNumber(ch) && ch != u)
2871             COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
2872     }
2873
2874     if (enginePrivate->v8engine()->illegalNames().contains(val))
2875         COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
2876
2877     return true;
2878 }
2879
2880 #include <qdeclarativejsparser_p.h>
2881
2882 static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node)
2883 {
2884     if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) {
2885         QString name =
2886             static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name.toString();
2887         return QStringList() << name;
2888     } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) {
2889         QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node);
2890
2891         QStringList rv = astNodeToStringList(expr->base);
2892         if (rv.isEmpty())
2893             return rv;
2894         rv.append(expr->name.toString());
2895         return rv;
2896     }
2897     return QStringList();
2898 }
2899
2900 bool QDeclarativeCompiler::compileAlias(QFastMetaBuilder &builder,
2901                                         QByteArray &data,
2902                                         QDeclarativeParser::Object *obj,
2903                                         int propIndex, int aliasIndex,
2904                                         Object::DynamicProperty &prop)
2905 {
2906     if (!prop.defaultValue)
2907         COMPILE_EXCEPTION(obj, tr("No property alias location"));
2908
2909     if (!prop.defaultValue->values.isOne() ||
2910         prop.defaultValue->values.first()->object ||
2911         !prop.defaultValue->values.first()->value.isScript())
2912         COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2913
2914     QDeclarativeJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST();
2915     if (!node)
2916         COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
2917
2918     QStringList alias = astNodeToStringList(node);
2919
2920     if (alias.count() < 1 || alias.count() > 3)
2921         COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
2922
2923     QDeclarativeParser::Object *idObject = compileState->ids.value(alias.at(0));
2924     if (!idObject)
2925         COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
2926
2927     QByteArray typeName;
2928
2929     int propIdx = -1;
2930     int flags = 0;
2931     int type = 0;
2932     bool writable = false;
2933     bool resettable = false;
2934     if (alias.count() == 2 || alias.count() == 3) {
2935         propIdx = indexOfProperty(idObject, alias.at(1));
2936
2937         if (-1 == propIdx) {
2938             COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2939         } else if (propIdx > 0xFFFF) {
2940             COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
2941         }
2942
2943         QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
2944         if (!aliasProperty.isScriptable())
2945             COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2946
2947         writable = aliasProperty.isWritable();
2948         resettable = aliasProperty.isResettable();
2949
2950         if (aliasProperty.type() < QVariant::UserType)
2951             type = aliasProperty.type();
2952
2953         if (alias.count() == 3) {
2954             QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
2955             if (!valueType)
2956                 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2957
2958             propIdx |= ((unsigned int)aliasProperty.type()) << 24;
2959
2960             int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
2961             if (valueTypeIndex == -1)
2962                 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2963             Q_ASSERT(valueTypeIndex <= 0xFF);
2964             
2965             aliasProperty = valueType->metaObject()->property(valueTypeIndex);
2966             propIdx |= (valueTypeIndex << 16);
2967         }
2968
2969         if (aliasProperty.isEnumType()) 
2970             typeName = "int";  // Avoid introducing a dependency on the aliased metaobject
2971         else
2972             typeName = aliasProperty.typeName();
2973     } else {
2974         Q_ASSERT(idObject->type != -1); // How else did it get an id?
2975
2976         const QDeclarativeCompiledData::TypeReference &ref = output->types.at(idObject->type);
2977         if (ref.type)
2978             typeName = ref.type->typeName();
2979         else
2980             typeName = ref.component->root->className();
2981
2982         typeName += '*';
2983     }
2984
2985     if (typeName.endsWith('*'))
2986         flags |= QML_ALIAS_FLAG_PTR;
2987
2988     QDeclarativeVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags };
2989
2990     typedef QDeclarativeVMEMetaData VMD;
2991     VMD *vmd = (QDeclarativeVMEMetaData *)data.data();
2992     *(vmd->aliasData() + aliasIndex) = aliasData;
2993
2994     prop.nameRef = builder.newString(prop.name.length());
2995     prop.resolvedCustomTypeName = pool->NewByteArray(typeName);
2996     prop.typeRef = builder.newString(typeName.length());
2997
2998     builder.setProperty(propIndex, prop.nameRef, prop.typeRef, (QMetaType::Type)type, 
2999                         (QFastMetaBuilder::PropertyFlag)(writable?int(QFastMetaBuilder::Writable):0), 
3000                         propIndex);
3001
3002     return true;
3003 }
3004
3005 bool QDeclarativeCompiler::buildBinding(QDeclarativeParser::Value *value,
3006                                         QDeclarativeParser::Property *prop,
3007                                         const BindingContext &ctxt)
3008 {
3009     Q_ASSERT(prop->index != -1);
3010     Q_ASSERT(prop->parent);
3011     Q_ASSERT(prop->parent->metaObject());
3012
3013     // XXX aakenned
3014     QMetaProperty mp = prop->parent->metaObject()->property(prop->index);
3015     if (!mp.isWritable() && !QDeclarativeMetaType::isList(prop->type))
3016         COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3017
3018     BindingReference *reference = pool->New<BindingReference>();
3019     reference->expression = value->value;
3020     reference->property = prop;
3021     reference->value = value;
3022     reference->bindingContext = ctxt;
3023     addBindingReference(reference);
3024
3025     return true;
3026 }
3027
3028 void QDeclarativeCompiler::genBindingAssignment(QDeclarativeParser::Value *binding,
3029                                                 QDeclarativeParser::Property *prop,
3030                                                 QDeclarativeParser::Object *obj,
3031                                                 QDeclarativeParser::Property *valueTypeProperty)
3032 {
3033     Q_UNUSED(obj);
3034     Q_ASSERT(binding->bindingReference);
3035
3036     const BindingReference &ref = *binding->bindingReference;
3037     if (ref.dataType == BindingReference::V4) {
3038         QDeclarativeInstruction store;
3039         store.setType(QDeclarativeInstruction::StoreV4Binding);
3040         store.assignBinding.value = ref.compiledIndex;
3041         store.assignBinding.context = ref.bindingContext.stack;
3042         store.assignBinding.owner = ref.bindingContext.owner;
3043         if (valueTypeProperty) 
3044             store.assignBinding.property = (valueTypeProperty->index & 0xFFFF) |
3045                                            ((valueTypeProperty->type & 0xFF)) << 16 |
3046                                            ((prop->index & 0xFF) << 24);
3047         else 
3048             store.assignBinding.property = prop->index;
3049         store.assignBinding.line = binding->location.start.line;
3050         output->addInstruction(store);
3051     } else if (ref.dataType == BindingReference::V8) {
3052         QDeclarativeInstruction store;
3053         store.setType(QDeclarativeInstruction::StoreV8Binding);
3054         store.assignBinding.value = ref.compiledIndex;
3055         store.assignBinding.context = ref.bindingContext.stack;
3056         store.assignBinding.owner = ref.bindingContext.owner;
3057         store.assignBinding.line = binding->location.start.line;
3058
3059         Q_ASSERT(ref.bindingContext.owner == 0 ||
3060                  (ref.bindingContext.owner != 0 && valueTypeProperty));
3061         if (ref.bindingContext.owner) {
3062             store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
3063         } else {
3064             store.assignBinding.property = genPropertyData(prop);
3065         }
3066
3067         output->addInstruction(store);
3068     } else {
3069         QDeclarativeInstruction store;
3070         if (!prop->isAlias)
3071             store.setType(QDeclarativeInstruction::StoreBinding);
3072         else
3073             store.setType(QDeclarativeInstruction::StoreBindingOnAlias);
3074         store.assignBinding.value = output->indexForString(ref.rewrittenExpression);
3075         store.assignBinding.context = ref.bindingContext.stack;
3076         store.assignBinding.owner = ref.bindingContext.owner;
3077         store.assignBinding.line = binding->location.start.line;
3078
3079         Q_ASSERT(ref.bindingContext.owner == 0 ||
3080                  (ref.bindingContext.owner != 0 && valueTypeProperty));
3081         if (ref.bindingContext.owner) {
3082             store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
3083         } else {
3084             store.assignBinding.property = genPropertyData(prop);
3085         }
3086         output->addInstruction(store);
3087     }
3088 }
3089
3090 int QDeclarativeCompiler::genContextCache()
3091 {
3092     if (compileState->ids.count() == 0)
3093         return -1;
3094
3095     QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache();
3096     cache->reserve(compileState->ids.count());
3097     for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o)) 
3098         cache->add(o->id, o->idIndex);
3099
3100     output->contextCaches.append(cache);
3101     return output->contextCaches.count() - 1;
3102 }
3103
3104 int QDeclarativeCompiler::genValueTypeData(QDeclarativeParser::Property *valueTypeProp, 
3105                                   QDeclarativeParser::Property *prop)
3106 {
3107     typedef QDeclarativePropertyPrivate QDPP;
3108     QByteArray data = QDPP::saveValueType(prop->parent->metaObject(), prop->index, 
3109                                           enginePrivate->valueTypes[prop->type]->metaObject(), 
3110                                           valueTypeProp->index, engine);
3111
3112     return output->indexForByteArray(data);
3113 }
3114
3115 int QDeclarativeCompiler::genPropertyData(QDeclarativeParser::Property *prop)
3116 {
3117     typedef QDeclarativePropertyPrivate QDPP;
3118     QByteArray data = QDPP::saveProperty(prop->parent->metaObject(), prop->index, engine);
3119
3120     return output->indexForByteArray(data);
3121 }
3122
3123 bool QDeclarativeCompiler::completeComponentBuild()
3124 {
3125     if (componentStats)
3126         componentStats->componentStat.ids = compileState->ids.count();
3127
3128     for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject; 
3129          aliasObject = compileState->aliasingObjects.next(aliasObject)) 
3130         COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
3131
3132     QDeclarativeV4Compiler::Expression expr(unit->imports());
3133     expr.component = compileState->root;
3134     expr.ids = &compileState->ids;
3135     expr.importCache = output->importCache;
3136
3137     QDeclarativeV4Compiler bindingCompiler;
3138
3139     QList<BindingReference*> sharedBindings;
3140
3141     for (BindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3142
3143         BindingReference &binding = *b;
3144
3145         // ### We don't currently optimize for bindings on alias's - because 
3146         // of the solution to QTBUG-13719
3147         if (!binding.property->isAlias) {
3148             expr.context = binding.bindingContext.object;
3149             expr.property = binding.property;
3150             expr.expression = binding.expression;
3151
3152             int index = bindingCompiler.compile(expr, enginePrivate);
3153             if (index != -1) {
3154                 binding.dataType = BindingReference::V4;
3155                 binding.compiledIndex = index;
3156                 if (componentStats)
3157                     componentStats->componentStat.optimizedBindings.append(b->value->location);
3158                 continue;
3159             } 
3160         }
3161
3162         // Pre-rewrite the expression
3163         QString expression = binding.expression.asScript();
3164
3165         QDeclarativeRewrite::RewriteBinding rewriteBinding;
3166         rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3167         bool isSharable = false;
3168         binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3169
3170         if (isSharable && !binding.property->isAlias /* See above re alias */ &&
3171             binding.property->type != qMetaTypeId<QDeclarativeBinding*>()) {
3172             binding.dataType = BindingReference::V8;
3173             sharedBindings.append(b);
3174         } else {
3175             binding.dataType = BindingReference::QtScript;
3176         }
3177
3178         if (componentStats)
3179             componentStats->componentStat.scriptBindings.append(b->value->location);
3180     }
3181
3182     if (!sharedBindings.isEmpty()) {
3183         struct Sort {
3184             static bool lt(const BindingReference *lhs, const BindingReference *rhs)
3185             {
3186                 return lhs->value->location.start.line < rhs->value->location.start.line;
3187             }
3188         };
3189
3190         qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3191
3192         int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3193         int lineNumber = startLineNumber;
3194
3195         QString functionArray(QLatin1String("["));
3196         for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3197             BindingReference *reference = sharedBindings.at(ii);
3198             QDeclarativeParser::Value *value = reference->value;
3199             const QString &expression = reference->rewrittenExpression;
3200
3201             if (ii != 0) functionArray += QLatin1String(",");
3202
3203             while (lineNumber < value->location.start.line) {
3204                 lineNumber++;
3205                 functionArray += QLatin1String("\n");
3206             }
3207
3208             functionArray += expression;
3209             reference->compiledIndex = ii;
3210         }
3211         functionArray += QLatin1String("]");
3212
3213         compileState->v8BindingProgram = functionArray;
3214         compileState->v8BindingProgramLine = startLineNumber;
3215         compileState->v8BindingProgramIndex = output->v8bindings.count();
3216         output->v8bindings.append(v8::Persistent<v8::Array>());
3217     }
3218
3219     if (bindingCompiler.isValid()) 
3220         compileState->compiledBindingData = bindingCompiler.program();
3221
3222     saveComponentState();
3223
3224     return true;
3225 }
3226
3227 void QDeclarativeCompiler::dumpStats()
3228 {
3229     Q_ASSERT(componentStats);
3230     qWarning().nospace() << "QML Document: " << output->url.toString();
3231     for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3232         const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3233         qWarning().nospace() << "    Component Line " << stat.lineNumber;
3234         qWarning().nospace() << "        Total Objects:      " << stat.objects;
3235         qWarning().nospace() << "        IDs Used:           " << stat.ids;
3236         qWarning().nospace() << "        Optimized Bindings: " << stat.optimizedBindings.count();
3237
3238         {
3239         QByteArray output;
3240         for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3241             if (0 == (ii % 10)) {
3242                 if (ii) output.append("\n");
3243                 output.append("            ");
3244             }
3245
3246             output.append("(");
3247             output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3248             output.append(":");
3249             output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3250             output.append(") ");
3251         }
3252         if (!output.isEmpty())
3253             qWarning().nospace() << output.constData();
3254         }
3255
3256         qWarning().nospace() << "        QScript Bindings:   " << stat.scriptBindings.count();
3257         {
3258         QByteArray output;
3259         for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3260             if (0 == (ii % 10)) {
3261                 if (ii) output.append("\n");
3262                 output.append("            ");
3263             }
3264
3265             output.append("(");
3266             output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3267             output.append(":");
3268             output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3269             output.append(") ");
3270         }
3271         if (!output.isEmpty())
3272             qWarning().nospace() << output.constData();
3273         }
3274     }
3275 }
3276
3277 /*!
3278     Returns true if from can be assigned to a (QObject) property of type
3279     to.
3280 */
3281 bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeParser::Object *from)
3282 {
3283     const QMetaObject *toMo = 
3284         enginePrivate->rawMetaObjectForType(to);
3285     const QMetaObject *fromMo = from->metaObject();
3286
3287     while (fromMo) {
3288         if (QDeclarativePropertyPrivate::equal(fromMo, toMo))
3289             return true;
3290         fromMo = fromMo->superClass();
3291     }
3292     return false;
3293 }
3294
3295 /*!
3296     Returns the element name, as written in the QML file, for o.
3297 */
3298 QString QDeclarativeCompiler::elementName(QDeclarativeParser::Object *o)
3299 {
3300     Q_ASSERT(o);
3301     if (o->type != -1) {
3302         return output->types.at(o->type).className;
3303     } else {
3304         return QString();
3305     }
3306 }
3307
3308 QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeParser::Object *from)
3309 {
3310     // ### Optimize
3311     const QMetaObject *mo = from->metatype;
3312     QDeclarativeType *type = 0;
3313     while (!type && mo) {
3314         type = QDeclarativeMetaType::qmlType(mo);
3315         mo = mo->superClass();
3316     }
3317    return type;
3318 }
3319
3320 QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeParser::Object *obj)
3321 {
3322     const QMetaObject *mo = obj->metatype;
3323
3324     int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3325     if (idx == -1)
3326         return QStringList();
3327
3328     QMetaClassInfo classInfo = mo->classInfo(idx);
3329     QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3330     return rv;
3331 }
3332
3333 QDeclarativePropertyCache::Data *
3334 QDeclarativeCompiler::property(QDeclarativeParser::Object *object, int index)
3335 {
3336     QDeclarativePropertyCache *cache = 0;
3337
3338     if (object->synthCache)
3339         cache = object->synthCache;
3340     else if (object->type != -1)
3341         cache = output->types[object->type].createPropertyCache(engine);
3342     else
3343         cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3344
3345     return cache->property(index);
3346 }
3347
3348 QDeclarativePropertyCache::Data *
3349 QDeclarativeCompiler::property(QDeclarativeParser::Object *object, const QHashedStringRef &name, bool *notInRevision)
3350 {
3351     if (notInRevision) *notInRevision = false;
3352
3353     QDeclarativePropertyCache *cache = 0;
3354
3355     if (object->synthCache)
3356         cache = object->synthCache;
3357     else if (object->type != -1)
3358         cache = output->types[object->type].createPropertyCache(engine);
3359     else
3360         cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3361
3362     QDeclarativePropertyCache::Data *d = cache->property(name);
3363
3364     // Find the first property
3365     while (d && d->isFunction())
3366         d = cache->overrideData(d);
3367
3368     if (d && !cache->isAllowedInRevision(d)) {
3369         if (notInRevision) *notInRevision = true;
3370         return 0;
3371     } else {
3372         return d;
3373     }
3374 }
3375
3376 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3377 QDeclarativePropertyCache::Data *
3378 QDeclarativeCompiler::signal(QDeclarativeParser::Object *object, const QHashedStringRef &name, bool *notInRevision)
3379 {
3380     if (notInRevision) *notInRevision = false;
3381
3382     QDeclarativePropertyCache *cache = 0;
3383
3384     if (object->synthCache)
3385         cache = object->synthCache;
3386     else if (object->type != -1)
3387         cache = output->types[object->type].createPropertyCache(engine);
3388     else
3389         cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3390
3391
3392     QDeclarativePropertyCache::Data *d = cache->property(name);
3393     if (notInRevision) *notInRevision = false;
3394
3395     while (d && !(d->isFunction()))
3396         d = cache->overrideData(d);
3397
3398     if (d && !cache->isAllowedInRevision(d)) {
3399         if (notInRevision) *notInRevision = true;
3400         return 0;
3401     } else if (d) {
3402         return d;
3403     }
3404
3405     if (name.endsWith(Changed_string)) {
3406         QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3407
3408         d = property(object, propName, notInRevision);
3409         if (d) 
3410             return cache->method(d->notifyIndex);
3411     }
3412
3413     return 0;
3414 }
3415
3416 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3417 int QDeclarativeCompiler::indexOfSignal(QDeclarativeParser::Object *object, const QString &name, 
3418                                         bool *notInRevision)
3419 {
3420     QDeclarativePropertyCache::Data *d = signal(object, QStringRef(&name), notInRevision);
3421     return d?d->coreIndex:-1;
3422 }
3423
3424 int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QString &name, 
3425                                           bool *notInRevision)
3426 {
3427     return indexOfProperty(object, QStringRef(&name), notInRevision);
3428 }
3429
3430 int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QHashedStringRef &name, 
3431                                           bool *notInRevision)
3432 {
3433     QDeclarativePropertyCache::Data *d = property(object, name, notInRevision);
3434     return d?d->coreIndex:-1;
3435 }
3436
3437 QT_END_NAMESPACE