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