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