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