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