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