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