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