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