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