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