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