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