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