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