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