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