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