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