Merge branch 'qtquick2' of scm.dev.nokia.troll.no:qt/qtdeclarative-staging into v8
[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.programIndex = compileState.v8BindingProgramIndex;
716         bindings.initV8Bindings.line = compileState.v8BindingProgramLine;
717         output->addInstruction(bindings);
718     }
719
720     genObject(tree);
721
722     QDeclarativeInstruction def;
723     def.setType(QDeclarativeInstruction::SetDefault);
724     output->addInstruction(def);
725
726     QDeclarativeInstruction done;
727     done.setType(QDeclarativeInstruction::Done);
728     output->addInstruction(done);
729
730     Q_ASSERT(tree->metatype);
731
732     if (tree->metadata.isEmpty()) {
733         output->root = tree->metatype;
734     } else {
735         static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
736         output->root = &output->rootData;
737     }
738     if (!tree->metadata.isEmpty()) 
739         enginePrivate->registerCompositeType(output);
740 }
741
742 static bool ValuePtrLessThan(const QDeclarativeParser::Value *t1, const QDeclarativeParser::Value *t2)
743 {
744     return t1->location.start.line < t2->location.start.line ||
745            (t1->location.start.line == t2->location.start.line &&
746             t1->location.start.column < t2->location.start.column);
747 }
748
749 bool QDeclarativeCompiler::buildObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
750 {
751     componentStat.objects++;
752
753     Q_ASSERT (obj->type != -1);
754     const QDeclarativeCompiledData::TypeReference &tr =
755         output->types.at(obj->type);
756     obj->metatype = tr.metaObject();
757
758     if (tr.component)
759         obj->url = tr.component->url;
760     if (tr.type)
761         obj->typeName = tr.type->qmlTypeName();
762     obj->className = tr.className;
763
764     // This object is a "Component" element
765     if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
766         COMPILE_CHECK(buildComponent(obj, ctxt));
767         return true;
768     } 
769
770     // Object instantiations reset the binding context
771     BindingContext objCtxt(obj);
772
773     // Create the synthesized meta object, ignoring aliases
774     COMPILE_CHECK(checkDynamicMeta(obj)); 
775     COMPILE_CHECK(mergeDynamicMetaProperties(obj));
776     COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
777
778     // Find the native type and check for the QDeclarativeParserStatus interface
779     QDeclarativeType *type = toQmlType(obj);
780     Q_ASSERT(type);
781     obj->parserStatusCast = type->parserStatusCast();
782     if (obj->parserStatusCast != -1)
783         compileState.parserStatusCount++;
784
785     // Check if this is a custom parser type.  Custom parser types allow
786     // assignments to non-existent properties.  These assignments are then
787     // compiled by the type.
788     bool isCustomParser = output->types.at(obj->type).type &&
789                           output->types.at(obj->type).type->customParser() != 0;
790     QList<QDeclarativeCustomParserProperty> customProps;
791
792     // Fetch the list of deferred properties
793     QStringList deferredList = deferredProperties(obj);
794
795     // Must do id property first.  This is to ensure that the id given to any
796     // id reference created matches the order in which the objects are
797     // instantiated
798     foreach(Property *prop, obj->properties) {
799         if (prop->name == "id") {
800             COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
801             break;
802         }
803     }
804
805     // Merge 
806     Property *defaultProperty = 0;
807     Property *skipProperty = 0;
808     if (obj->defaultProperty) {
809         const QMetaObject *metaObject = obj->metaObject();
810         Q_ASSERT(metaObject);
811         QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
812         if (p.name()) {
813             Property *explicitProperty = obj->getProperty(p.name(), false);
814             if (explicitProperty && !explicitProperty->value) {
815                 skipProperty = explicitProperty;
816
817                 defaultProperty = new Property;
818                 defaultProperty->parent = obj;
819                 defaultProperty->isDefault = true;
820                 defaultProperty->location = obj->defaultProperty->location;
821                 defaultProperty->listValueRange = obj->defaultProperty->listValueRange;
822                 defaultProperty->listCommaPositions = obj->defaultProperty->listCommaPositions;
823
824                 defaultProperty->values  = obj->defaultProperty->values;
825                 defaultProperty->values += explicitProperty->values;
826                 foreach(QDeclarativeParser::Value *value, defaultProperty->values)
827                     value->addref();
828                 qSort(defaultProperty->values.begin(), defaultProperty->values.end(), ValuePtrLessThan);
829
830             } else {
831                 defaultProperty = obj->defaultProperty;
832                 defaultProperty->addref();
833             }
834         } else {
835             defaultProperty = obj->defaultProperty;
836             defaultProperty->addref();
837         }
838     }
839
840     QDeclarativeCustomParser *cp = 0;
841     if (isCustomParser)
842         cp = output->types.at(obj->type).type->customParser();
843
844     // Build all explicit properties specified
845     foreach(Property *prop, obj->properties) {
846
847         if (prop == skipProperty)
848             continue;
849         if (prop->name == "id")
850             continue;
851
852         bool canDefer = false;
853         if (isCustomParser) {
854             if (doesPropertyExist(prop, obj) && 
855                 (!(cp->flags() & QDeclarativeCustomParser::AcceptsAttachedProperties) ||
856                  !isAttachedPropertyName(prop->name))) {
857                 int ids = compileState.ids.count();
858                 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
859                 canDefer = ids == compileState.ids.count();
860             } else {
861                 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
862             }
863         } else {
864             if (isSignalPropertyName(prop->name)) {
865                 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
866             } else {
867                 int ids = compileState.ids.count();
868                 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
869                 canDefer = ids == compileState.ids.count();
870             }
871         }
872
873         if (canDefer && !deferredList.isEmpty() &&
874             deferredList.contains(QString::fromUtf8(prop->name)))
875             prop->isDeferred = true;
876
877     }
878
879     // Build the default property
880     if (defaultProperty)  {
881         Property *prop = defaultProperty;
882
883         bool canDefer = false;
884         if (isCustomParser) {
885             if (doesPropertyExist(prop, obj)) {
886                 int ids = compileState.ids.count();
887                 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
888                 canDefer = ids == compileState.ids.count();
889             } else {
890                 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
891             }
892         } else {
893             int ids = compileState.ids.count();
894             COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
895             canDefer = ids == compileState.ids.count();
896         }
897
898         if (canDefer && !deferredList.isEmpty() &&
899             deferredList.contains(QString::fromUtf8(prop->name)))
900             prop->isDeferred = true;
901     }
902
903     if (defaultProperty) 
904         defaultProperty->release();
905
906     // Compile custom parser parts
907     if (isCustomParser && !customProps.isEmpty()) {
908         cp->clearErrors();
909         cp->compiler = this;
910         cp->object = obj;
911         obj->custom = cp->compile(customProps);
912         cp->compiler = 0;
913         cp->object = 0;
914         foreach (QDeclarativeError err, cp->errors()) {
915             err.setUrl(output->url);
916             exceptions << err;
917         }
918     }
919
920     return true;
921 }
922
923 void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj)
924 {
925     QDeclarativeCompiledData::TypeReference &tr = output->types[obj->type];
926     if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
927         genComponent(obj);
928         return;
929     }
930
931     // Create the object
932     if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
933         !output->types.at(obj->type).type->isExtendedType() && obj != compileState.root) {
934
935         QDeclarativeInstruction create;
936         create.setType(QDeclarativeInstruction::CreateSimpleObject);
937         create.createSimple.create = output->types.at(obj->type).type->createFunction();
938         create.createSimple.typeSize = output->types.at(obj->type).type->createSize();
939         create.createSimple.type = obj->type;
940         create.createSimple.line = obj->location.start.line;
941         create.createSimple.column = obj->location.start.column;
942         output->addInstruction(create);
943
944     } else {
945
946         QDeclarativeInstruction create;
947         create.setType(QDeclarativeInstruction::CreateObject);
948         create.create.line = obj->location.start.line;
949         create.create.column = obj->location.start.column;
950         create.create.data = -1;
951         if (!obj->custom.isEmpty())
952             create.create.data = output->indexForByteArray(obj->custom);
953         create.create.type = obj->type;
954         if (!output->types.at(create.create.type).type && 
955             !obj->bindingBitmask.isEmpty()) {
956             Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
957             create.create.bindingBits = 
958                 output->indexForByteArray(obj->bindingBitmask);
959         } else {
960             create.create.bindingBits = -1;
961         }
962         output->addInstruction(create);
963
964     }
965
966     // Setup the synthesized meta object if necessary
967     if (!obj->metadata.isEmpty()) {
968         QDeclarativeInstruction meta;
969         meta.setType(QDeclarativeInstruction::StoreMetaObject);
970         meta.storeMeta.data = output->indexForByteArray(obj->metadata);
971         meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata);
972         meta.storeMeta.propertyCache = output->propertyCaches.count();
973
974         QDeclarativePropertyCache *propertyCache = obj->synthCache;
975         Q_ASSERT(propertyCache);
976         propertyCache->addref();
977
978         // Add flag for alias properties
979         if (!obj->synthdata.isEmpty()) {
980             const QDeclarativeVMEMetaData *vmeMetaData = 
981                 reinterpret_cast<const QDeclarativeVMEMetaData *>(obj->synthdata.constData());
982             for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
983                 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
984                 propertyCache->property(index)->flags |= QDeclarativePropertyCache::Data::IsAlias;
985             }
986         }
987
988         if (obj == unitRoot) {
989             propertyCache->addref();
990             output->rootPropertyCache = propertyCache;
991         }
992
993         output->propertyCaches << propertyCache;
994         output->addInstruction(meta);
995     } else if (obj == unitRoot) {
996         output->rootPropertyCache = tr.createPropertyCache(engine);
997         output->rootPropertyCache->addref();
998     }
999
1000     // Set the object id
1001     if (!obj->id.isEmpty()) {
1002         QDeclarativeInstruction id;
1003         id.setType(QDeclarativeInstruction::SetId);
1004         id.setId.value = output->indexForString(obj->id);
1005         id.setId.index = obj->idIndex;
1006         output->addInstruction(id);
1007     }
1008
1009     // Begin the class
1010     if (tr.type && obj->parserStatusCast != -1) {
1011         QDeclarativeInstruction begin;
1012         begin.setType(QDeclarativeInstruction::BeginObject);
1013         begin.begin.castValue = obj->parserStatusCast;
1014         output->addInstruction(begin);
1015     }
1016
1017     genObjectBody(obj);
1018 }
1019
1020 void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj)
1021 {
1022     typedef QPair<Property *, int> PropPair;
1023     foreach(const PropPair &prop, obj->scriptStringProperties) {
1024         const QString &script = prop.first->values.at(0)->value.asScript();
1025         QDeclarativeInstruction ss;
1026         ss.setType(QDeclarativeInstruction::StoreScriptString);
1027         ss.storeScriptString.propertyIndex = prop.first->index;
1028         ss.storeScriptString.value = output->indexForString(script);
1029         ss.storeScriptString.scope = prop.second;
1030         ss.storeScriptString.bindingId = rewriteBinding(script, prop.first->name);
1031         ss.storeScriptString.line = prop.first->location.start.line;
1032         output->addInstruction(ss);
1033     }
1034
1035     bool seenDefer = false;
1036     foreach(Property *prop, obj->valueProperties) {
1037         if (prop->isDeferred) {
1038             seenDefer = true;
1039             continue;
1040         }
1041         if (!prop->isAlias)
1042             genValueProperty(prop, obj);
1043     }
1044     if (seenDefer) {
1045         QDeclarativeInstruction defer;
1046         defer.setType(QDeclarativeInstruction::Defer);
1047         defer.defer.deferCount = 0;
1048         int deferIdx = output->addInstruction(defer);
1049         int nextInstructionIndex = output->nextInstructionIndex();
1050
1051         QDeclarativeInstruction init;
1052         init.setType(QDeclarativeInstruction::Init);
1053         init.init.bindingsSize = compileState.bindings.count(); // XXX - bigger than necessary
1054         init.init.parserStatusSize = compileState.parserStatusCount; // XXX - bigger than necessary
1055         init.init.contextCache = -1;
1056         init.init.compiledBinding = -1;
1057         output->addInstruction(init);
1058
1059         foreach(Property *prop, obj->valueProperties) {
1060             if (!prop->isDeferred)
1061                 continue;
1062             genValueProperty(prop, obj);
1063         }
1064
1065         QDeclarativeInstruction done;
1066         done.setType(QDeclarativeInstruction::Done);
1067         output->addInstruction(done);
1068
1069         output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1070     }
1071
1072     foreach(Property *prop, obj->signalProperties) {
1073
1074         QDeclarativeParser::Value *v = prop->values.at(0);
1075
1076         if (v->type == Value::SignalObject) {
1077
1078             genObject(v->object);
1079
1080             QDeclarativeInstruction assign;
1081             assign.setType(QDeclarativeInstruction::AssignSignalObject);
1082             assign.assignSignalObject.line = v->location.start.line;
1083             assign.assignSignalObject.signal =
1084                 output->indexForByteArray(prop->name);
1085             output->addInstruction(assign);
1086
1087         } else if (v->type == Value::SignalExpression) {
1088
1089             BindingContext ctxt = compileState.signalExpressions.value(v);
1090
1091             QDeclarativeInstruction store;
1092             store.setType(QDeclarativeInstruction::StoreSignal);
1093             store.storeSignal.signalIndex = prop->index;
1094             store.storeSignal.value =
1095                 output->indexForString(v->value.asScript().trimmed());
1096             store.storeSignal.context = ctxt.stack;
1097             store.storeSignal.name = output->indexForByteArray(prop->name);
1098             store.storeSignal.line = v->location.start.line;
1099             output->addInstruction(store);
1100
1101         }
1102
1103     }
1104
1105     foreach(Property *prop, obj->attachedProperties) {
1106         QDeclarativeInstruction fetch;
1107         fetch.setType(QDeclarativeInstruction::FetchAttached);
1108         fetch.fetchAttached.id = prop->index;
1109         fetch.fetchAttached.line = prop->location.start.line;
1110         output->addInstruction(fetch);
1111
1112         genObjectBody(prop->value);
1113
1114         QDeclarativeInstruction pop;
1115         pop.setType(QDeclarativeInstruction::PopFetchedObject);
1116         output->addInstruction(pop);
1117     }
1118
1119     foreach(Property *prop, obj->groupedProperties) {
1120         QDeclarativeInstruction fetch;
1121         fetch.setType(QDeclarativeInstruction::FetchObject);
1122         fetch.fetch.property = prop->index;
1123         fetch.fetch.line = prop->location.start.line;
1124         output->addInstruction(fetch);
1125
1126         if (!prop->value->metadata.isEmpty()) {
1127             QDeclarativeInstruction meta;
1128             meta.setType(QDeclarativeInstruction::StoreMetaObject);
1129             meta.storeMeta.data = output->indexForByteArray(prop->value->metadata);
1130             meta.storeMeta.aliasData = output->indexForByteArray(prop->value->synthdata);
1131             meta.storeMeta.propertyCache = -1;
1132             output->addInstruction(meta);
1133         }
1134
1135         genObjectBody(prop->value);
1136
1137         QDeclarativeInstruction pop;
1138         pop.setType(QDeclarativeInstruction::PopFetchedObject);
1139         output->addInstruction(pop);
1140     }
1141
1142     foreach(Property *prop, obj->valueTypeProperties) {
1143         if (!prop->isAlias)
1144             genValueTypeProperty(obj, prop);
1145     }
1146
1147     foreach(Property *prop, obj->valueProperties) {
1148         if (prop->isDeferred) 
1149             continue;
1150         if (prop->isAlias)
1151             genValueProperty(prop, obj);
1152     }
1153
1154     foreach(Property *prop, obj->valueTypeProperties) {
1155         if (prop->isAlias)
1156             genValueTypeProperty(obj, prop);
1157     }
1158 }
1159
1160 void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeParser::Object *obj,QDeclarativeParser::Property *prop)
1161 {
1162     QDeclarativeInstruction fetch;
1163     fetch.setType(QDeclarativeInstruction::FetchValueType);
1164     fetch.fetchValue.property = prop->index;
1165     fetch.fetchValue.type = prop->type;
1166     fetch.fetchValue.bindingSkipList = 0;
1167
1168     if (obj->type == -1 || output->types.at(obj->type).component) {
1169         // We only have to do this if this is a composite type.  If it is a builtin
1170         // type it can't possibly already have bindings that need to be cleared.
1171         foreach(Property *vprop, prop->value->valueProperties) {
1172             if (!vprop->values.isEmpty()) {
1173                 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1174                 fetch.fetchValue.bindingSkipList |= (1 << vprop->index);
1175             }
1176         }
1177     }
1178
1179     output->addInstruction(fetch);
1180
1181     foreach(Property *vprop, prop->value->valueProperties) {
1182         genPropertyAssignment(vprop, prop->value, prop);
1183     }
1184
1185     QDeclarativeInstruction pop;
1186     pop.setType(QDeclarativeInstruction::PopValueType);
1187     pop.fetchValue.property = prop->index;
1188     pop.fetchValue.type = prop->type;
1189     pop.fetchValue.bindingSkipList = 0;
1190     output->addInstruction(pop);
1191 }
1192
1193 void QDeclarativeCompiler::genComponent(QDeclarativeParser::Object *obj)
1194 {
1195     QDeclarativeParser::Object *root = obj->defaultProperty->values.at(0)->object;
1196     Q_ASSERT(root);
1197
1198     QDeclarativeInstruction create;
1199     create.setType(QDeclarativeInstruction::CreateComponent);
1200     create.createComponent.line = root->location.start.line;
1201     create.createComponent.column = root->location.start.column;
1202     create.createComponent.endLine = root->location.end.line;
1203     int createInstruction = output->addInstruction(create);
1204     int nextInstructionIndex = output->nextInstructionIndex();
1205
1206     ComponentCompileState oldCompileState = compileState;
1207     compileState = componentState(root);
1208
1209     QDeclarativeInstruction init;
1210     init.setType(QDeclarativeInstruction::Init);
1211     init.init.bindingsSize = compileState.bindings.count();
1212     init.init.parserStatusSize = compileState.parserStatusCount;
1213     init.init.contextCache = genContextCache();
1214     if (compileState.compiledBindingData.isEmpty())
1215         init.init.compiledBinding = -1;
1216     else
1217         init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData);
1218     output->addInstruction(init);
1219
1220     if (!compileState.v8BindingProgram.isEmpty()) {
1221         QDeclarativeInstruction bindings;
1222         bindings.setType(QDeclarativeInstruction::InitV8Bindings);
1223         bindings.initV8Bindings.program = output->indexForString(compileState.v8BindingProgram);
1224         bindings.initV8Bindings.programIndex = compileState.v8BindingProgramIndex;
1225         bindings.initV8Bindings.line = compileState.v8BindingProgramLine;
1226         output->addInstruction(bindings);
1227     }
1228
1229     genObject(root);
1230
1231     QDeclarativeInstruction def;
1232     def.setType(QDeclarativeInstruction::SetDefault);
1233     output->addInstruction(def);
1234
1235     QDeclarativeInstruction done;
1236     done.setType(QDeclarativeInstruction::Done);
1237     output->addInstruction(done);
1238
1239     output->instruction(createInstruction)->createComponent.count = 
1240         output->nextInstructionIndex() - nextInstructionIndex;
1241
1242     compileState = oldCompileState;
1243
1244     if (!obj->id.isEmpty()) {
1245         QDeclarativeInstruction id;
1246         id.setType(QDeclarativeInstruction::SetId);
1247         id.setId.value = output->indexForString(obj->id);
1248         id.setId.index = obj->idIndex;
1249         output->addInstruction(id);
1250     }
1251
1252     if (obj == unitRoot) {
1253         output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1254         output->rootPropertyCache->addref();
1255     }
1256 }
1257
1258 bool QDeclarativeCompiler::buildComponent(QDeclarativeParser::Object *obj,
1259                                  const BindingContext &ctxt)
1260 {
1261     // The special "Component" element can only have the id property and a
1262     // default property, that actually defines the component's tree
1263
1264     // Find, check and set the "id" property (if any)
1265     Property *idProp = 0;
1266     if (obj->properties.count() > 1 ||
1267        (obj->properties.count() == 1 && obj->properties.begin().key() != "id"))
1268         COMPILE_EXCEPTION(*obj->properties.begin(), tr("Component elements may not contain properties other than id"));
1269        
1270     if (obj->properties.count())
1271         idProp = *obj->properties.begin();
1272
1273     if (idProp) {
1274        if (idProp->value || idProp->values.count() > 1 || idProp->values.at(0)->object) 
1275            COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1276        COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1277
1278         QString idVal = idProp->values.first()->primitive();
1279
1280         if (compileState.ids.contains(idVal))
1281             COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1282
1283         obj->id = idVal;
1284         addId(idVal, obj);
1285     }
1286
1287     // Check the Component tree is well formed
1288     if (obj->defaultProperty &&
1289        (obj->defaultProperty->value || obj->defaultProperty->values.count() > 1 ||
1290         (obj->defaultProperty->values.count() == 1 && !obj->defaultProperty->values.first()->object)))
1291         COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1292
1293     if (!obj->dynamicProperties.isEmpty())
1294         COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1295     if (!obj->dynamicSignals.isEmpty())
1296         COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1297     if (!obj->dynamicSlots.isEmpty())
1298         COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1299
1300     QDeclarativeParser::Object *root = 0;
1301     if (obj->defaultProperty && obj->defaultProperty->values.count())
1302         root = obj->defaultProperty->values.first()->object;
1303
1304     if (!root)
1305         COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1306
1307     // Build the component tree
1308     COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1309
1310     return true;
1311 }
1312
1313 bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeParser::Object *obj,
1314                                          const BindingContext &ctxt)
1315 {
1316     ComponentCompileState oldComponentCompileState = compileState;
1317     ComponentStat oldComponentStat = componentStat;
1318
1319     compileState = ComponentCompileState();
1320     compileState.root = obj;
1321     compileState.nested = true;
1322
1323     componentStat = ComponentStat();
1324     componentStat.lineNumber = obj->location.start.line;
1325
1326     if (obj)
1327         COMPILE_CHECK(buildObject(obj, ctxt));
1328
1329     COMPILE_CHECK(completeComponentBuild());
1330
1331     compileState = oldComponentCompileState;
1332     componentStat = oldComponentStat;
1333
1334     return true;
1335 }
1336
1337
1338 // Build a sub-object.  A sub-object is one that was not created directly by
1339 // QML - such as a grouped property object, or an attached object.  Sub-object's
1340 // can't have an id, involve a custom parser, have attached properties etc.
1341 bool QDeclarativeCompiler::buildSubObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt)
1342 {
1343     Q_ASSERT(obj->metatype);
1344     Q_ASSERT(!obj->defaultProperty);
1345     Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1346                                    // sub-context
1347
1348     foreach(Property *prop, obj->properties) {
1349         if (isSignalPropertyName(prop->name)) {
1350             COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1351         } else {
1352             COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1353         }
1354     }
1355
1356     return true;
1357 }
1358
1359 int QDeclarativeCompiler::componentTypeRef()
1360 {
1361     QDeclarativeType *t = QDeclarativeMetaType::qmlType("QtQuick/Component",1,0);
1362     for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1363         if (output->types.at(ii).type == t)
1364             return ii;
1365     }
1366     QDeclarativeCompiledData::TypeReference ref;
1367     ref.className = "Component";
1368     ref.type = t;
1369     output->types << ref;
1370     return output->types.count() - 1;
1371 }
1372
1373 bool QDeclarativeCompiler::buildSignal(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj,
1374                                        const BindingContext &ctxt)
1375 {
1376     Q_ASSERT(obj->metaObject());
1377
1378     QByteArray name = prop->name;
1379     Q_ASSERT(name.startsWith("on"));
1380     name = name.mid(2);
1381
1382     // Note that the property name could start with any alpha or '_' or '$' character,
1383     // so we need to do the lower-casing of the first alpha character.
1384     for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1385         if (name[firstAlphaIndex] >= 'A' && name[firstAlphaIndex] <= 'Z') {
1386             name[firstAlphaIndex] = name[firstAlphaIndex] - 'A' + 'a';
1387             break;
1388         }
1389     }
1390
1391     bool notInRevision = false;
1392     int sigIdx = indexOfSignal(obj, name, &notInRevision);
1393
1394     if (sigIdx == -1) {
1395
1396         if (notInRevision && -1 == indexOfProperty(obj, prop->name, 0)) {
1397             Q_ASSERT(obj->type != -1);
1398             const QList<QDeclarativeTypeData::TypeReference>  &resolvedTypes = unit->resolvedTypes();
1399             const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1400             if (type.type) {
1401                 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));
1402             } else {
1403                 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)));
1404             }
1405         }
1406
1407         // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1408         // property.
1409         COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1410
1411     }  else {
1412
1413         if (prop->value || prop->values.count() != 1)
1414             COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1415
1416         prop->index = sigIdx;
1417         obj->addSignalProperty(prop);
1418
1419         if (prop->values.at(0)->object) {
1420             COMPILE_CHECK(buildObject(prop->values.at(0)->object, ctxt));
1421             prop->values.at(0)->type = Value::SignalObject;
1422         } else {
1423             prop->values.at(0)->type = Value::SignalExpression;
1424
1425             if (!prop->values.at(0)->value.isScript())
1426                 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1427
1428             QString script = prop->values.at(0)->value.asScript().trimmed();
1429             if (script.isEmpty())
1430                 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1431
1432             compileState.signalExpressions.insert(prop->values.at(0), ctxt);
1433         }
1434     }
1435
1436     return true;
1437 }
1438
1439
1440 /*!
1441     Returns true if (value) property \a prop exists on obj, false otherwise.
1442 */
1443 bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeParser::Property *prop,
1444                                              QDeclarativeParser::Object *obj)
1445 {
1446     if(isAttachedPropertyName(prop->name) || prop->name == "id")
1447         return true;
1448
1449     const QMetaObject *mo = obj->metaObject();
1450     if (mo) {
1451         if (prop->isDefault) {
1452             QMetaProperty p = QDeclarativeMetaType::defaultProperty(mo);
1453             return p.name() != 0;
1454         } else {
1455             int idx = indexOfProperty(obj, prop->name);
1456             return idx != -1 && mo->property(idx).isScriptable();
1457         }
1458     }
1459
1460     return false;
1461 }
1462
1463 bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop,
1464                                 QDeclarativeParser::Object *obj,
1465                                 const BindingContext &ctxt)
1466 {
1467     if (prop->isEmpty())
1468         COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1469
1470     const QMetaObject *metaObject = obj->metaObject();
1471     Q_ASSERT(metaObject);
1472
1473     if (isAttachedPropertyName(prop->name)) {
1474         // Setup attached property data
1475
1476         if (ctxt.isSubContext()) {
1477             // Attached properties cannot be used on sub-objects.  Sub-objects
1478             // always exist in a binding sub-context, which is what we test
1479             // for here.
1480             COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1481         }
1482
1483         QDeclarativeType *type = 0;
1484         QDeclarativeImportedNamespace *typeNamespace = 0;
1485         unit->imports().resolveType(prop->name, &type, 0, 0, 0, &typeNamespace);
1486
1487         if (typeNamespace) {
1488             COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj, 
1489                                                    ctxt));
1490             return true;
1491         } else if (!type || !type->attachedPropertiesType())  {
1492             COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1493         }
1494
1495         if (!prop->value)
1496             COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1497
1498         Q_ASSERT(type->attachedPropertiesFunction());
1499         prop->index = type->attachedPropertiesId();
1500         prop->value->metatype = type->attachedPropertiesType();
1501     } else {
1502         // Setup regular property data
1503         QMetaProperty p;
1504
1505         if (prop->isDefault) {
1506             p = QDeclarativeMetaType::defaultProperty(metaObject);
1507
1508             if (p.name()) {
1509                 prop->index = p.propertyIndex();
1510                 prop->name = p.name();
1511             }
1512
1513         } else {
1514             bool notInRevision = false;
1515             prop->index = indexOfProperty(obj, prop->name, &notInRevision);
1516             if (prop->index == -1 && notInRevision) {
1517                 const QList<QDeclarativeTypeData::TypeReference>  &resolvedTypes = unit->resolvedTypes();
1518                 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1519                 if (type.type) {
1520                     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));
1521                 } else {
1522                     COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)));
1523                 }
1524             }
1525
1526             if (prop->index != -1) {
1527                 p = metaObject->property(prop->index);
1528                 Q_ASSERT(p.name());
1529
1530                 if (!p.isScriptable()) {
1531                     prop->index = -1;
1532                     p = QMetaProperty();
1533                 }
1534             }
1535         }
1536
1537         // We can't error here as the "id" property does not require a
1538         // successful index resolution
1539         if (p.name()) 
1540             prop->type = p.userType();
1541
1542         // Check if this is an alias
1543         if (prop->index != -1 && 
1544             prop->parent && 
1545             prop->parent->type != -1 && 
1546             output->types.at(prop->parent->type).component) {
1547
1548             QDeclarativePropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1549             if (cache && cache->property(prop->index) && 
1550                 cache->property(prop->index)->flags & QDeclarativePropertyCache::Data::IsAlias)
1551                 prop->isAlias = true;
1552         }
1553
1554         if (prop->index != -1 && !prop->values.isEmpty()) 
1555             prop->parent->setBindingBit(prop->index);
1556     }
1557
1558     if (!prop->isDefault && prop->name == "id" && !ctxt.isSubContext()) {
1559
1560         // The magic "id" behavior doesn't apply when "id" is resolved as a
1561         // default property or to sub-objects (which are always in binding
1562         // sub-contexts)
1563         COMPILE_CHECK(buildIdProperty(prop, obj));
1564         if (prop->type == QVariant::String &&
1565             prop->values.at(0)->value.isString())
1566             COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1567
1568     } else if (isAttachedPropertyName(prop->name)) {
1569
1570         COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1571
1572     } else if (prop->index == -1) {
1573
1574         if (prop->isDefault) {
1575             COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1576         } else {
1577             COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1578         }
1579
1580     } else if (prop->value) {
1581
1582         COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1583
1584     } else if (enginePrivate->isList(prop->type)) {
1585
1586         COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1587
1588     } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) {
1589
1590         COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1591
1592     } else {
1593
1594         COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1595
1596     }
1597
1598     return true;
1599 }
1600
1601 bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
1602                                                     QDeclarativeParser::Property *nsProp, 
1603                                                     QDeclarativeParser::Object *obj, 
1604                                                     const BindingContext &ctxt)
1605 {
1606     if (!nsProp->value)
1607         COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1608
1609     foreach (Property *prop, nsProp->value->properties) {
1610
1611         if (!isAttachedPropertyName(prop->name))
1612             COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1613
1614         // Setup attached property data
1615
1616         QDeclarativeType *type = 0;
1617         unit->imports().resolveType(ns, prop->name, &type, 0, 0, 0);
1618
1619         if (!type || !type->attachedPropertiesType()) 
1620             COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1621
1622         if (!prop->value)
1623             COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1624
1625         Q_ASSERT(type->attachedPropertiesFunction());
1626         prop->index = type->index();
1627         prop->value->metatype = type->attachedPropertiesType();
1628
1629         COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1630     }
1631
1632     return true;
1633 }
1634
1635 void QDeclarativeCompiler::genValueProperty(QDeclarativeParser::Property *prop,
1636                                    QDeclarativeParser::Object *obj)
1637 {
1638     if (enginePrivate->isList(prop->type)) {
1639         genListProperty(prop, obj);
1640     } else {
1641         genPropertyAssignment(prop, obj);
1642     }
1643 }
1644
1645 void QDeclarativeCompiler::genListProperty(QDeclarativeParser::Property *prop,
1646                                   QDeclarativeParser::Object *obj)
1647 {
1648     int listType = enginePrivate->listType(prop->type);
1649
1650     QDeclarativeInstruction fetch;
1651     fetch.setType(QDeclarativeInstruction::FetchQList);
1652     fetch.fetchQmlList.property = prop->index;
1653     bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1654     fetch.fetchQmlList.type = listType;
1655     output->addInstruction(fetch);
1656
1657     for (int ii = 0; ii < prop->values.count(); ++ii) {
1658         QDeclarativeParser::Value *v = prop->values.at(ii);
1659
1660         if (v->type == Value::CreatedObject) {
1661
1662             genObject(v->object);
1663             if (listTypeIsInterface) {
1664                 QDeclarativeInstruction assign;
1665                 assign.setType(QDeclarativeInstruction::AssignObjectList);
1666                 assign.assignObjectList.line = prop->location.start.line;
1667                 output->addInstruction(assign);
1668             } else {
1669                 QDeclarativeInstruction store;
1670                 store.setType(QDeclarativeInstruction::StoreObjectQList);
1671                 output->addInstruction(store);
1672             }
1673
1674         } else if (v->type == Value::PropertyBinding) {
1675
1676             genBindingAssignment(v, prop, obj);
1677
1678         }
1679
1680     }
1681
1682     QDeclarativeInstruction pop;
1683     pop.setType(QDeclarativeInstruction::PopQList);
1684     output->addInstruction(pop);
1685 }
1686
1687 void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *prop,
1688                                         QDeclarativeParser::Object *obj,
1689                                         QDeclarativeParser::Property *valueTypeProperty)
1690 {
1691     for (int ii = 0; ii < prop->values.count(); ++ii) {
1692         QDeclarativeParser::Value *v = prop->values.at(ii);
1693
1694         Q_ASSERT(v->type == Value::CreatedObject ||
1695                  v->type == Value::PropertyBinding ||
1696                  v->type == Value::Literal);
1697
1698         if (v->type == Value::CreatedObject) {
1699
1700             genObject(v->object);
1701
1702             if (QDeclarativeMetaType::isInterface(prop->type)) {
1703
1704                 QDeclarativeInstruction store;
1705                 store.setType(QDeclarativeInstruction::StoreInterface);
1706                 store.storeObject.line = v->object->location.start.line;
1707                 store.storeObject.propertyIndex = prop->index;
1708                 output->addInstruction(store);
1709
1710             } else if (prop->type == -1) {
1711
1712                 QDeclarativeInstruction store;
1713                 store.setType(QDeclarativeInstruction::StoreVariantObject);
1714                 store.storeObject.line = v->object->location.start.line;
1715                 store.storeObject.propertyIndex = prop->index;
1716                 output->addInstruction(store);
1717
1718             } else {
1719
1720                 QDeclarativeInstruction store;
1721                 store.setType(QDeclarativeInstruction::StoreObject);
1722                 store.storeObject.line = v->object->location.start.line;
1723                 store.storeObject.propertyIndex = prop->index;
1724                 output->addInstruction(store);
1725
1726             }
1727         } else if (v->type == Value::PropertyBinding) {
1728
1729             genBindingAssignment(v, prop, obj, valueTypeProperty);
1730
1731         } else if (v->type == Value::Literal) {
1732
1733             QMetaProperty mp = obj->metaObject()->property(prop->index);
1734             genLiteralAssignment(mp, v);
1735
1736         }
1737
1738     }
1739
1740     for (int ii = 0; ii < prop->onValues.count(); ++ii) {
1741
1742         QDeclarativeParser::Value *v = prop->onValues.at(ii);
1743
1744         Q_ASSERT(v->type == Value::ValueSource ||
1745                  v->type == Value::ValueInterceptor);
1746
1747         if (v->type == Value::ValueSource) {
1748             genObject(v->object);
1749
1750             QDeclarativeInstruction store;
1751             store.setType(QDeclarativeInstruction::StoreValueSource);
1752             if (valueTypeProperty) {
1753                 store.assignValueSource.property = genValueTypeData(prop, valueTypeProperty);
1754                 store.assignValueSource.owner = 1;
1755             } else {
1756                 store.assignValueSource.property = genPropertyData(prop);
1757                 store.assignValueSource.owner = 0;
1758             }
1759             QDeclarativeType *valueType = toQmlType(v->object);
1760             store.assignValueSource.castValue = valueType->propertyValueSourceCast();
1761             output->addInstruction(store);
1762
1763         } else if (v->type == Value::ValueInterceptor) {
1764             genObject(v->object);
1765
1766             QDeclarativeInstruction store;
1767             store.setType(QDeclarativeInstruction::StoreValueInterceptor);
1768             if (valueTypeProperty) {
1769                 store.assignValueInterceptor.property = genValueTypeData(prop, valueTypeProperty);
1770                 store.assignValueInterceptor.owner = 1;
1771             } else {
1772                 store.assignValueInterceptor.property = genPropertyData(prop);
1773                 store.assignValueInterceptor.owner = 0;
1774             }
1775             QDeclarativeType *valueType = toQmlType(v->object);
1776             store.assignValueInterceptor.castValue = valueType->propertyValueInterceptorCast();
1777             output->addInstruction(store);
1778         }
1779
1780     }
1781 }
1782
1783 bool QDeclarativeCompiler::buildIdProperty(QDeclarativeParser::Property *prop,
1784                                   QDeclarativeParser::Object *obj)
1785 {
1786     if (prop->value ||
1787         prop->values.count() > 1 ||
1788         prop->values.at(0)->object)
1789         COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
1790
1791     QDeclarativeParser::Value *idValue = prop->values.at(0);
1792     QString val = idValue->primitive();
1793
1794     COMPILE_CHECK(checkValidId(idValue, val));
1795
1796     if (compileState.ids.contains(val))
1797         COMPILE_EXCEPTION(prop, tr("id is not unique"));
1798
1799     prop->values.at(0)->type = Value::Id;
1800
1801     obj->id = val;
1802     addId(val, obj);
1803
1804     return true;
1805 }
1806
1807 void QDeclarativeCompiler::addId(const QString &id, QDeclarativeParser::Object *obj)
1808 {
1809     Q_ASSERT(!compileState.ids.contains(id));
1810     Q_ASSERT(obj->id == id);
1811     obj->idIndex = compileState.ids.count();
1812     compileState.ids.insert(id, obj);
1813     compileState.idIndexes.insert(obj->idIndex, obj);
1814 }
1815
1816 void QDeclarativeCompiler::addBindingReference(const BindingReference &ref)
1817 {
1818     Q_ASSERT(ref.value && !compileState.bindings.contains(ref.value));
1819     compileState.bindings.insert(ref.value, ref);
1820 }
1821
1822 void QDeclarativeCompiler::saveComponentState()
1823 {
1824     Q_ASSERT(compileState.root);
1825     Q_ASSERT(!savedCompileStates.contains(compileState.root));
1826
1827     savedCompileStates.insert(compileState.root, compileState);
1828     savedComponentStats.append(componentStat);
1829 }
1830
1831 QDeclarativeCompiler::ComponentCompileState
1832 QDeclarativeCompiler::componentState(QDeclarativeParser::Object *obj)
1833 {
1834     Q_ASSERT(savedCompileStates.contains(obj));
1835     return savedCompileStates.value(obj);
1836 }
1837
1838 // Build attached property object.  In this example,
1839 // Text {
1840 //    GridView.row: 10
1841 // }
1842 // GridView is an attached property object.
1843 bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeParser::Property *prop,
1844                                         QDeclarativeParser::Object *obj,
1845                                         const BindingContext &ctxt)
1846 {
1847     Q_ASSERT(prop->value);
1848     Q_ASSERT(prop->index != -1); // This is set in buildProperty()
1849
1850     obj->addAttachedProperty(prop);
1851
1852     COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1853
1854     return true;
1855 }
1856
1857
1858 // Build "grouped" properties. In this example:
1859 // Text {
1860 //     font.pointSize: 12
1861 //     font.family: "Helvetica"
1862 // }
1863 // font is a nested property.  pointSize and family are not.
1864 bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeParser::Property *prop,
1865                                                 QDeclarativeParser::Object *obj,
1866                                                 const BindingContext &ctxt)
1867 {
1868     Q_ASSERT(prop->type != 0);
1869     Q_ASSERT(prop->index != -1);
1870
1871     if (QDeclarativeValueTypeFactory::isValueType(prop->type)) {
1872         if (prop->type >= 0 /* QVariant == -1 */ && enginePrivate->valueTypes[prop->type]) {
1873
1874             if (prop->values.count()) {
1875                 if (prop->values.at(0)->location < prop->value->location) {
1876                     COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
1877                 } else {
1878                     COMPILE_EXCEPTION(prop->values.at(0), tr( "Property has already been assigned a value"));
1879                 }
1880             }
1881
1882             if (!obj->metaObject()->property(prop->index).isWritable()) {
1883                 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
1884             }
1885
1886
1887             if (prop->isAlias) {
1888                 foreach (Property *vtProp, prop->value->properties)
1889                     vtProp->isAlias = true;
1890             }
1891
1892             COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
1893                                                  prop->value, obj, ctxt.incr()));
1894             obj->addValueTypeProperty(prop);
1895         } else {
1896             COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1897         }
1898
1899     } else {
1900         // Load the nested property's meta type
1901         prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
1902         if (!prop->value->metatype)
1903             COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1904
1905         if (prop->values.count()) 
1906             COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign a value directly to a grouped property"));
1907
1908         obj->addGroupedProperty(prop);
1909
1910         COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1911     }
1912
1913     return true;
1914 }
1915
1916 bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
1917                                                   QDeclarativeParser::Object *obj,
1918                                                   QDeclarativeParser::Object *baseObj,
1919                                                   const BindingContext &ctxt)
1920 {
1921     if (obj->defaultProperty)
1922         COMPILE_EXCEPTION(obj, tr("Invalid property use"));
1923     obj->metatype = type->metaObject();
1924
1925     foreach (Property *prop, obj->properties) {
1926         int idx = type->metaObject()->indexOfProperty(prop->name.constData());
1927         if (idx == -1)
1928             COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1929         QMetaProperty p = type->metaObject()->property(idx);
1930         if (!p.isScriptable())
1931             COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
1932         prop->index = idx;
1933         prop->type = p.userType();
1934         prop->isValueTypeSubProperty = true;
1935
1936         if (prop->value)
1937             COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
1938
1939         if (prop->values.count() > 1) {
1940             COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
1941         } else if (prop->values.count()) {
1942             QDeclarativeParser::Value *value = prop->values.at(0);
1943
1944             if (value->object) {
1945                 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
1946             } else if (value->value.isScript()) {
1947                 // ### Check for writability
1948
1949                 //optimization for <Type>.<EnumValue> enum assignments
1950                 bool isEnumAssignment = false;
1951                 COMPILE_CHECK(testQualifiedEnumAssignment(p, obj, value, &isEnumAssignment));
1952                 if (isEnumAssignment) {
1953                     value->type = Value::Literal;
1954                 } else {
1955                     BindingReference reference;
1956                     reference.expression = value->value;
1957                     reference.property = prop;
1958                     reference.value = value;
1959                     reference.bindingContext = ctxt;
1960                     reference.bindingContext.owner++;
1961                     addBindingReference(reference);
1962                     value->type = Value::PropertyBinding;
1963                 }
1964             } else  {
1965                 COMPILE_CHECK(testLiteralAssignment(p, value));
1966                 value->type = Value::Literal;
1967             }
1968         }
1969
1970         for (int ii = 0; ii < prop->onValues.count(); ++ii) {
1971             QDeclarativeParser::Value *v = prop->onValues.at(ii);
1972             Q_ASSERT(v->object);
1973
1974             COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt)); 
1975         }
1976
1977         obj->addValueProperty(prop);
1978     }
1979
1980     return true;
1981 }
1982
1983 // Build assignments to QML lists.  QML lists are properties of type
1984 // QDeclarativeListProperty<T>.  List properties can accept a list of 
1985 // objects, or a single binding.
1986 bool QDeclarativeCompiler::buildListProperty(QDeclarativeParser::Property *prop,
1987                                              QDeclarativeParser::Object *obj,
1988                                              const BindingContext &ctxt)
1989 {
1990     Q_ASSERT(enginePrivate->isList(prop->type));
1991
1992     int t = prop->type;
1993
1994     obj->addValueProperty(prop);
1995
1996     int listType = enginePrivate->listType(t);
1997     bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1998
1999     bool assignedBinding = false;
2000     for (int ii = 0; ii < prop->values.count(); ++ii) {
2001         QDeclarativeParser::Value *v = prop->values.at(ii);
2002         if (v->object) {
2003             v->type = Value::CreatedObject;
2004             COMPILE_CHECK(buildObject(v->object, ctxt));
2005
2006             // We check object coercian here.  We check interface assignment
2007             // at runtime.
2008             if (!listTypeIsInterface) {
2009                 if (!canCoerce(listType, v->object)) {
2010                     COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2011                 }
2012             }
2013
2014         } else if (v->value.isScript()) {
2015             if (assignedBinding)
2016                 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2017
2018             assignedBinding = true;
2019             COMPILE_CHECK(buildBinding(v, prop, ctxt));
2020             v->type = Value::PropertyBinding;
2021         } else {
2022             COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2023         }
2024     }
2025
2026     return true;
2027 }
2028
2029 // Compiles an assignment to a QDeclarativeScriptString property
2030 bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeParser::Property *prop,
2031                                             QDeclarativeParser::Object *obj,
2032                                             const BindingContext &ctxt)
2033 {
2034     if (prop->values.count() > 1) 
2035         COMPILE_EXCEPTION(prop->values.at(1), tr( "Cannot assign multiple values to a script property"));
2036
2037     if (prop->values.at(0)->object)
2038         COMPILE_EXCEPTION(prop->values.at(0), tr( "Invalid property assignment: script expected"));
2039
2040     obj->addScriptStringProperty(prop, ctxt.stack);
2041
2042     return true;
2043 }
2044
2045 // Compile regular property assignments of the form "property: <value>"
2046 bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeParser::Property *prop,
2047                                           QDeclarativeParser::Object *obj,
2048                                           const BindingContext &ctxt)
2049 {
2050     obj->addValueProperty(prop);
2051
2052     if (prop->values.count() > 1)
2053         COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign multiple values to a singular property") );
2054
2055     for (int ii = 0; ii < prop->values.count(); ++ii) {
2056         QDeclarativeParser::Value *v = prop->values.at(ii);
2057         if (v->object) {
2058
2059             COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2060
2061         } else {
2062
2063             COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2064
2065         }
2066     }
2067
2068     for (int ii = 0; ii < prop->onValues.count(); ++ii) {
2069         QDeclarativeParser::Value *v = prop->onValues.at(ii);
2070
2071         Q_ASSERT(v->object);
2072         COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2073     }
2074
2075     return true;
2076 }
2077
2078 // Compile assigning a single object instance to a regular property
2079 bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeParser::Property *prop,
2080                                                          QDeclarativeParser::Object *obj,
2081                                                          QDeclarativeParser::Value *v,
2082                                                          const BindingContext &ctxt)
2083 {
2084     Q_ASSERT(prop->index != -1);
2085     Q_ASSERT(v->object->type != -1);
2086
2087     if (!obj->metaObject()->property(prop->index).isWritable())
2088         COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2089
2090     if (QDeclarativeMetaType::isInterface(prop->type)) {
2091
2092         // Assigning an object to an interface ptr property
2093         COMPILE_CHECK(buildObject(v->object, ctxt));
2094
2095         v->type = Value::CreatedObject;
2096
2097     } else if (prop->type == -1) {
2098
2099         // Assigning an object to a QVariant
2100         COMPILE_CHECK(buildObject(v->object, ctxt));
2101
2102         v->type = Value::CreatedObject;
2103     } else {
2104         // Normally buildObject() will set this up, but we need the static
2105         // meta object earlier to test for assignability.  It doesn't matter
2106         // that there may still be outstanding synthesized meta object changes
2107         // on this type, as they are not relevant for assignability testing
2108         v->object->metatype = output->types.at(v->object->type).metaObject();
2109         Q_ASSERT(v->object->metaObject());
2110
2111         // We want to raw metaObject here as the raw metaobject is the
2112         // actual property type before we applied any extensions that might
2113         // effect the properties on the type, but don't effect assignability
2114         const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2115
2116         // Will be true if the assgned type inherits propertyMetaObject
2117         bool isAssignable = false;
2118         // Determine isAssignable value
2119         if (propertyMetaObject) {
2120             const QMetaObject *c = v->object->metatype;
2121             while(c) {
2122                 isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject));
2123                 c = c->superClass();
2124             }
2125         }
2126
2127         if (isAssignable) {
2128             // Simple assignment
2129             COMPILE_CHECK(buildObject(v->object, ctxt));
2130
2131             v->type = Value::CreatedObject;
2132         } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) {
2133             // Automatic "Component" insertion
2134             QDeclarativeParser::Object *root = v->object;
2135             QDeclarativeParser::Object *component = new QDeclarativeParser::Object;
2136             component->type = componentTypeRef();
2137             component->typeName = "Qt/Component";
2138             component->metatype = &QDeclarativeComponent::staticMetaObject;
2139             component->location = root->location;
2140             QDeclarativeParser::Value *componentValue = new QDeclarativeParser::Value;
2141             componentValue->object = root;
2142             component->getDefaultProperty()->addValue(componentValue);
2143             v->object = component;
2144             COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2145         } else {
2146             COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2147         }
2148     }
2149
2150     return true;
2151 }
2152
2153 // Compile assigning a single object instance to a regular property using the "on" syntax.
2154 //
2155 // For example:
2156 //     Item {
2157 //         NumberAnimation on x { }
2158 //     }
2159 bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeParser::Property *prop,
2160                                                      QDeclarativeParser::Object *obj,
2161                                                      QDeclarativeParser::Object *baseObj,
2162                                                      QDeclarativeParser::Value *v,
2163                                                      const BindingContext &ctxt)
2164 {
2165     Q_ASSERT(prop->index != -1);
2166     Q_ASSERT(v->object->type != -1);
2167
2168     if (!obj->metaObject()->property(prop->index).isWritable())
2169         COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2170
2171
2172     // Normally buildObject() will set this up, but we need the static
2173     // meta object earlier to test for assignability.  It doesn't matter
2174     // that there may still be outstanding synthesized meta object changes
2175     // on this type, as they are not relevant for assignability testing
2176     v->object->metatype = output->types.at(v->object->type).metaObject();
2177     Q_ASSERT(v->object->metaObject());
2178
2179     // Will be true if the assigned type inherits QDeclarativePropertyValueSource
2180     bool isPropertyValue = false;
2181     // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor
2182     bool isPropertyInterceptor = false;
2183     if (QDeclarativeType *valueType = toQmlType(v->object)) {
2184         isPropertyValue = valueType->propertyValueSourceCast() != -1;
2185         isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2186     }
2187
2188     if (isPropertyValue || isPropertyInterceptor) {
2189         // Assign as a property value source
2190         COMPILE_CHECK(buildObject(v->object, ctxt));
2191
2192         if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2193             buildDynamicMeta(baseObj, ForceCreation);
2194         v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2195     } else {
2196         COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(QString::fromUtf8(v->object->typeName)).arg(QString::fromUtf8(prop->name.constData())));
2197     }
2198
2199     return true;
2200 }
2201
2202 // Compile assigning a literal or binding to a regular property
2203 bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeParser::Property *prop,
2204                                                  QDeclarativeParser::Object *obj,
2205                                                  QDeclarativeParser::Value *v,
2206                                                  const BindingContext &ctxt)
2207 {
2208     Q_ASSERT(prop->index != -1);
2209
2210     if (v->value.isScript()) {
2211
2212         //optimization for <Type>.<EnumValue> enum assignments
2213         bool isEnumAssignment = false;
2214         COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj, v, &isEnumAssignment));
2215         if (isEnumAssignment) {
2216             v->type = Value::Literal;
2217             return true;
2218         }
2219
2220         COMPILE_CHECK(buildBinding(v, prop, ctxt));
2221
2222         v->type = Value::PropertyBinding;
2223
2224     } else {
2225
2226         COMPILE_CHECK(testLiteralAssignment(obj->metaObject()->property(prop->index), v));
2227
2228         v->type = Value::Literal;
2229     }
2230
2231     return true;
2232 }
2233
2234 bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop,
2235                                               QDeclarativeParser::Object *obj,
2236                                               QDeclarativeParser::Value *v,
2237                                               bool *isAssignment)
2238 {
2239     *isAssignment = false;
2240     if (!prop.isEnumType())
2241         return true;
2242
2243     if (!prop.isWritable())
2244         COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
2245
2246     QString string = v->value.asString();
2247     if (!string.at(0).isUpper())
2248         return true;
2249
2250     QStringList parts = string.split(QLatin1Char('.'));
2251     if (parts.count() != 2)
2252         return true;
2253
2254     QString typeName = parts.at(0);
2255     QDeclarativeType *type = 0;
2256     unit->imports().resolveType(typeName.toUtf8(), &type, 0, 0, 0, 0);
2257
2258     //handle enums on value types (where obj->typeName is empty)
2259     QByteArray objTypeName = obj->typeName;
2260     if (objTypeName.isEmpty()) {
2261         QDeclarativeType *objType = toQmlType(obj);
2262         if (objType)
2263             objTypeName = objType->qmlTypeName();
2264     }
2265
2266     if (!type)
2267         return true;
2268
2269     QString enumValue = parts.at(1);
2270     int value = -1;
2271
2272     if (objTypeName == type->qmlTypeName()) {
2273         // When these two match, we can short cut the search
2274         if (prop.isFlagType()) {
2275             value = prop.enumerator().keysToValue(enumValue.toUtf8().constData());
2276         } else {
2277             value = prop.enumerator().keyToValue(enumValue.toUtf8().constData());
2278         }
2279     } else {
2280         // Otherwise we have to search the whole type
2281         // This matches the logic in QV8TypeWrapper
2282         QByteArray enumName = enumValue.toUtf8();
2283         const QMetaObject *metaObject = type->baseMetaObject();
2284         for (int ii = metaObject->enumeratorCount() - 1; value == -1 && ii >= 0; --ii) {
2285             QMetaEnum e = metaObject->enumerator(ii);
2286             value = e.keyToValue(enumName.constData());
2287         }
2288     }
2289
2290     if (value == -1)
2291         return true;
2292
2293     v->type = Value::Literal;
2294     v->value = QDeclarativeParser::Variant((double)value);
2295     *isAssignment = true;
2296
2297     return true;
2298 }
2299
2300 // Similar logic to above, but not knowing target property.
2301 int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const
2302 {
2303     int dot = script.indexOf('.');
2304     if (dot > 0) {
2305         QDeclarativeType *type = 0;
2306         unit->imports().resolveType(script.left(dot), &type, 0, 0, 0, 0);
2307         if (!type)
2308             return -1;
2309         const QMetaObject *mo = type->metaObject();
2310         const char *key = script.constData() + dot+1;
2311         int i = mo->enumeratorCount();
2312         while (i--) {
2313             int v = mo->enumerator(i).keyToValue(key);
2314             if (v >= 0)
2315                 return v;
2316         }
2317     }
2318     return -1;
2319 }
2320
2321 const QMetaObject *QDeclarativeCompiler::resolveType(const QByteArray& name) const
2322 {
2323     QDeclarativeType *qmltype = 0;
2324     if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0)) 
2325         return 0;
2326     if (!qmltype)
2327         return 0;
2328     return qmltype->metaObject();
2329 }
2330
2331 // similar to logic of completeComponentBuild, but also sticks data
2332 // into primitives at the end
2333 int QDeclarativeCompiler::rewriteBinding(const QString& expression, const QByteArray& name)
2334 {
2335     QDeclarativeRewrite::RewriteBinding rewriteBinding;
2336     rewriteBinding.setName('$' + name.mid(name.lastIndexOf('.') + 1));
2337
2338     QString rewrite = rewriteBinding(expression, 0, 0);
2339
2340     return output->indexForString(rewrite);
2341 }
2342
2343 // Ensures that the dynamic meta specification on obj is valid
2344 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj)
2345 {
2346     QSet<QByteArray> propNames;
2347     QSet<QByteArray> methodNames;
2348     bool seenDefaultProperty = false;
2349
2350     // Check properties
2351     for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2352         const QDeclarativeParser::Object::DynamicProperty &prop =
2353             obj->dynamicProperties.at(ii);
2354
2355         if (prop.isDefaultProperty) {
2356             if (seenDefaultProperty)
2357                 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2358             seenDefaultProperty = true;
2359         }
2360
2361         if (propNames.contains(prop.name))
2362             COMPILE_EXCEPTION(&prop, tr("Duplicate property name"));
2363
2364         QString propName = QString::fromUtf8(prop.name);
2365         if (propName.at(0).isUpper())
2366             COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
2367
2368         if (enginePrivate->v8engine.illegalNames().contains(propName))
2369             COMPILE_EXCEPTION(&prop, tr("Illegal property name"));
2370
2371         propNames.insert(prop.name);
2372     }
2373
2374     for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2375         QByteArray name = obj->dynamicSignals.at(ii).name;
2376         if (methodNames.contains(name))
2377             COMPILE_EXCEPTION(obj, tr("Duplicate signal name"));
2378         QString nameStr = QString::fromUtf8(name);
2379         if (nameStr.at(0).isUpper())
2380             COMPILE_EXCEPTION(obj, tr("Signal names cannot begin with an upper case letter"));
2381         if (enginePrivate->v8engine.illegalNames().contains(nameStr))
2382             COMPILE_EXCEPTION(obj, tr("Illegal signal name"));
2383         methodNames.insert(name);
2384     }
2385     for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2386         QByteArray name = obj->dynamicSlots.at(ii).name;
2387         if (methodNames.contains(name))
2388             COMPILE_EXCEPTION(obj, tr("Duplicate method name"));
2389         QString nameStr = QString::fromUtf8(name);
2390         if (nameStr.at(0).isUpper())
2391             COMPILE_EXCEPTION(obj, tr("Method names cannot begin with an upper case letter"));
2392         if (enginePrivate->v8engine.illegalNames().contains(nameStr))
2393             COMPILE_EXCEPTION(obj, tr("Illegal method name"));
2394         methodNames.insert(name);
2395     }
2396
2397     return true;
2398 }
2399
2400 bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeParser::Object *obj)
2401 {
2402     for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2403         const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2404
2405         if (!p.defaultValue || p.type == Object::DynamicProperty::Alias)
2406             continue;
2407
2408         Property *property = 0;
2409         if (p.isDefaultProperty) {
2410             property = obj->getDefaultProperty();
2411         } else {
2412             property = obj->getProperty(p.name);
2413             if (!property->values.isEmpty()) 
2414                 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2415         }
2416
2417         if (property->value)
2418             COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2419
2420         for (int ii = 0; ii < p.defaultValue->values.count(); ++ii) {
2421             QDeclarativeParser::Value *v = p.defaultValue->values.at(ii);
2422             v->addref();
2423             property->values.append(v);
2424         }
2425     }
2426     return true;
2427 }
2428
2429 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2430
2431 bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, DynamicMetaMode mode)
2432 {
2433     Q_ASSERT(obj);
2434     Q_ASSERT(obj->metatype);
2435
2436     if (mode != ForceCreation &&
2437         obj->dynamicProperties.isEmpty() &&
2438         obj->dynamicSignals.isEmpty() &&
2439         obj->dynamicSlots.isEmpty())
2440         return true;
2441
2442     QByteArray dynamicData(sizeof(QDeclarativeVMEMetaData), (char)0);
2443
2444     QByteArray newClassName = obj->metatype->className();
2445     newClassName.append("_QML_");
2446     int idx = classIndexCounter()->fetchAndAddRelaxed(1);
2447     newClassName.append(QByteArray::number(idx));
2448     if (compileState.root == obj && !compileState.nested) {
2449         QString path = output->url.path();
2450         int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2451         if (lastSlash > -1) {
2452             QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2453             if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2454                 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(idx);
2455         }
2456     }
2457
2458     QMetaObjectBuilder builder;
2459     builder.setClassName(newClassName);
2460     builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
2461
2462     bool hasAlias = false;
2463     for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2464         const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2465
2466         int propIdx = obj->metaObject()->indexOfProperty(p.name.constData());
2467         if (-1 != propIdx) {
2468             QMetaProperty prop = obj->metaObject()->property(propIdx);
2469             if (prop.isFinal())
2470                 COMPILE_EXCEPTION(&p, tr("Cannot override FINAL property"));
2471         }
2472
2473         if (p.isDefaultProperty &&
2474             (p.type != Object::DynamicProperty::Alias ||
2475              mode == ResolveAliases))
2476             builder.addClassInfo("DefaultProperty", p.name);
2477
2478         QByteArray type;
2479         int propertyType = 0;
2480         bool readonly = false;
2481         switch(p.type) {
2482         case Object::DynamicProperty::Alias:
2483             hasAlias = true;
2484             continue;
2485             break;
2486         case Object::DynamicProperty::CustomList:
2487         case Object::DynamicProperty::Custom:
2488             {
2489                 QByteArray customTypeName;
2490                 QDeclarativeType *qmltype = 0;
2491                 QUrl url;
2492                 if (!unit->imports().resolveType(p.customType, &qmltype, &url, 0, 0, 0)) 
2493                     COMPILE_EXCEPTION(&p, tr("Invalid property type"));
2494
2495                 if (!qmltype) {
2496                     QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(url);
2497                     Q_ASSERT(tdata);
2498                     Q_ASSERT(tdata->isComplete());
2499
2500                     QDeclarativeCompiledData *data = tdata->compiledData();
2501                     customTypeName = data->root->className();
2502                     data->release();
2503                     tdata->release();
2504                 } else {
2505                     customTypeName = qmltype->typeName();
2506                 }
2507
2508                 if (p.type == Object::DynamicProperty::Custom) {
2509                     type = customTypeName + '*';
2510                     propertyType = QMetaType::QObjectStar;
2511                 } else {
2512                     readonly = true;
2513                     type = "QDeclarativeListProperty<";
2514                     type.append(customTypeName);
2515                     type.append(">");
2516                     propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
2517                 }
2518             }
2519             break;
2520         case Object::DynamicProperty::Variant:
2521             propertyType = -1;
2522             type = "QVariant";
2523             break;
2524         case Object::DynamicProperty::Int:
2525             propertyType = QVariant::Int;
2526             type = "int";
2527             break;
2528         case Object::DynamicProperty::Bool:
2529             propertyType = QVariant::Bool;
2530             type = "bool";
2531             break;
2532         case Object::DynamicProperty::Real:
2533             propertyType = QVariant::Double;
2534             type = "double";
2535             break;
2536         case Object::DynamicProperty::String:
2537             propertyType = QVariant::String;
2538             type = "QString";
2539             break;
2540         case Object::DynamicProperty::Url:
2541             propertyType = QVariant::Url;
2542             type = "QUrl";
2543             break;
2544         case Object::DynamicProperty::Color:
2545             propertyType = QVariant::Color;
2546             type = "QColor";
2547             break;
2548         case Object::DynamicProperty::Time:
2549             propertyType = QVariant::Time;
2550             type = "QTime";
2551             break;
2552         case Object::DynamicProperty::Date:
2553             propertyType = QVariant::Date;
2554             type = "QDate";
2555             break;
2556         case Object::DynamicProperty::DateTime:
2557             propertyType = QVariant::DateTime;
2558             type = "QDateTime";
2559             break;
2560         }
2561
2562         ((QDeclarativeVMEMetaData *)dynamicData.data())->propertyCount++;
2563         QDeclarativeVMEMetaData::PropertyData propertyData = { propertyType };
2564         dynamicData.append((char *)&propertyData, sizeof(propertyData));
2565
2566         builder.addSignal(p.name + "Changed()");
2567         QMetaPropertyBuilder propBuilder = 
2568             builder.addProperty(p.name, type, builder.methodCount() - 1);
2569         propBuilder.setWritable(!readonly);
2570     }
2571
2572     for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
2573         const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
2574
2575         if (p.type == Object::DynamicProperty::Alias) {
2576             if (mode == ResolveAliases) {
2577                 ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++;
2578                 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, p));
2579             } else {
2580                 // Need a fake signal so that the metaobject remains consistent across
2581                 // the resolve and non-resolve alias runs
2582                 builder.addSignal(p.name + "Changed()");
2583             }
2584         }
2585     }
2586
2587     for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
2588         const Object::DynamicSignal &s = obj->dynamicSignals.at(ii);
2589         QByteArray sig(s.name + '(');
2590         for (int jj = 0; jj < s.parameterTypes.count(); ++jj) {
2591             if (jj) sig.append(',');
2592             sig.append(s.parameterTypes.at(jj));
2593         }
2594         sig.append(')');
2595         QMetaMethodBuilder b = builder.addSignal(sig);
2596         b.setParameterNames(s.parameterNames);
2597         ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++;
2598     }
2599
2600     QStringList funcScripts;
2601
2602     for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2603         Object::DynamicSlot &s = obj->dynamicSlots[ii];
2604         QByteArray sig(s.name + '(');
2605         QString funcScript(QLatin1String("(function ") + s.name + QLatin1Char('('));
2606
2607         for (int jj = 0; jj < s.parameterNames.count(); ++jj) {
2608             if (jj) { 
2609                 sig.append(',');
2610                 funcScript.append(QLatin1Char(','));
2611             }
2612             funcScript.append(QLatin1String(s.parameterNames.at(jj)));
2613             sig.append("QVariant");
2614         }
2615         sig.append(')');
2616         funcScript.append(QLatin1Char(')'));
2617         funcScript.append(s.body);
2618         funcScript.append(QLatin1Char(')'));
2619         funcScripts << funcScript;
2620
2621         QMetaMethodBuilder b = builder.addSlot(sig);
2622         b.setReturnType("QVariant");
2623         b.setParameterNames(s.parameterNames);
2624
2625         ((QDeclarativeVMEMetaData *)dynamicData.data())->methodCount++;
2626         QDeclarativeVMEMetaData::MethodData methodData =
2627              { s.parameterNames.count(), 0, funcScript.length(), s.location.start.line };
2628
2629         dynamicData.append((char *)&methodData, sizeof(methodData));
2630     }
2631
2632     for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
2633         const QString &funcScript = funcScripts.at(ii);
2634         QDeclarativeVMEMetaData::MethodData *data =
2635             ((QDeclarativeVMEMetaData *)dynamicData.data())->methodData() + ii;
2636
2637         data->bodyOffset = dynamicData.size();
2638
2639         dynamicData.append((const char *)funcScript.constData(),
2640                            (funcScript.length() * sizeof(QChar)));
2641     }
2642
2643     obj->metadata = builder.toRelocatableData();
2644     builder.fromRelocatableData(&obj->extObject, obj->metatype, obj->metadata);
2645
2646     if (mode == IgnoreAliases && hasAlias)
2647         compileState.aliasingObjects << obj;
2648
2649     obj->synthdata = dynamicData;
2650
2651     if (obj->synthCache) {
2652         obj->synthCache->release();
2653         obj->synthCache = 0;
2654     }
2655
2656     if (obj->type != -1) {
2657         QDeclarativePropertyCache *cache = output->types[obj->type].createPropertyCache(engine)->copy();
2658         cache->append(engine, &obj->extObject, QDeclarativePropertyCache::Data::NoFlags,
2659                       QDeclarativePropertyCache::Data::IsVMEFunction, 
2660                       QDeclarativePropertyCache::Data::IsVMESignal);
2661         obj->synthCache = cache;
2662     }
2663
2664     return true;
2665 }
2666
2667 bool QDeclarativeCompiler::checkValidId(QDeclarativeParser::Value *v, const QString &val)
2668 {
2669     if (val.isEmpty()) 
2670         COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
2671
2672     if (val.at(0).isLetter() && !val.at(0).isLower()) 
2673         COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
2674
2675     QChar u(QLatin1Char('_'));
2676     for (int ii = 0; ii < val.count(); ++ii) {
2677
2678         if (ii == 0 && !val.at(ii).isLetter() && val.at(ii) != u) {
2679             COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
2680         } else if (ii != 0 && !val.at(ii).isLetterOrNumber() && val.at(ii) != u)  {
2681             COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
2682         }
2683
2684     }
2685
2686     if (enginePrivate->v8engine.illegalNames().contains(val))
2687         COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
2688
2689     return true;
2690 }
2691
2692 #include <qdeclarativejsparser_p.h>
2693
2694 static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node)
2695 {
2696     if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) {
2697         QString name =
2698             static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name->asString();
2699         return QStringList() << name;
2700     } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) {
2701         QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node);
2702
2703         QStringList rv = astNodeToStringList(expr->base);
2704         if (rv.isEmpty())
2705             return rv;
2706         rv.append(expr->name->asString());
2707         return rv;
2708     }
2709     return QStringList();
2710 }
2711
2712 bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder,
2713                                         QByteArray &data,
2714                                         QDeclarativeParser::Object *obj,
2715                                         const Object::DynamicProperty &prop)
2716 {
2717     if (!prop.defaultValue)
2718         COMPILE_EXCEPTION(obj, tr("No property alias location"));
2719
2720     if (prop.defaultValue->values.count() != 1 ||
2721         prop.defaultValue->values.at(0)->object ||
2722         !prop.defaultValue->values.at(0)->value.isScript())
2723         COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2724
2725     QDeclarativeJS::AST::Node *node = prop.defaultValue->values.at(0)->value.asAST();
2726     if (!node)
2727         COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
2728
2729     QStringList alias = astNodeToStringList(node);
2730
2731     if (alias.count() < 1 || alias.count() > 3)
2732         COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
2733
2734     if (!compileState.ids.contains(alias.at(0)))
2735         COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
2736
2737     QDeclarativeParser::Object *idObject = compileState.ids[alias.at(0)];
2738
2739     QByteArray typeName;
2740
2741     int propIdx = -1;
2742     int flags = 0;
2743     bool writable = false;
2744     if (alias.count() == 2 || alias.count() == 3) {
2745         propIdx = indexOfProperty(idObject, alias.at(1).toUtf8());
2746
2747         if (-1 == propIdx) {
2748             COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2749         } else if (propIdx > 0xFFFF) {
2750             COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
2751         }
2752
2753         QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
2754         if (!aliasProperty.isScriptable())
2755             COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2756
2757         writable = aliasProperty.isWritable();
2758
2759         if (alias.count() == 3) {
2760             QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
2761             if (!valueType)
2762                 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2763
2764             propIdx |= ((unsigned int)aliasProperty.type()) << 24;
2765
2766             int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
2767             if (valueTypeIndex == -1)
2768                 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2769             Q_ASSERT(valueTypeIndex <= 0xFF);
2770             
2771             aliasProperty = valueType->metaObject()->property(valueTypeIndex);
2772             propIdx |= (valueTypeIndex << 16);
2773         }
2774
2775         if (aliasProperty.isEnumType()) 
2776             typeName = "int";  // Avoid introducing a dependency on the aliased metaobject
2777         else
2778             typeName = aliasProperty.typeName();
2779     } else {
2780         typeName = idObject->metaObject()->className();
2781
2782         //use the base type since it has been registered with metatype system
2783         int index = typeName.indexOf("_QML_");
2784         if (index != -1) {
2785             typeName = typeName.left(index);
2786         } else {
2787             index = typeName.indexOf("_QMLTYPE_");
2788             const QMetaObject *mo = idObject->metaObject();
2789             while (index != -1 && mo) {
2790                 typeName = mo->superClass()->className();
2791                 index = typeName.indexOf("_QMLTYPE_");
2792                 mo = mo->superClass();
2793             }
2794         }
2795
2796         typeName += '*';
2797     }
2798
2799     if (typeName.endsWith('*'))
2800         flags |= QML_ALIAS_FLAG_PTR;
2801
2802     data.append((const char *)&idObject->idIndex, sizeof(idObject->idIndex));
2803     data.append((const char *)&propIdx, sizeof(propIdx));
2804     data.append((const char *)&flags, sizeof(flags));
2805
2806     builder.addSignal(prop.name + "Changed()");
2807     QMetaPropertyBuilder propBuilder = 
2808         builder.addProperty(prop.name, typeName.constData(), builder.methodCount() - 1);
2809     propBuilder.setWritable(writable);
2810     return true;
2811 }
2812
2813 bool QDeclarativeCompiler::buildBinding(QDeclarativeParser::Value *value,
2814                                QDeclarativeParser::Property *prop,
2815                                const BindingContext &ctxt)
2816 {
2817     Q_ASSERT(prop->index != -1);
2818     Q_ASSERT(prop->parent);
2819     Q_ASSERT(prop->parent->metaObject());
2820
2821     QMetaProperty mp = prop->parent->metaObject()->property(prop->index);
2822     if (!mp.isWritable() && !QDeclarativeMetaType::isList(prop->type))
2823         COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
2824
2825     BindingReference reference;
2826     reference.expression = value->value;
2827     reference.property = prop;
2828     reference.value = value;
2829     reference.bindingContext = ctxt;
2830     addBindingReference(reference);
2831
2832     return true;
2833 }
2834
2835 void QDeclarativeCompiler::genBindingAssignment(QDeclarativeParser::Value *binding,
2836                                                 QDeclarativeParser::Property *prop,
2837                                                 QDeclarativeParser::Object *obj,
2838                                                 QDeclarativeParser::Property *valueTypeProperty)
2839 {
2840     Q_UNUSED(obj);
2841     Q_ASSERT(compileState.bindings.contains(binding));
2842
2843     const BindingReference &ref = compileState.bindings.value(binding);
2844     if (ref.dataType == BindingReference::V4) {
2845         QDeclarativeInstruction store;
2846         store.setType(QDeclarativeInstruction::StoreV4Binding);
2847         store.assignBinding.value = ref.compiledIndex;
2848         store.assignBinding.context = ref.bindingContext.stack;
2849         store.assignBinding.owner = ref.bindingContext.owner;
2850         if (valueTypeProperty) 
2851             store.assignBinding.property = (valueTypeProperty->index & 0xFFFF) |
2852                                            ((valueTypeProperty->type & 0xFF)) << 16 |
2853                                            ((prop->index & 0xFF) << 24);
2854         else 
2855             store.assignBinding.property = prop->index;
2856         store.assignBinding.line = binding->location.start.line;
2857         output->addInstruction(store);
2858     } else if (ref.dataType == BindingReference::V8) {
2859         QDeclarativeInstruction store;
2860         store.setType(QDeclarativeInstruction::StoreV8Binding);
2861         store.assignBinding.value = ref.compiledIndex;
2862         store.assignBinding.context = ref.bindingContext.stack;
2863         store.assignBinding.owner = ref.bindingContext.owner;
2864         store.assignBinding.line = binding->location.start.line;
2865
2866         Q_ASSERT(ref.bindingContext.owner == 0 ||
2867                  (ref.bindingContext.owner != 0 && valueTypeProperty));
2868         if (ref.bindingContext.owner) {
2869             store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
2870         } else {
2871             store.assignBinding.property = genPropertyData(prop);
2872         }
2873
2874         output->addInstruction(store);
2875     } else {
2876         QDeclarativeInstruction store;
2877         if (!prop->isAlias)
2878             store.setType(QDeclarativeInstruction::StoreBinding);
2879         else
2880             store.setType(QDeclarativeInstruction::StoreBindingOnAlias);
2881         store.assignBinding.value = output->indexForString(ref.rewrittenExpression);
2882         store.assignBinding.context = ref.bindingContext.stack;
2883         store.assignBinding.owner = ref.bindingContext.owner;
2884         store.assignBinding.line = binding->location.start.line;
2885
2886         Q_ASSERT(ref.bindingContext.owner == 0 ||
2887                  (ref.bindingContext.owner != 0 && valueTypeProperty));
2888         if (ref.bindingContext.owner) {
2889             store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
2890         } else {
2891             store.assignBinding.property = genPropertyData(prop);
2892         }
2893         output->addInstruction(store);
2894     }
2895 }
2896
2897 int QDeclarativeCompiler::genContextCache()
2898 {
2899     if (compileState.ids.count() == 0)
2900         return -1;
2901
2902     QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache();
2903
2904     for (QHash<QString, QDeclarativeParser::Object *>::ConstIterator iter = compileState.ids.begin();
2905          iter != compileState.ids.end();
2906          ++iter) 
2907         cache->add(iter.key(), (*iter)->idIndex);
2908
2909     output->contextCaches.append(cache);
2910     return output->contextCaches.count() - 1;
2911 }
2912
2913 int QDeclarativeCompiler::genValueTypeData(QDeclarativeParser::Property *valueTypeProp, 
2914                                   QDeclarativeParser::Property *prop)
2915 {
2916     QByteArray data =
2917         QDeclarativePropertyPrivate::saveValueType(prop->parent->metaObject(), prop->index, 
2918                                                    enginePrivate->valueTypes[prop->type]->metaObject(), 
2919                                                    valueTypeProp->index);
2920 //                valueTypeProp->index, valueTypeProp->type);
2921
2922     return output->indexForByteArray(data);
2923 }
2924
2925 int QDeclarativeCompiler::genPropertyData(QDeclarativeParser::Property *prop)
2926 {
2927     return output->indexForByteArray(QDeclarativePropertyPrivate::saveProperty(prop->parent->metaObject(), prop->index));
2928 }
2929
2930 bool QDeclarativeCompiler::completeComponentBuild()
2931 {
2932     componentStat.ids = compileState.ids.count();
2933
2934     for (int ii = 0; ii < compileState.aliasingObjects.count(); ++ii) {
2935         QDeclarativeParser::Object *aliasObject = compileState.aliasingObjects.at(ii);
2936         COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
2937     }
2938
2939     QDeclarativeV4Compiler::Expression expr;
2940     expr.component = compileState.root;
2941     expr.ids = compileState.ids;
2942     expr.importCache = output->importCache;
2943     expr.imports = unit->imports();
2944
2945     QDeclarativeV4Compiler bindingCompiler;
2946
2947     QList<BindingReference*> sharedBindings;
2948
2949     for (QHash<QDeclarativeParser::Value*,BindingReference>::Iterator iter = compileState.bindings.begin(); 
2950          iter != compileState.bindings.end(); ++iter) {
2951
2952         BindingReference &binding = *iter;
2953
2954         // ### We don't currently optimize for bindings on alias's - because 
2955         // of the solution to QTBUG-13719
2956         if (!binding.property->isAlias) {
2957             expr.context = binding.bindingContext.object;
2958             expr.property = binding.property;
2959             expr.expression = binding.expression;
2960
2961             int index = bindingCompiler.compile(expr, enginePrivate);
2962             if (index != -1) {
2963                 binding.dataType = BindingReference::V4;
2964                 binding.compiledIndex = index;
2965                 componentStat.optimizedBindings.append(iter.key()->location);
2966                 continue;
2967             } 
2968         }
2969
2970         // Pre-rewrite the expression
2971         QString expression = binding.expression.asScript();
2972
2973         QDeclarativeRewrite::RewriteBinding rewriteBinding;
2974         rewriteBinding.setName('$'+binding.property->name);
2975         bool isSharable = false;
2976         binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
2977
2978         if (isSharable && !binding.property->isAlias /* See above re alias */ &&
2979             binding.property->type != qMetaTypeId<QDeclarativeBinding*>()) {
2980             binding.dataType = BindingReference::V8;
2981             sharedBindings.append(&iter.value());
2982         } else {
2983             binding.dataType = BindingReference::QtScript;
2984         }
2985
2986         componentStat.scriptBindings.append(iter.key()->location);
2987     }
2988
2989     if (!sharedBindings.isEmpty()) {
2990         struct Sort {
2991             static bool lt(const BindingReference *lhs, const BindingReference *rhs)
2992             {
2993                 return lhs->value->location.start.line < rhs->value->location.start.line;
2994             }
2995         };
2996
2997         qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
2998
2999         int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3000         int lineNumber = startLineNumber;
3001
3002         QString functionArray(QLatin1String("["));
3003         for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3004             BindingReference *reference = sharedBindings.at(ii);
3005             QDeclarativeParser::Value *value = reference->value;
3006             const QString &expression = reference->rewrittenExpression;
3007
3008             if (ii != 0) functionArray += QLatin1String(",");
3009
3010             while (lineNumber < value->location.start.line) {
3011                 lineNumber++;
3012                 functionArray += QLatin1String("\n");
3013             }
3014
3015             functionArray += expression;
3016             reference->compiledIndex = ii;
3017         }
3018         functionArray += QLatin1String("]");
3019
3020         compileState.v8BindingProgram = functionArray;
3021         compileState.v8BindingProgramLine = startLineNumber;
3022         compileState.v8BindingProgramIndex = output->v8bindings.count();
3023         output->v8bindings.append(v8::Persistent<v8::Array>());
3024     }
3025
3026     if (bindingCompiler.isValid()) 
3027         compileState.compiledBindingData = bindingCompiler.program();
3028
3029     saveComponentState();
3030
3031     return true;
3032 }
3033
3034 void QDeclarativeCompiler::dumpStats()
3035 {
3036     qWarning().nospace() << "QML Document: " << output->url.toString();
3037     for (int ii = 0; ii < savedComponentStats.count(); ++ii) {
3038         const ComponentStat &stat = savedComponentStats.at(ii);
3039         qWarning().nospace() << "    Component Line " << stat.lineNumber;
3040         qWarning().nospace() << "        Total Objects:      " << stat.objects;
3041         qWarning().nospace() << "        IDs Used:           " << stat.ids;
3042         qWarning().nospace() << "        Optimized Bindings: " << stat.optimizedBindings.count();
3043
3044         {
3045         QByteArray output;
3046         for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3047             if (0 == (ii % 10)) {
3048                 if (ii) output.append("\n");
3049                 output.append("            ");
3050             }
3051
3052             output.append("(");
3053             output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3054             output.append(":");
3055             output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3056             output.append(") ");
3057         }
3058         if (!output.isEmpty())
3059             qWarning().nospace() << output.constData();
3060         }
3061
3062         qWarning().nospace() << "        QScript Bindings:   " << stat.scriptBindings.count();
3063         {
3064         QByteArray output;
3065         for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3066             if (0 == (ii % 10)) {
3067                 if (ii) output.append("\n");
3068                 output.append("            ");
3069             }
3070
3071             output.append("(");
3072             output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3073             output.append(":");
3074             output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3075             output.append(") ");
3076         }
3077         if (!output.isEmpty())
3078             qWarning().nospace() << output.constData();
3079         }
3080     }
3081 }
3082
3083 /*!
3084     Returns true if from can be assigned to a (QObject) property of type
3085     to.
3086 */
3087 bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeParser::Object *from)
3088 {
3089     const QMetaObject *toMo = 
3090         enginePrivate->rawMetaObjectForType(to);
3091     const QMetaObject *fromMo = from->metaObject();
3092
3093     while (fromMo) {
3094         if (QDeclarativePropertyPrivate::equal(fromMo, toMo))
3095             return true;
3096         fromMo = fromMo->superClass();
3097     }
3098     return false;
3099 }
3100
3101 QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeParser::Object *from)
3102 {
3103     // ### Optimize
3104     const QMetaObject *mo = from->metatype;
3105     QDeclarativeType *type = 0;
3106     while (!type && mo) {
3107         type = QDeclarativeMetaType::qmlType(mo);
3108         mo = mo->superClass();
3109     }
3110    return type;
3111 }
3112
3113 QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeParser::Object *obj)
3114 {
3115     const QMetaObject *mo = obj->metatype;
3116
3117     int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3118     if (idx == -1)
3119         return QStringList();
3120
3121     QMetaClassInfo classInfo = mo->classInfo(idx);
3122     QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3123     return rv;
3124 }
3125
3126 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3127 int QDeclarativeCompiler::indexOfSignal(QDeclarativeParser::Object *object, const QByteArray &name, 
3128                                         bool *notInRevision)
3129 {
3130     if (notInRevision) *notInRevision = false;
3131
3132     if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) {
3133         // XXX fromUtf8
3134         QString strName(QString::fromUtf8(name));
3135         QDeclarativePropertyCache *cache = 
3136             object->synthCache?object->synthCache:output->types.at(object->type).propertyCache();
3137
3138         QDeclarativePropertyCache::Data *d = cache->property(strName);
3139         if (notInRevision) *notInRevision = false;
3140
3141         while (d && !(d->flags & QDeclarativePropertyCache::Data::IsFunction))
3142             d = cache->overrideData(d);
3143
3144         if (d && !cache->isAllowedInRevision(d)) {
3145             if (notInRevision) *notInRevision = true;
3146             return -1;
3147         } else if (d) {
3148             return d->coreIndex;
3149         }
3150
3151         if (name.endsWith("Changed")) {
3152             QByteArray propName = name.mid(0, name.length() - 7);
3153
3154             int propIndex = indexOfProperty(object, propName, notInRevision);
3155             if (propIndex != -1) {
3156                 d = cache->property(propIndex);
3157                 return d->notifyIndex;
3158             }
3159         }
3160
3161         return -1;
3162     } else {
3163         return QDeclarativePropertyPrivate::findSignalByName(object->metaObject(), name).methodIndex();
3164     }
3165
3166 }
3167
3168 int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QByteArray &name, 
3169                                           bool *notInRevision)
3170 {
3171     if (notInRevision) *notInRevision = false;
3172
3173     if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) {
3174         // XXX fromUtf8
3175         QString strName(QString::fromUtf8(name));
3176         QDeclarativePropertyCache *cache = 
3177             object->synthCache?object->synthCache:output->types.at(object->type).propertyCache();
3178
3179         QDeclarativePropertyCache::Data *d = cache->property(strName);
3180         // Find the first property
3181         while (d && d->flags & QDeclarativePropertyCache::Data::IsFunction) 
3182             d = cache->overrideData(d);
3183
3184         if (d && !cache->isAllowedInRevision(d)) {
3185             if (notInRevision) *notInRevision = true;
3186             return -1;
3187         } else {
3188             return d?d->coreIndex:-1;
3189         }
3190     } else {
3191         const QMetaObject *mo = object->metaObject();
3192         return mo->indexOfProperty(name.constData());
3193     }
3194 }
3195
3196 QT_END_NAMESPACE