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