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