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