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