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