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