src/declarative/qml/qdeclarativecompiler.cpp
changeset 30 5dc02b23752f
child 33 3e2da88830cd
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "private/qdeclarativecompiler_p.h"
       
    43 
       
    44 #include "private/qdeclarativecompositetypedata_p.h"
       
    45 #include "private/qdeclarativeparser_p.h"
       
    46 #include "private/qdeclarativescriptparser_p.h"
       
    47 #include "qdeclarativepropertyvaluesource.h"
       
    48 #include "qdeclarativecomponent.h"
       
    49 #include "private/qmetaobjectbuilder_p.h"
       
    50 #include "private/qdeclarativestringconverters_p.h"
       
    51 #include "private/qdeclarativeengine_p.h"
       
    52 #include "qdeclarativeengine.h"
       
    53 #include "qdeclarativecontext.h"
       
    54 #include "private/qdeclarativemetatype_p.h"
       
    55 #include "private/qdeclarativecustomparser_p_p.h"
       
    56 #include "private/qdeclarativecontext_p.h"
       
    57 #include "private/qdeclarativecomponent_p.h"
       
    58 #include "parser/qdeclarativejsast_p.h"
       
    59 #include "private/qdeclarativevmemetaobject_p.h"
       
    60 #include "private/qdeclarativeexpression_p.h"
       
    61 #include "private/qdeclarativeproperty_p.h"
       
    62 #include "private/qdeclarativerewrite_p.h"
       
    63 #include "qdeclarativescriptstring.h"
       
    64 #include "private/qdeclarativeglobal_p.h"
       
    65 #include "private/qdeclarativescriptparser_p.h"
       
    66 #include "private/qdeclarativebinding_p.h"
       
    67 #include "private/qdeclarativecompiledbindings_p.h"
       
    68 #include "private/qdeclarativeglobalscriptclass_p.h"
       
    69 
       
    70 #include <QColor>
       
    71 #include <QDebug>
       
    72 #include <QPointF>
       
    73 #include <QSizeF>
       
    74 #include <QRectF>
       
    75 #include <QAtomicInt>
       
    76 #include <QtCore/qdebug.h>
       
    77 #include <QtCore/qdatetime.h>
       
    78 
       
    79 QT_BEGIN_NAMESPACE
       
    80 
       
    81 DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP);
       
    82 DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS);
       
    83 DEFINE_BOOL_CONFIG_OPTION(bindingsDump, QML_BINDINGS_DUMP);
       
    84 
       
    85 using namespace QDeclarativeParser;
       
    86 
       
    87 /*!
       
    88     Instantiate a new QDeclarativeCompiler.
       
    89 */
       
    90 QDeclarativeCompiler::QDeclarativeCompiler()
       
    91 : output(0), engine(0), unitRoot(0), unit(0)
       
    92 {
       
    93 }
       
    94 
       
    95 /*!
       
    96     Returns true if the last call to compile() caused errors.
       
    97 
       
    98     \sa errors()
       
    99 */
       
   100 bool QDeclarativeCompiler::isError() const
       
   101 {
       
   102     return !exceptions.isEmpty();
       
   103 }
       
   104 
       
   105 /*!
       
   106     Return the list of errors from the last call to compile(), or an empty list
       
   107     if there were no errors.
       
   108 */
       
   109 QList<QDeclarativeError> QDeclarativeCompiler::errors() const
       
   110 {
       
   111     return exceptions;
       
   112 }
       
   113 
       
   114 /*!
       
   115     Returns true if \a name refers to an attached property, false otherwise.
       
   116 
       
   117     Attached property names are those that start with a capital letter.
       
   118 */
       
   119 bool QDeclarativeCompiler::isAttachedPropertyName(const QByteArray &name)
       
   120 {
       
   121     return !name.isEmpty() && name.at(0) >= 'A' && name.at(0) <= 'Z';
       
   122 }
       
   123 
       
   124 /*!
       
   125     Returns true if \a name refers to a signal property, false otherwise.
       
   126 
       
   127     Signal property names are those that start with "on", followed by a capital
       
   128     letter.
       
   129 */
       
   130 bool QDeclarativeCompiler::isSignalPropertyName(const QByteArray &name)
       
   131 {
       
   132     return name.length() >= 3 && name.startsWith("on") &&
       
   133            'A' <= name.at(2) && 'Z' >= name.at(2);
       
   134 }
       
   135 
       
   136 /*!
       
   137     \macro COMPILE_EXCEPTION
       
   138     \internal
       
   139     Inserts an error into the QDeclarativeCompiler error list, and returns false
       
   140     (failure).
       
   141 
       
   142     \a token is used to source the error line and column, and \a desc is the
       
   143     error itself.  \a desc can be an expression that can be piped into QDebug.
       
   144 
       
   145     For example:
       
   146 
       
   147     \code
       
   148     COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(QString::fromUtf8(property->name)));
       
   149     \endcode
       
   150 */
       
   151 #define COMPILE_EXCEPTION(token, desc) \
       
   152     {  \
       
   153         QString exceptionDescription; \
       
   154         QDeclarativeError error; \
       
   155         error.setUrl(output->url); \
       
   156         error.setLine((token)->location.start.line); \
       
   157         error.setColumn((token)->location.start.column); \
       
   158         error.setDescription(desc.trimmed()); \
       
   159         exceptions << error; \
       
   160         return false; \
       
   161     }
       
   162 
       
   163 /*!
       
   164     \macro COMPILE_CHECK
       
   165     \internal
       
   166     Returns false if \a is false, otherwise does nothing.
       
   167 */
       
   168 #define COMPILE_CHECK(a) \
       
   169     { \
       
   170         if (!a) return false; \
       
   171     }
       
   172 
       
   173 /*!
       
   174     Returns true if literal \a v can be assigned to property \a prop, otherwise
       
   175     false.
       
   176 
       
   177     This test corresponds to action taken by genLiteralAssignment().  Any change
       
   178     made here, must have a corresponding action in genLiteralAssigment().
       
   179 */
       
   180 bool QDeclarativeCompiler::testLiteralAssignment(const QMetaProperty &prop,
       
   181                                         QDeclarativeParser::Value *v)
       
   182 {
       
   183     QString string = v->value.asString();
       
   184 
       
   185     if (!prop.isWritable())
       
   186         COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
       
   187 
       
   188     if (prop.isEnumType()) {
       
   189         int value;
       
   190         if (prop.isFlagType()) {
       
   191             value = prop.enumerator().keysToValue(string.toUtf8().constData());
       
   192         } else
       
   193             value = prop.enumerator().keyToValue(string.toUtf8().constData());
       
   194         if (value == -1)
       
   195             COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration"));
       
   196         return true;
       
   197     }
       
   198     int type = prop.userType();
       
   199     switch(type) {
       
   200         case -1:
       
   201             break;
       
   202         case QVariant::String:
       
   203             if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
       
   204             break;
       
   205         case QVariant::Url:
       
   206             if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected"));
       
   207             break;
       
   208         case QVariant::UInt:
       
   209             {
       
   210             bool ok = v->value.isNumber();
       
   211             if (ok) {
       
   212                 double n = v->value.asNumber();
       
   213                 if (double(uint(n)) != n)
       
   214                     ok = false;
       
   215             }
       
   216             if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected"));
       
   217             }
       
   218             break;
       
   219         case QVariant::Int:
       
   220             {
       
   221             bool ok = v->value.isNumber();
       
   222             if (ok) {
       
   223                 double n = v->value.asNumber();
       
   224                 if (double(int(n)) != n)
       
   225                     ok = false;
       
   226             }
       
   227             if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected"));
       
   228             }
       
   229             break;
       
   230         case QMetaType::Float:
       
   231             if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: float expected"));
       
   232             break;
       
   233         case QVariant::Double:
       
   234             if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: double expected"));
       
   235             break;
       
   236         case QVariant::Color:
       
   237             {
       
   238             bool ok;
       
   239             QDeclarativeStringConverters::colorFromString(string, &ok);
       
   240             if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected"));
       
   241             }
       
   242             break;
       
   243         case QVariant::Date:
       
   244             {
       
   245             bool ok;
       
   246             QDeclarativeStringConverters::dateFromString(string, &ok);
       
   247             if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected"));
       
   248             }
       
   249             break;
       
   250         case QVariant::Time:
       
   251             {
       
   252             bool ok;
       
   253             QDeclarativeStringConverters::timeFromString(string, &ok);
       
   254             if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected"));
       
   255             }
       
   256             break;
       
   257         case QVariant::DateTime:
       
   258             {
       
   259             bool ok;
       
   260             QDeclarativeStringConverters::dateTimeFromString(string, &ok);
       
   261             if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected"));
       
   262             }
       
   263             break;
       
   264         case QVariant::Point:
       
   265         case QVariant::PointF:
       
   266             {
       
   267             bool ok;
       
   268             QPointF point = QDeclarativeStringConverters::pointFFromString(string, &ok);
       
   269             if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected"));
       
   270             }
       
   271             break;
       
   272         case QVariant::Size:
       
   273         case QVariant::SizeF:
       
   274             {
       
   275             bool ok;
       
   276             QSizeF size = QDeclarativeStringConverters::sizeFFromString(string, &ok);
       
   277             if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected"));
       
   278             }
       
   279             break;
       
   280         case QVariant::Rect:
       
   281         case QVariant::RectF:
       
   282             {
       
   283             bool ok;
       
   284             QRectF rect = QDeclarativeStringConverters::rectFFromString(string, &ok);
       
   285             if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected"));
       
   286             }
       
   287             break;
       
   288         case QVariant::Bool:
       
   289             {
       
   290             if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected"));
       
   291             }
       
   292             break;
       
   293         case QVariant::Vector3D:
       
   294             {
       
   295             bool ok;
       
   296             QDeclarativeStringConverters::vector3DFromString(string, &ok);
       
   297             if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected"));
       
   298             }
       
   299             break;
       
   300         default:
       
   301             {
       
   302             int t = prop.userType();
       
   303             QDeclarativeMetaType::StringConverter converter =
       
   304                 QDeclarativeMetaType::customStringConverter(t);
       
   305             if (!converter)
       
   306                 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName(prop.type()))));
       
   307             }
       
   308             break;
       
   309     }
       
   310     return true;
       
   311 }
       
   312 
       
   313 /*!
       
   314     Generate a store instruction for assigning literal \a v to property \a prop.
       
   315 
       
   316     Any literal assignment that is approved in testLiteralAssignment() must have
       
   317     a corresponding action in this method.
       
   318 */
       
   319 void QDeclarativeCompiler::genLiteralAssignment(const QMetaProperty &prop,
       
   320                                        QDeclarativeParser::Value *v)
       
   321 {
       
   322     QString string = v->value.asString();
       
   323 
       
   324     QDeclarativeInstruction instr;
       
   325     instr.line = v->location.start.line;
       
   326     if (prop.isEnumType()) {
       
   327         int value;
       
   328         if (prop.isFlagType()) {
       
   329             value = prop.enumerator().keysToValue(string.toUtf8().constData());
       
   330         } else
       
   331             value = prop.enumerator().keyToValue(string.toUtf8().constData());
       
   332 
       
   333         instr.type = QDeclarativeInstruction::StoreInteger;
       
   334         instr.storeInteger.propertyIndex = prop.propertyIndex();
       
   335         instr.storeInteger.value = value;
       
   336         output->bytecode << instr;
       
   337         return;
       
   338     }
       
   339 
       
   340     int type = prop.userType();
       
   341     switch(type) {
       
   342         case -1:
       
   343             {
       
   344             if (v->value.isNumber()) {
       
   345                 double n = v->value.asNumber();
       
   346                 if (double(int(n)) == n) {
       
   347                     instr.type = QDeclarativeInstruction::StoreVariantInteger;
       
   348                     instr.storeInteger.propertyIndex = prop.propertyIndex();
       
   349                     instr.storeInteger.value = int(n);
       
   350                 } else {
       
   351                     instr.type = QDeclarativeInstruction::StoreVariantDouble;
       
   352                     instr.storeDouble.propertyIndex = prop.propertyIndex();
       
   353                     instr.storeDouble.value = n;
       
   354                 }
       
   355             } else if(v->value.isBoolean()) {
       
   356                 instr.type = QDeclarativeInstruction::StoreVariantBool;
       
   357                 instr.storeBool.propertyIndex = prop.propertyIndex();
       
   358                 instr.storeBool.value = v->value.asBoolean();
       
   359             } else {
       
   360                 instr.type = QDeclarativeInstruction::StoreVariant;
       
   361                 instr.storeString.propertyIndex = prop.propertyIndex();
       
   362                 instr.storeString.value = output->indexForString(string);
       
   363             }
       
   364             }
       
   365             break;
       
   366         case QVariant::String:
       
   367             {
       
   368             instr.type = QDeclarativeInstruction::StoreString;
       
   369             instr.storeString.propertyIndex = prop.propertyIndex();
       
   370             instr.storeString.value = output->indexForString(string);
       
   371             }
       
   372             break;
       
   373         case QVariant::Url:
       
   374             {
       
   375             instr.type = QDeclarativeInstruction::StoreUrl;
       
   376             QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
       
   377             instr.storeUrl.propertyIndex = prop.propertyIndex();
       
   378             instr.storeUrl.value = output->indexForUrl(u);
       
   379             }
       
   380             break;
       
   381         case QVariant::UInt:
       
   382             {
       
   383             instr.type = QDeclarativeInstruction::StoreInteger;
       
   384             instr.storeInteger.propertyIndex = prop.propertyIndex();
       
   385             instr.storeInteger.value = uint(v->value.asNumber());
       
   386             }
       
   387             break;
       
   388         case QVariant::Int:
       
   389             {
       
   390             instr.type = QDeclarativeInstruction::StoreInteger;
       
   391             instr.storeInteger.propertyIndex = prop.propertyIndex();
       
   392             instr.storeInteger.value = int(v->value.asNumber());
       
   393             }
       
   394             break;
       
   395         case QMetaType::Float:
       
   396             {
       
   397             instr.type = QDeclarativeInstruction::StoreFloat;
       
   398             instr.storeFloat.propertyIndex = prop.propertyIndex();
       
   399             instr.storeFloat.value = float(v->value.asNumber());
       
   400             }
       
   401             break;
       
   402         case QVariant::Double:
       
   403             {
       
   404             instr.type = QDeclarativeInstruction::StoreDouble;
       
   405             instr.storeDouble.propertyIndex = prop.propertyIndex();
       
   406             instr.storeDouble.value = v->value.asNumber();
       
   407             }
       
   408             break;
       
   409         case QVariant::Color:
       
   410             {
       
   411             QColor c = QDeclarativeStringConverters::colorFromString(string);
       
   412             instr.type = QDeclarativeInstruction::StoreColor;
       
   413             instr.storeColor.propertyIndex = prop.propertyIndex();
       
   414             instr.storeColor.value = c.rgba();
       
   415             }
       
   416             break;
       
   417         case QVariant::Date:
       
   418             {
       
   419             QDate d = QDeclarativeStringConverters::dateFromString(string);
       
   420             instr.type = QDeclarativeInstruction::StoreDate;
       
   421             instr.storeDate.propertyIndex = prop.propertyIndex();
       
   422             instr.storeDate.value = d.toJulianDay();
       
   423             }
       
   424             break;
       
   425         case QVariant::Time:
       
   426             {
       
   427             QTime time = QDeclarativeStringConverters::timeFromString(string);
       
   428             int data[] = { time.hour(), time.minute(),
       
   429                            time.second(), time.msec() };
       
   430             int index = output->indexForInt(data, 4);
       
   431             instr.type = QDeclarativeInstruction::StoreTime;
       
   432             instr.storeTime.propertyIndex = prop.propertyIndex();
       
   433             instr.storeTime.valueIndex = index;
       
   434             }
       
   435             break;
       
   436         case QVariant::DateTime:
       
   437             {
       
   438             QDateTime dateTime = QDeclarativeStringConverters::dateTimeFromString(string);
       
   439             int data[] = { dateTime.date().toJulianDay(),
       
   440                            dateTime.time().hour(),
       
   441                            dateTime.time().minute(),
       
   442                            dateTime.time().second(),
       
   443                            dateTime.time().msec() };
       
   444             int index = output->indexForInt(data, 5);
       
   445             instr.type = QDeclarativeInstruction::StoreDateTime;
       
   446             instr.storeDateTime.propertyIndex = prop.propertyIndex();
       
   447             instr.storeDateTime.valueIndex = index;
       
   448             }
       
   449             break;
       
   450         case QVariant::Point:
       
   451         case QVariant::PointF:
       
   452             {
       
   453             bool ok;
       
   454             QPointF point =
       
   455                 QDeclarativeStringConverters::pointFFromString(string, &ok);
       
   456             float data[] = { float(point.x()), float(point.y()) };
       
   457             int index = output->indexForFloat(data, 2);
       
   458             if (type == QVariant::PointF)
       
   459                 instr.type = QDeclarativeInstruction::StorePointF;
       
   460             else
       
   461                 instr.type = QDeclarativeInstruction::StorePoint;
       
   462             instr.storeRealPair.propertyIndex = prop.propertyIndex();
       
   463             instr.storeRealPair.valueIndex = index;
       
   464             }
       
   465             break;
       
   466         case QVariant::Size:
       
   467         case QVariant::SizeF:
       
   468             {
       
   469             bool ok;
       
   470             QSizeF size = QDeclarativeStringConverters::sizeFFromString(string, &ok);
       
   471             float data[] = { float(size.width()), float(size.height()) };
       
   472             int index = output->indexForFloat(data, 2);
       
   473             if (type == QVariant::SizeF)
       
   474                 instr.type = QDeclarativeInstruction::StoreSizeF;
       
   475             else
       
   476                 instr.type = QDeclarativeInstruction::StoreSize;
       
   477             instr.storeRealPair.propertyIndex = prop.propertyIndex();
       
   478             instr.storeRealPair.valueIndex = index;
       
   479             }
       
   480             break;
       
   481         case QVariant::Rect:
       
   482         case QVariant::RectF:
       
   483             {
       
   484             bool ok;
       
   485             QRectF rect = QDeclarativeStringConverters::rectFFromString(string, &ok);
       
   486             float data[] = { float(rect.x()), float(rect.y()),
       
   487                              float(rect.width()), float(rect.height()) };
       
   488             int index = output->indexForFloat(data, 4);
       
   489             if (type == QVariant::RectF)
       
   490                 instr.type = QDeclarativeInstruction::StoreRectF;
       
   491             else
       
   492                 instr.type = QDeclarativeInstruction::StoreRect;
       
   493             instr.storeRect.propertyIndex = prop.propertyIndex();
       
   494             instr.storeRect.valueIndex = index;
       
   495             }
       
   496             break;
       
   497         case QVariant::Bool:
       
   498             {
       
   499             bool b = v->value.asBoolean();
       
   500             instr.type = QDeclarativeInstruction::StoreBool;
       
   501             instr.storeBool.propertyIndex = prop.propertyIndex();
       
   502             instr.storeBool.value = b;
       
   503             }
       
   504             break;
       
   505         case QVariant::Vector3D:
       
   506             {
       
   507             bool ok;
       
   508             QVector3D vector =
       
   509                 QDeclarativeStringConverters::vector3DFromString(string, &ok);
       
   510             float data[] = { float(vector.x()), float(vector.y()), float(vector.z()) };
       
   511             int index = output->indexForFloat(data, 3);
       
   512             instr.type = QDeclarativeInstruction::StoreVector3D;
       
   513             instr.storeRealPair.propertyIndex = prop.propertyIndex();
       
   514             instr.storeRealPair.valueIndex = index;
       
   515             }
       
   516             break;
       
   517         default:
       
   518             {
       
   519             int t = prop.userType();
       
   520             int index = output->customTypeData.count();
       
   521             instr.type = QDeclarativeInstruction::AssignCustomType;
       
   522             instr.assignCustomType.propertyIndex = prop.propertyIndex();
       
   523             instr.assignCustomType.valueIndex = index;
       
   524 
       
   525             QDeclarativeCompiledData::CustomTypeData data;
       
   526             data.index = output->indexForString(string);
       
   527             data.type = t;
       
   528             output->customTypeData << data;
       
   529             }
       
   530             break;
       
   531     }
       
   532     output->bytecode << instr;
       
   533 }
       
   534 
       
   535 /*!
       
   536     Resets data by clearing the lists that the QDeclarativeCompiler modifies.
       
   537 */
       
   538 void QDeclarativeCompiler::reset(QDeclarativeCompiledData *data)
       
   539 {
       
   540     data->types.clear();
       
   541     data->primitives.clear();
       
   542     data->floatData.clear();
       
   543     data->intData.clear();
       
   544     data->customTypeData.clear();
       
   545     data->datas.clear();
       
   546     data->bytecode.clear();
       
   547 }
       
   548 
       
   549 /*!
       
   550     Compile \a unit, and store the output in \a out.  \a engine is the QDeclarativeEngine
       
   551     with which the QDeclarativeCompiledData will be associated.
       
   552 
       
   553     Returns true on success, false on failure.  On failure, the compile errors
       
   554     are available from errors().
       
   555 
       
   556     If the environment variant QML_COMPILER_DUMP is set
       
   557     (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
       
   558     on a successful compiler.
       
   559 */
       
   560 bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine,
       
   561                                    QDeclarativeCompositeTypeData *unit,
       
   562                                    QDeclarativeCompiledData *out)
       
   563 {
       
   564     exceptions.clear();
       
   565 
       
   566     Q_ASSERT(out);
       
   567     reset(out);
       
   568 
       
   569     output = out;
       
   570 
       
   571     // Compile types
       
   572     for (int ii = 0; ii < unit->types.count(); ++ii) {
       
   573         QDeclarativeCompositeTypeData::TypeReference &tref = unit->types[ii];
       
   574         QDeclarativeCompiledData::TypeReference ref;
       
   575         QDeclarativeScriptParser::TypeReference *parserRef = unit->data.referencedTypes().at(ii);
       
   576         if (tref.type) {
       
   577             ref.type = tref.type;
       
   578             if (!ref.type->isCreatable()) {
       
   579                 QString err = ref.type->noCreationReason();
       
   580                 if (err.isEmpty())
       
   581                     err = tr( "Element is not creatable.");
       
   582                 COMPILE_EXCEPTION(parserRef->refObjects.first(), err);
       
   583             }
       
   584         } else if (tref.unit) {
       
   585             ref.component = tref.unit->toComponent(engine);
       
   586 
       
   587             if (ref.component->isError()) {
       
   588                 QDeclarativeError error;
       
   589                 error.setUrl(output->url);
       
   590                 error.setDescription(QLatin1String("Unable to create type ") +
       
   591                                      parserRef->name);
       
   592                 if (!parserRef->refObjects.isEmpty()) {
       
   593                     QDeclarativeParser::Object *parserObject = parserRef->refObjects.first();
       
   594                     error.setLine(parserObject->location.start.line);
       
   595                     error.setColumn(parserObject->location.start.column);
       
   596                 }
       
   597 
       
   598                 exceptions << error;
       
   599                 exceptions << ref.component->errors();
       
   600                 reset(out);
       
   601                 return false;
       
   602             }
       
   603             ref.ref = tref.unit;
       
   604             ref.ref->addref();
       
   605         }
       
   606         ref.className = parserRef->name.toUtf8();
       
   607         out->types << ref;
       
   608     }
       
   609 
       
   610     Object *root = unit->data.tree();
       
   611     Q_ASSERT(root);
       
   612 
       
   613     this->engine = engine;
       
   614     this->enginePrivate = QDeclarativeEnginePrivate::get(engine);
       
   615     this->unit = unit;
       
   616     this->unitRoot = root;
       
   617     compileTree(root);
       
   618 
       
   619     if (!isError()) {
       
   620         if (compilerDump())
       
   621             out->dumpInstructions();
       
   622         if (compilerStatDump())
       
   623             dumpStats();
       
   624     } else {
       
   625         reset(out);
       
   626     }
       
   627 
       
   628     compileState = ComponentCompileState();
       
   629     savedCompileStates.clear();
       
   630     output = 0;
       
   631     this->engine = 0;
       
   632     this->enginePrivate = 0;
       
   633     this->unit = 0;
       
   634     this->unitRoot = 0;
       
   635 
       
   636     return !isError();
       
   637 }
       
   638 
       
   639 void QDeclarativeCompiler::compileTree(Object *tree)
       
   640 {
       
   641     compileState.root = tree;
       
   642     componentStat.lineNumber = tree->location.start.line;
       
   643 
       
   644     if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
       
   645         return;
       
   646 
       
   647     QDeclarativeInstruction init;
       
   648     init.type = QDeclarativeInstruction::Init;
       
   649     init.line = 0;
       
   650     init.init.bindingsSize = compileState.bindings.count();
       
   651     init.init.parserStatusSize = compileState.parserStatusCount;
       
   652     init.init.contextCache = genContextCache();
       
   653     if (compileState.compiledBindingData.isEmpty())
       
   654         init.init.compiledBinding = -1;
       
   655     else
       
   656         init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData);
       
   657     output->bytecode << init;
       
   658 
       
   659     // Build global import scripts
       
   660     QHash<QString, Object::ScriptBlock> importedScripts;
       
   661     QStringList importedScriptIndexes;
       
   662 
       
   663     for (int ii = 0; ii < unit->scripts.count(); ++ii) {
       
   664         QString scriptCode = QString::fromUtf8(unit->scripts.at(ii).resource->data);
       
   665         Object::ScriptBlock::Pragmas pragmas = QDeclarativeScriptParser::extractPragmas(scriptCode);
       
   666 
       
   667         if (!scriptCode.isEmpty()) {
       
   668             Object::ScriptBlock &scriptBlock = importedScripts[unit->scripts.at(ii).qualifier];
       
   669 
       
   670             scriptBlock.codes.append(scriptCode);
       
   671             scriptBlock.lineNumbers.append(1);
       
   672             scriptBlock.files.append(unit->scripts.at(ii).resource->url);
       
   673             scriptBlock.pragmas.append(pragmas);
       
   674         }
       
   675     }
       
   676 
       
   677     for (QHash<QString, Object::ScriptBlock>::Iterator iter = importedScripts.begin(); 
       
   678          iter != importedScripts.end(); ++iter) {
       
   679 
       
   680         importedScriptIndexes.append(iter.key());
       
   681 
       
   682         QDeclarativeInstruction import;
       
   683         import.type = QDeclarativeInstruction::StoreImportedScript;
       
   684         import.line = 0;
       
   685         import.storeScript.value = output->scripts.count();
       
   686         output->scripts << *iter;
       
   687         output->bytecode << import;
       
   688     }
       
   689 
       
   690     genObject(tree);
       
   691 
       
   692     QDeclarativeInstruction def;
       
   693     init.line = 0;
       
   694     def.type = QDeclarativeInstruction::SetDefault;
       
   695     output->bytecode << def;
       
   696 
       
   697     output->importCache = new QDeclarativeTypeNameCache(engine);
       
   698 
       
   699     for (int ii = 0; ii < importedScriptIndexes.count(); ++ii) 
       
   700         output->importCache->add(importedScriptIndexes.at(ii), ii);
       
   701 
       
   702     unit->imports.cache(output->importCache, engine);
       
   703 
       
   704     Q_ASSERT(tree->metatype);
       
   705 
       
   706     if (tree->metadata.isEmpty()) {
       
   707         output->root = tree->metatype;
       
   708     } else {
       
   709         static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
       
   710         output->root = &output->rootData;
       
   711     }
       
   712     if (!tree->metadata.isEmpty()) 
       
   713         enginePrivate->registerCompositeType(output);
       
   714 }
       
   715 
       
   716 static bool ValuePtrLessThan(const Value *t1, const Value *t2) 
       
   717 {
       
   718     return t1->location.start.line < t2->location.start.line ||
       
   719            (t1->location.start.line == t2->location.start.line &&
       
   720             t1->location.start.column < t2->location.start.column);
       
   721 }
       
   722 
       
   723 bool QDeclarativeCompiler::buildObject(Object *obj, const BindingContext &ctxt)
       
   724 {
       
   725     componentStat.objects++;
       
   726 
       
   727     Q_ASSERT (obj->type != -1);
       
   728     const QDeclarativeCompiledData::TypeReference &tr =
       
   729         output->types.at(obj->type);
       
   730     obj->metatype = tr.metaObject();
       
   731 
       
   732     if (tr.component)
       
   733         obj->url = tr.component->url();
       
   734     if (tr.type)
       
   735         obj->typeName = tr.type->qmlTypeName();
       
   736     obj->className = tr.className;
       
   737 
       
   738     // This object is a "Component" element
       
   739     if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
       
   740         COMPILE_CHECK(buildComponent(obj, ctxt));
       
   741         return true;
       
   742     } 
       
   743 
       
   744     // Object instantiations reset the binding context
       
   745     BindingContext objCtxt(obj);
       
   746 
       
   747     // Create the synthesized meta object, ignoring aliases
       
   748     COMPILE_CHECK(checkDynamicMeta(obj)); 
       
   749     COMPILE_CHECK(mergeDynamicMetaProperties(obj));
       
   750     COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
       
   751 
       
   752     // Find the native type and check for the QDeclarativeParserStatus interface
       
   753     QDeclarativeType *type = toQmlType(obj);
       
   754     Q_ASSERT(type);
       
   755     obj->parserStatusCast = type->parserStatusCast();
       
   756     if (obj->parserStatusCast != -1)
       
   757         compileState.parserStatusCount++;
       
   758 
       
   759     // Check if this is a custom parser type.  Custom parser types allow
       
   760     // assignments to non-existent properties.  These assignments are then
       
   761     // compiled by the type.
       
   762     bool isCustomParser = output->types.at(obj->type).type &&
       
   763                           output->types.at(obj->type).type->customParser() != 0;
       
   764     QList<QDeclarativeCustomParserProperty> customProps;
       
   765 
       
   766     // Fetch the list of deferred properties
       
   767     QStringList deferredList = deferredProperties(obj);
       
   768 
       
   769     // Must do id property first.  This is to ensure that the id given to any
       
   770     // id reference created matches the order in which the objects are
       
   771     // instantiated
       
   772     foreach(Property *prop, obj->properties) {
       
   773         if (prop->name == "id") {
       
   774             COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
       
   775             break;
       
   776         }
       
   777     }
       
   778 
       
   779     // Merge 
       
   780     Property *defaultProperty = 0;
       
   781     Property *skipProperty = 0;
       
   782     if (obj->defaultProperty) {
       
   783         const QMetaObject *metaObject = obj->metaObject();
       
   784         Q_ASSERT(metaObject);
       
   785         QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
       
   786         if (p.name()) {
       
   787             Property *explicitProperty = obj->getProperty(p.name(), false);
       
   788             if (explicitProperty && !explicitProperty->value) {
       
   789                 skipProperty = explicitProperty;
       
   790 
       
   791                 defaultProperty = new Property;
       
   792                 defaultProperty->parent = obj;
       
   793                 defaultProperty->isDefault = true;
       
   794                 defaultProperty->location = obj->defaultProperty->location;
       
   795                 defaultProperty->listValueRange = obj->defaultProperty->listValueRange;
       
   796                 defaultProperty->listCommaPositions = obj->defaultProperty->listCommaPositions;
       
   797 
       
   798                 defaultProperty->values  = obj->defaultProperty->values;
       
   799                 defaultProperty->values += explicitProperty->values;
       
   800                 foreach(Value *value, defaultProperty->values)
       
   801                     value->addref();
       
   802                 qSort(defaultProperty->values.begin(), defaultProperty->values.end(), ValuePtrLessThan);
       
   803 
       
   804             } else {
       
   805                 defaultProperty = obj->defaultProperty;
       
   806                 defaultProperty->addref();
       
   807             }
       
   808         } else {
       
   809             defaultProperty = obj->defaultProperty;
       
   810             defaultProperty->addref();
       
   811         }
       
   812     }
       
   813 
       
   814     // Build all explicit properties specified
       
   815     foreach(Property *prop, obj->properties) {
       
   816 
       
   817         if (prop == skipProperty)
       
   818             continue;
       
   819         if (prop->name == "id")
       
   820             continue;
       
   821 
       
   822         bool canDefer = false;
       
   823         if (isCustomParser) {
       
   824             if (doesPropertyExist(prop, obj)) {
       
   825                 int ids = compileState.ids.count();
       
   826                 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
       
   827                 canDefer = ids == compileState.ids.count();
       
   828             } else {
       
   829                 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
       
   830             }
       
   831         } else {
       
   832             if (isSignalPropertyName(prop->name)) {
       
   833                 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
       
   834             } else {
       
   835                 int ids = compileState.ids.count();
       
   836                 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
       
   837                 canDefer = ids == compileState.ids.count();
       
   838             }
       
   839         }
       
   840 
       
   841         if (canDefer && !deferredList.isEmpty() &&
       
   842             deferredList.contains(QString::fromUtf8(prop->name)))
       
   843             prop->isDeferred = true;
       
   844 
       
   845     }
       
   846 
       
   847     // Build the default property
       
   848     if (defaultProperty)  {
       
   849         Property *prop = defaultProperty;
       
   850 
       
   851         bool canDefer = false;
       
   852         if (isCustomParser) {
       
   853             if (doesPropertyExist(prop, obj)) {
       
   854                 int ids = compileState.ids.count();
       
   855                 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
       
   856                 canDefer = ids == compileState.ids.count();
       
   857             } else {
       
   858                 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
       
   859             }
       
   860         } else {
       
   861             int ids = compileState.ids.count();
       
   862             COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
       
   863             canDefer = ids == compileState.ids.count();
       
   864         }
       
   865 
       
   866         if (canDefer && !deferredList.isEmpty() &&
       
   867             deferredList.contains(QString::fromUtf8(prop->name)))
       
   868             prop->isDeferred = true;
       
   869     }
       
   870 
       
   871     if (defaultProperty) 
       
   872         defaultProperty->release();
       
   873 
       
   874     // Compile custom parser parts
       
   875     if (isCustomParser/* && !customProps.isEmpty()*/) {
       
   876         QDeclarativeCustomParser *cp = output->types.at(obj->type).type->customParser();
       
   877         cp->clearErrors();
       
   878         cp->compiler = this;
       
   879         cp->object = obj;
       
   880         obj->custom = cp->compile(customProps);
       
   881         cp->compiler = 0;
       
   882         cp->object = 0;
       
   883         foreach (QDeclarativeError err, cp->errors()) {
       
   884             err.setUrl(output->url);
       
   885             exceptions << err;
       
   886         }
       
   887     }
       
   888 
       
   889     return true;
       
   890 }
       
   891 
       
   892 void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj)
       
   893 {
       
   894     const QDeclarativeCompiledData::TypeReference &tr =
       
   895         output->types.at(obj->type);
       
   896     if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
       
   897         genComponent(obj);
       
   898         return;
       
   899     }
       
   900 
       
   901     // Create the object
       
   902     if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
       
   903         !output->types.at(obj->type).type->isExtendedType() && obj != compileState.root) {
       
   904 
       
   905         QDeclarativeInstruction create;
       
   906         create.type = QDeclarativeInstruction::CreateSimpleObject;
       
   907         create.line = obj->location.start.line;
       
   908         create.createSimple.create = output->types.at(obj->type).type->createFunction();
       
   909         create.createSimple.typeSize = output->types.at(obj->type).type->createSize();
       
   910         create.createSimple.column = obj->location.start.column;
       
   911         output->bytecode << create;
       
   912 
       
   913     } else {
       
   914 
       
   915         QDeclarativeInstruction create;
       
   916         create.type = QDeclarativeInstruction::CreateObject;
       
   917         create.line = obj->location.start.line;
       
   918         create.create.column = obj->location.start.column;
       
   919         create.create.data = -1;
       
   920         if (!obj->custom.isEmpty())
       
   921             create.create.data = output->indexForByteArray(obj->custom);
       
   922         create.create.type = obj->type;
       
   923         if (!output->types.at(create.create.type).type && 
       
   924             !obj->bindingBitmask.isEmpty()) {
       
   925             Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
       
   926             create.create.bindingBits = 
       
   927                 output->indexForByteArray(obj->bindingBitmask);
       
   928         } else {
       
   929             create.create.bindingBits = -1;
       
   930         }
       
   931         output->bytecode << create;
       
   932 
       
   933     }
       
   934 
       
   935     // Setup the synthesized meta object if necessary
       
   936     if (!obj->metadata.isEmpty()) {
       
   937         QDeclarativeInstruction meta;
       
   938         meta.type = QDeclarativeInstruction::StoreMetaObject;
       
   939         meta.line = 0;
       
   940         meta.storeMeta.data = output->indexForByteArray(obj->metadata);
       
   941         meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata);
       
   942         meta.storeMeta.propertyCache = output->propertyCaches.count();
       
   943         // ### Surely the creation of this property cache could be more efficient
       
   944         QDeclarativePropertyCache *propertyCache = 0;
       
   945         if (tr.component)
       
   946             propertyCache = QDeclarativeComponentPrivate::get(tr.component)->cc->rootPropertyCache->copy();
       
   947         else
       
   948             propertyCache = enginePrivate->cache(obj->metaObject()->superClass())->copy();
       
   949 
       
   950         propertyCache->append(engine, obj->metaObject(), QDeclarativePropertyCache::Data::NoFlags,
       
   951                               QDeclarativePropertyCache::Data::IsVMEFunction);
       
   952 
       
   953         if (obj == unitRoot) {
       
   954             propertyCache->addref();
       
   955             output->rootPropertyCache = propertyCache;
       
   956         }
       
   957 
       
   958         output->propertyCaches << propertyCache;
       
   959         output->bytecode << meta;
       
   960     } else if (obj == unitRoot) {
       
   961         if (tr.component)
       
   962             output->rootPropertyCache = QDeclarativeComponentPrivate::get(tr.component)->cc->rootPropertyCache;
       
   963         else
       
   964             output->rootPropertyCache = enginePrivate->cache(obj->metaObject());
       
   965 
       
   966         output->rootPropertyCache->addref();
       
   967     }
       
   968 
       
   969     // Set the object id
       
   970     if (!obj->id.isEmpty()) {
       
   971         QDeclarativeInstruction id;
       
   972         id.type = QDeclarativeInstruction::SetId;
       
   973         id.line = 0;
       
   974         id.setId.value = output->indexForString(obj->id);
       
   975         id.setId.index = obj->idIndex;
       
   976         output->bytecode << id;
       
   977     }
       
   978 
       
   979     // Begin the class
       
   980     if (obj->parserStatusCast != -1) {
       
   981         QDeclarativeInstruction begin;
       
   982         begin.type = QDeclarativeInstruction::BeginObject;
       
   983         begin.begin.castValue = obj->parserStatusCast;
       
   984         begin.line = obj->location.start.line;
       
   985         output->bytecode << begin;
       
   986     }
       
   987 
       
   988     genObjectBody(obj);
       
   989 }
       
   990 
       
   991 void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj)
       
   992 {
       
   993     typedef QPair<Property *, int> PropPair;
       
   994     foreach(const PropPair &prop, obj->scriptStringProperties) {
       
   995         QDeclarativeInstruction ss;
       
   996         ss.type = QDeclarativeInstruction::StoreScriptString;
       
   997         ss.storeScriptString.propertyIndex = prop.first->index;
       
   998         ss.storeScriptString.value = 
       
   999             output->indexForString(prop.first->values.at(0)->value.asScript());
       
  1000         ss.storeScriptString.scope = prop.second;
       
  1001         output->bytecode << ss;
       
  1002     }
       
  1003 
       
  1004     bool seenDefer = false;
       
  1005     foreach(Property *prop, obj->valueProperties) {
       
  1006         if (prop->isDeferred) {
       
  1007             seenDefer = true;
       
  1008             continue;
       
  1009         }
       
  1010         genValueProperty(prop, obj);
       
  1011     }
       
  1012     if (seenDefer) {
       
  1013         QDeclarativeInstruction defer;
       
  1014         defer.type = QDeclarativeInstruction::Defer;
       
  1015         defer.line = 0;
       
  1016         defer.defer.deferCount = 0;
       
  1017         int deferIdx = output->bytecode.count();
       
  1018         output->bytecode << defer;
       
  1019 
       
  1020         QDeclarativeInstruction init;
       
  1021         init.type = QDeclarativeInstruction::Init;
       
  1022         init.init.bindingsSize = compileState.bindings.count(); // XXX - bigger than necessary
       
  1023         init.init.parserStatusSize = compileState.parserStatusCount; // XXX - bigger than necessary
       
  1024         init.init.contextCache = -1;
       
  1025         init.init.compiledBinding = -1;
       
  1026         output->bytecode << init;
       
  1027 
       
  1028         foreach(Property *prop, obj->valueProperties) {
       
  1029             if (!prop->isDeferred)
       
  1030                 continue;
       
  1031             genValueProperty(prop, obj);
       
  1032         }
       
  1033 
       
  1034         output->bytecode[deferIdx].defer.deferCount =
       
  1035             output->bytecode.count() - deferIdx - 1;
       
  1036     }
       
  1037 
       
  1038     foreach(Property *prop, obj->signalProperties) {
       
  1039 
       
  1040         QDeclarativeParser::Value *v = prop->values.at(0);
       
  1041 
       
  1042         if (v->type == Value::SignalObject) {
       
  1043 
       
  1044             genObject(v->object);
       
  1045 
       
  1046             QDeclarativeInstruction assign;
       
  1047             assign.type = QDeclarativeInstruction::AssignSignalObject;
       
  1048             assign.line = v->location.start.line;
       
  1049             assign.assignSignalObject.signal =
       
  1050                 output->indexForByteArray(prop->name);
       
  1051             output->bytecode << assign;
       
  1052 
       
  1053         } else if (v->type == Value::SignalExpression) {
       
  1054 
       
  1055             BindingContext ctxt = compileState.signalExpressions.value(v);
       
  1056 
       
  1057             QDeclarativeInstruction store;
       
  1058             store.type = QDeclarativeInstruction::StoreSignal;
       
  1059             store.line = v->location.start.line;
       
  1060             store.storeSignal.signalIndex = prop->index;
       
  1061             store.storeSignal.value =
       
  1062                 output->indexForString(v->value.asScript().trimmed());
       
  1063             store.storeSignal.context = ctxt.stack;
       
  1064             output->bytecode << store;
       
  1065 
       
  1066         }
       
  1067 
       
  1068     }
       
  1069 
       
  1070     foreach(Property *prop, obj->attachedProperties) {
       
  1071         QDeclarativeInstruction fetch;
       
  1072         fetch.type = QDeclarativeInstruction::FetchAttached;
       
  1073         fetch.line = prop->location.start.line;
       
  1074         fetch.fetchAttached.id = prop->index;
       
  1075         output->bytecode << fetch;
       
  1076 
       
  1077         genObjectBody(prop->value);
       
  1078 
       
  1079         QDeclarativeInstruction pop;
       
  1080         pop.type = QDeclarativeInstruction::PopFetchedObject;
       
  1081         pop.line = prop->location.start.line;
       
  1082         output->bytecode << pop;
       
  1083     }
       
  1084 
       
  1085     foreach(Property *prop, obj->groupedProperties) {
       
  1086         QDeclarativeInstruction fetch;
       
  1087         fetch.type = QDeclarativeInstruction::FetchObject;
       
  1088         fetch.fetch.property = prop->index;
       
  1089         fetch.line = prop->location.start.line;
       
  1090         output->bytecode << fetch;
       
  1091 
       
  1092         if (!prop->value->metadata.isEmpty()) {
       
  1093             QDeclarativeInstruction meta;
       
  1094             meta.type = QDeclarativeInstruction::StoreMetaObject;
       
  1095             meta.line = 0;
       
  1096             meta.storeMeta.data = output->indexForByteArray(prop->value->metadata);
       
  1097             meta.storeMeta.aliasData = output->indexForByteArray(prop->value->synthdata);
       
  1098             meta.storeMeta.propertyCache = output->propertyCaches.count();
       
  1099             // ### Surely the creation of this property cache could be more efficient
       
  1100             QDeclarativePropertyCache *propertyCache =
       
  1101                 enginePrivate->cache(prop->value->metaObject()->superClass())->copy();
       
  1102             propertyCache->append(engine, prop->value->metaObject(), QDeclarativePropertyCache::Data::NoFlags,
       
  1103                                   QDeclarativePropertyCache::Data::IsVMEFunction);
       
  1104 
       
  1105             output->propertyCaches << propertyCache;
       
  1106             output->bytecode << meta;
       
  1107         }
       
  1108 
       
  1109         genObjectBody(prop->value);
       
  1110 
       
  1111         QDeclarativeInstruction pop;
       
  1112         pop.type = QDeclarativeInstruction::PopFetchedObject;
       
  1113         pop.line = prop->location.start.line;
       
  1114         output->bytecode << pop;
       
  1115     }
       
  1116 
       
  1117     foreach(Property *prop, obj->valueTypeProperties) {
       
  1118         QDeclarativeInstruction fetch;
       
  1119         fetch.type = QDeclarativeInstruction::FetchValueType;
       
  1120         fetch.fetchValue.property = prop->index;
       
  1121         fetch.fetchValue.type = prop->type;
       
  1122         fetch.line = prop->location.start.line;
       
  1123 
       
  1124         output->bytecode << fetch;
       
  1125 
       
  1126         foreach(Property *vprop, prop->value->valueProperties) {
       
  1127             genPropertyAssignment(vprop, prop->value, prop);
       
  1128         }
       
  1129 
       
  1130         QDeclarativeInstruction pop;
       
  1131         pop.type = QDeclarativeInstruction::PopValueType;
       
  1132         pop.fetchValue.property = prop->index;
       
  1133         pop.fetchValue.type = prop->type;
       
  1134         pop.line = prop->location.start.line;
       
  1135         output->bytecode << pop;
       
  1136     }
       
  1137 }
       
  1138 
       
  1139 void QDeclarativeCompiler::genComponent(QDeclarativeParser::Object *obj)
       
  1140 {
       
  1141     QDeclarativeParser::Object *root = obj->defaultProperty->values.at(0)->object;
       
  1142     Q_ASSERT(root);
       
  1143 
       
  1144     QDeclarativeInstruction create;
       
  1145     create.type = QDeclarativeInstruction::CreateComponent;
       
  1146     create.line = root->location.start.line;
       
  1147     create.createComponent.column = root->location.start.column;
       
  1148     create.createComponent.endLine = root->location.end.line;
       
  1149     output->bytecode << create;
       
  1150     int count = output->bytecode.count();
       
  1151 
       
  1152     ComponentCompileState oldCompileState = compileState;
       
  1153     compileState = componentState(root);
       
  1154 
       
  1155     QDeclarativeInstruction init;
       
  1156     init.type = QDeclarativeInstruction::Init;
       
  1157     init.init.bindingsSize = compileState.bindings.count();
       
  1158     init.init.parserStatusSize = compileState.parserStatusCount;
       
  1159     init.init.contextCache = genContextCache();
       
  1160     if (compileState.compiledBindingData.isEmpty())
       
  1161         init.init.compiledBinding = -1;
       
  1162     else
       
  1163         init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData);
       
  1164     init.line = obj->location.start.line;
       
  1165     output->bytecode << init;
       
  1166 
       
  1167     genObject(root);
       
  1168 
       
  1169     QDeclarativeInstruction def;
       
  1170     init.line = 0;
       
  1171     def.type = QDeclarativeInstruction::SetDefault;
       
  1172     output->bytecode << def;
       
  1173 
       
  1174     output->bytecode[count - 1].createComponent.count =
       
  1175         output->bytecode.count() - count;
       
  1176 
       
  1177     compileState = oldCompileState;
       
  1178 
       
  1179     if (!obj->id.isEmpty()) {
       
  1180         QDeclarativeInstruction id;
       
  1181         id.type = QDeclarativeInstruction::SetId;
       
  1182         id.line = 0;
       
  1183         id.setId.value = output->indexForString(obj->id);
       
  1184         id.setId.index = obj->idIndex;
       
  1185         output->bytecode << id;
       
  1186     }
       
  1187 }
       
  1188 
       
  1189 bool QDeclarativeCompiler::buildComponent(QDeclarativeParser::Object *obj,
       
  1190                                  const BindingContext &ctxt)
       
  1191 {
       
  1192     // The special "Component" element can only have the id property and a
       
  1193     // default property, that actually defines the component's tree
       
  1194 
       
  1195     // Find, check and set the "id" property (if any)
       
  1196     Property *idProp = 0;
       
  1197     if (obj->properties.count() > 1 ||
       
  1198        (obj->properties.count() == 1 && obj->properties.begin().key() != "id"))
       
  1199         COMPILE_EXCEPTION(*obj->properties.begin(), tr("Component elements may not contain properties other than id"));
       
  1200        
       
  1201     if (obj->properties.count())
       
  1202         idProp = *obj->properties.begin();
       
  1203 
       
  1204     if (idProp) {
       
  1205        if (idProp->value || idProp->values.count() > 1 || idProp->values.at(0)->object) 
       
  1206            COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
       
  1207        COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
       
  1208 
       
  1209         QString idVal = idProp->values.first()->primitive();
       
  1210 
       
  1211         if (compileState.ids.contains(idVal))
       
  1212             COMPILE_EXCEPTION(idProp, tr("id is not unique"));
       
  1213 
       
  1214         obj->id = idVal;
       
  1215         addId(idVal, obj);
       
  1216     }
       
  1217 
       
  1218     // Check the Component tree is well formed
       
  1219     if (obj->defaultProperty &&
       
  1220        (obj->defaultProperty->value || obj->defaultProperty->values.count() > 1 ||
       
  1221         (obj->defaultProperty->values.count() == 1 && !obj->defaultProperty->values.first()->object)))
       
  1222         COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
       
  1223 
       
  1224     if (!obj->dynamicProperties.isEmpty())
       
  1225         COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
       
  1226     if (!obj->dynamicSignals.isEmpty())
       
  1227         COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
       
  1228     if (!obj->dynamicSlots.isEmpty())
       
  1229         COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
       
  1230 
       
  1231     Object *root = 0;
       
  1232     if (obj->defaultProperty && obj->defaultProperty->values.count())
       
  1233         root = obj->defaultProperty->values.first()->object;
       
  1234 
       
  1235     if (!root)
       
  1236         COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
       
  1237 
       
  1238     // Build the component tree
       
  1239     COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
       
  1240 
       
  1241     return true;
       
  1242 }
       
  1243 
       
  1244 bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeParser::Object *obj,
       
  1245                                          const BindingContext &ctxt)
       
  1246 {
       
  1247     ComponentCompileState oldComponentCompileState = compileState;
       
  1248     ComponentStat oldComponentStat = componentStat;
       
  1249 
       
  1250     compileState = ComponentCompileState();
       
  1251     compileState.root = obj;
       
  1252 
       
  1253     componentStat = ComponentStat();
       
  1254     componentStat.lineNumber = obj->location.start.line;
       
  1255 
       
  1256     if (obj)
       
  1257         COMPILE_CHECK(buildObject(obj, ctxt));
       
  1258 
       
  1259     COMPILE_CHECK(completeComponentBuild());
       
  1260 
       
  1261     compileState = oldComponentCompileState;
       
  1262     componentStat = oldComponentStat;
       
  1263 
       
  1264     return true;
       
  1265 }
       
  1266 
       
  1267 
       
  1268 // Build a sub-object.  A sub-object is one that was not created directly by
       
  1269 // QML - such as a grouped property object, or an attached object.  Sub-object's
       
  1270 // can't have an id, involve a custom parser, have attached properties etc.
       
  1271 bool QDeclarativeCompiler::buildSubObject(Object *obj, const BindingContext &ctxt)
       
  1272 {
       
  1273     Q_ASSERT(obj->metatype);
       
  1274     Q_ASSERT(!obj->defaultProperty);
       
  1275     Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
       
  1276                                    // sub-context
       
  1277 
       
  1278     foreach(Property *prop, obj->properties) {
       
  1279         if (isSignalPropertyName(prop->name)) {
       
  1280             COMPILE_CHECK(buildSignal(prop, obj, ctxt));
       
  1281         } else {
       
  1282             COMPILE_CHECK(buildProperty(prop, obj, ctxt));
       
  1283         }
       
  1284     }
       
  1285 
       
  1286     return true;
       
  1287 }
       
  1288 
       
  1289 int QDeclarativeCompiler::componentTypeRef()
       
  1290 {
       
  1291     QDeclarativeType *t = QDeclarativeMetaType::qmlType("Qt/Component",4,7);
       
  1292     for (int ii = output->types.count() - 1; ii >= 0; --ii) {
       
  1293         if (output->types.at(ii).type == t)
       
  1294             return ii;
       
  1295     }
       
  1296     QDeclarativeCompiledData::TypeReference ref;
       
  1297     ref.className = "Component";
       
  1298     ref.type = t;
       
  1299     output->types << ref;
       
  1300     return output->types.count() - 1;
       
  1301 }
       
  1302 
       
  1303 bool QDeclarativeCompiler::buildSignal(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj,
       
  1304                                        const BindingContext &ctxt)
       
  1305 {
       
  1306     Q_ASSERT(obj->metaObject());
       
  1307 
       
  1308     QByteArray name = prop->name;
       
  1309     Q_ASSERT(name.startsWith("on"));
       
  1310     name = name.mid(2);
       
  1311     if(name[0] >= 'A' && name[0] <= 'Z')
       
  1312         name[0] = name[0] - 'A' + 'a';
       
  1313 
       
  1314     int sigIdx = QDeclarativePropertyPrivate::findSignalByName(obj->metaObject(), name).methodIndex();
       
  1315 
       
  1316     if (sigIdx == -1) {
       
  1317 
       
  1318         // If the "on<Signal>" name doesn't resolve into a signal, try it as a
       
  1319         // property.
       
  1320         COMPILE_CHECK(buildProperty(prop, obj, ctxt));
       
  1321 
       
  1322     }  else {
       
  1323 
       
  1324         if (prop->value || prop->values.count() != 1)
       
  1325             COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
       
  1326 
       
  1327         prop->index = sigIdx;
       
  1328         obj->addSignalProperty(prop);
       
  1329 
       
  1330         if (prop->values.at(0)->object) {
       
  1331             COMPILE_CHECK(buildObject(prop->values.at(0)->object, ctxt));
       
  1332             prop->values.at(0)->type = Value::SignalObject;
       
  1333         } else {
       
  1334             prop->values.at(0)->type = Value::SignalExpression;
       
  1335 
       
  1336             if (!prop->values.at(0)->value.isScript())
       
  1337                 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
       
  1338 
       
  1339             QString script = prop->values.at(0)->value.asScript().trimmed();
       
  1340             if (script.isEmpty())
       
  1341                 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
       
  1342 
       
  1343             compileState.signalExpressions.insert(prop->values.at(0), ctxt);
       
  1344         }
       
  1345     }
       
  1346 
       
  1347     return true;
       
  1348 }
       
  1349 
       
  1350 
       
  1351 /*!
       
  1352     Returns true if (value) property \a prop exists on obj, false otherwise.
       
  1353 */
       
  1354 bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeParser::Property *prop,
       
  1355                                     QDeclarativeParser::Object *obj)
       
  1356 {
       
  1357     if(isAttachedPropertyName(prop->name) || prop->name == "id")
       
  1358         return true;
       
  1359 
       
  1360     const QMetaObject *mo = obj->metaObject();
       
  1361     if (mo) {
       
  1362         if (prop->isDefault) {
       
  1363             QMetaProperty p = QDeclarativeMetaType::defaultProperty(mo);
       
  1364             return p.name() != 0;
       
  1365         } else {
       
  1366             int idx = mo->indexOfProperty(prop->name.constData());
       
  1367             return idx != -1;
       
  1368         }
       
  1369     }
       
  1370 
       
  1371     return false;
       
  1372 }
       
  1373 
       
  1374 bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop,
       
  1375                                 QDeclarativeParser::Object *obj,
       
  1376                                 const BindingContext &ctxt)
       
  1377 {
       
  1378     if (prop->isEmpty())
       
  1379         COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
       
  1380 
       
  1381     const QMetaObject *metaObject = obj->metaObject();
       
  1382     Q_ASSERT(metaObject);
       
  1383 
       
  1384     if (isAttachedPropertyName(prop->name)) {
       
  1385         // Setup attached property data
       
  1386 
       
  1387         if (ctxt.isSubContext()) {
       
  1388             // Attached properties cannot be used on sub-objects.  Sub-objects
       
  1389             // always exist in a binding sub-context, which is what we test
       
  1390             // for here.
       
  1391             COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
       
  1392         }
       
  1393 
       
  1394         QDeclarativeType *type = 0;
       
  1395         QDeclarativeImportedNamespace *typeNamespace = 0;
       
  1396         enginePrivate->importDatabase.resolveType(unit->imports, prop->name, 
       
  1397                                                   &type, 0, 0, 0, &typeNamespace);
       
  1398 
       
  1399         if (typeNamespace) {
       
  1400             // ### We might need to indicate that this property is a namespace 
       
  1401             // for the DOM API
       
  1402             COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj, 
       
  1403                                                    ctxt));
       
  1404             return true;
       
  1405         } else if (!type || !type->attachedPropertiesType())  {
       
  1406             COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
       
  1407         }
       
  1408 
       
  1409         if (!prop->value)
       
  1410             COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
       
  1411 
       
  1412         Q_ASSERT(type->attachedPropertiesFunction());
       
  1413         prop->index = type->index();
       
  1414         prop->value->metatype = type->attachedPropertiesType();
       
  1415     } else {
       
  1416         // Setup regular property data
       
  1417         QMetaProperty p;
       
  1418 
       
  1419         if (prop->isDefault) {
       
  1420             p = QDeclarativeMetaType::defaultProperty(metaObject);
       
  1421 
       
  1422             if (p.name()) {
       
  1423                 prop->index = p.propertyIndex();
       
  1424                 prop->name = p.name();
       
  1425             }
       
  1426 
       
  1427         } else {
       
  1428             prop->index = metaObject->indexOfProperty(prop->name.constData());
       
  1429 
       
  1430             if (prop->index != -1) {
       
  1431                 p = metaObject->property(prop->index);
       
  1432                 Q_ASSERT(p.name());
       
  1433             }
       
  1434         }
       
  1435 
       
  1436         // We can't error here as the "id" property does not require a
       
  1437         // successful index resolution
       
  1438         if (p.name()) {
       
  1439             prop->type = p.userType();
       
  1440         }
       
  1441     }
       
  1442 
       
  1443     if (prop->index != -1) 
       
  1444         prop->parent->setBindingBit(prop->index);
       
  1445 
       
  1446     if (!prop->isDefault && prop->name == "id" && !ctxt.isSubContext()) {
       
  1447 
       
  1448         // The magic "id" behavior doesn't apply when "id" is resolved as a
       
  1449         // default property or to sub-objects (which are always in binding
       
  1450         // sub-contexts)
       
  1451         COMPILE_CHECK(buildIdProperty(prop, obj));
       
  1452         if (prop->type == QVariant::String &&
       
  1453             prop->values.at(0)->value.isString())
       
  1454             COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
       
  1455 
       
  1456     } else if (isAttachedPropertyName(prop->name)) {
       
  1457 
       
  1458         COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
       
  1459 
       
  1460     } else if (prop->index == -1) {
       
  1461 
       
  1462         if (prop->isDefault) {
       
  1463             COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
       
  1464         } else {
       
  1465             COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
       
  1466         }
       
  1467 
       
  1468     } else if (prop->value) {
       
  1469 
       
  1470         COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
       
  1471 
       
  1472     } else if (enginePrivate->isList(prop->type)) {
       
  1473 
       
  1474         COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
       
  1475 
       
  1476     } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) {
       
  1477 
       
  1478         COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
       
  1479 
       
  1480     } else {
       
  1481 
       
  1482         COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
       
  1483 
       
  1484     }
       
  1485 
       
  1486     return true;
       
  1487 }
       
  1488 
       
  1489 bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
       
  1490                                                     QDeclarativeParser::Property *nsProp, 
       
  1491                                                     QDeclarativeParser::Object *obj, 
       
  1492                                                     const BindingContext &ctxt)
       
  1493 {
       
  1494     if (!nsProp->value)
       
  1495         COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
       
  1496 
       
  1497     foreach (Property *prop, nsProp->value->properties) {
       
  1498 
       
  1499         if (!isAttachedPropertyName(prop->name))
       
  1500             COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
       
  1501 
       
  1502         // Setup attached property data
       
  1503 
       
  1504         QDeclarativeType *type = 0;
       
  1505         enginePrivate->importDatabase.resolveTypeInNamespace(ns, prop->name, &type, 0, 0, 0);
       
  1506 
       
  1507         if (!type || !type->attachedPropertiesType()) 
       
  1508             COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
       
  1509 
       
  1510         if (!prop->value)
       
  1511             COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
       
  1512 
       
  1513         Q_ASSERT(type->attachedPropertiesFunction());
       
  1514         prop->index = type->index();
       
  1515         prop->value->metatype = type->attachedPropertiesType();
       
  1516 
       
  1517         COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
       
  1518     }
       
  1519 
       
  1520     return true;
       
  1521 }
       
  1522 
       
  1523 void QDeclarativeCompiler::genValueProperty(QDeclarativeParser::Property *prop,
       
  1524                                    QDeclarativeParser::Object *obj)
       
  1525 {
       
  1526     if (enginePrivate->isList(prop->type)) {
       
  1527         genListProperty(prop, obj);
       
  1528     } else {
       
  1529         genPropertyAssignment(prop, obj);
       
  1530     }
       
  1531 }
       
  1532 
       
  1533 void QDeclarativeCompiler::genListProperty(QDeclarativeParser::Property *prop,
       
  1534                                   QDeclarativeParser::Object *obj)
       
  1535 {
       
  1536     int listType = enginePrivate->listType(prop->type);
       
  1537 
       
  1538     QDeclarativeInstruction fetch;
       
  1539     fetch.type = QDeclarativeInstruction::FetchQList;
       
  1540     fetch.line = prop->location.start.line;
       
  1541     fetch.fetchQmlList.property = prop->index;
       
  1542     bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
       
  1543     fetch.fetchQmlList.type = listType;
       
  1544     output->bytecode << fetch;
       
  1545 
       
  1546     for (int ii = 0; ii < prop->values.count(); ++ii) {
       
  1547         Value *v = prop->values.at(ii);
       
  1548 
       
  1549         if (v->type == Value::CreatedObject) {
       
  1550 
       
  1551             genObject(v->object);
       
  1552             if (listTypeIsInterface) {
       
  1553                 QDeclarativeInstruction assign;
       
  1554                 assign.type = QDeclarativeInstruction::AssignObjectList;
       
  1555                 assign.line = prop->location.start.line;
       
  1556                 output->bytecode << assign;
       
  1557             } else {
       
  1558                 QDeclarativeInstruction store;
       
  1559                 store.type = QDeclarativeInstruction::StoreObjectQList;
       
  1560                 store.line = prop->location.start.line;
       
  1561                 output->bytecode << store;
       
  1562             }
       
  1563 
       
  1564         } else if (v->type == Value::PropertyBinding) {
       
  1565 
       
  1566             genBindingAssignment(v, prop, obj);
       
  1567 
       
  1568         }
       
  1569 
       
  1570     }
       
  1571 
       
  1572     QDeclarativeInstruction pop;
       
  1573     pop.type = QDeclarativeInstruction::PopQList;
       
  1574     pop.line = prop->location.start.line;
       
  1575     output->bytecode << pop;
       
  1576 }
       
  1577 
       
  1578 void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *prop,
       
  1579                                         QDeclarativeParser::Object *obj,
       
  1580                                         QDeclarativeParser::Property *valueTypeProperty)
       
  1581 {
       
  1582     for (int ii = 0; ii < prop->values.count(); ++ii) {
       
  1583         QDeclarativeParser::Value *v = prop->values.at(ii);
       
  1584 
       
  1585         Q_ASSERT(v->type == Value::CreatedObject ||
       
  1586                  v->type == Value::PropertyBinding ||
       
  1587                  v->type == Value::Literal);
       
  1588 
       
  1589         if (v->type == Value::CreatedObject) {
       
  1590 
       
  1591             genObject(v->object);
       
  1592 
       
  1593             if (QDeclarativeMetaType::isInterface(prop->type)) {
       
  1594 
       
  1595                 QDeclarativeInstruction store;
       
  1596                 store.type = QDeclarativeInstruction::StoreInterface;
       
  1597                 store.line = v->object->location.start.line;
       
  1598                 store.storeObject.propertyIndex = prop->index;
       
  1599                 output->bytecode << store;
       
  1600 
       
  1601             } else if (prop->type == -1) {
       
  1602 
       
  1603                 QDeclarativeInstruction store;
       
  1604                 store.type = QDeclarativeInstruction::StoreVariantObject;
       
  1605                 store.line = v->object->location.start.line;
       
  1606                 store.storeObject.propertyIndex = prop->index;
       
  1607                 output->bytecode << store;
       
  1608 
       
  1609             } else {
       
  1610 
       
  1611                 QDeclarativeInstruction store;
       
  1612                 store.type = QDeclarativeInstruction::StoreObject;
       
  1613                 store.line = v->object->location.start.line;
       
  1614                 store.storeObject.propertyIndex = prop->index;
       
  1615                 output->bytecode << store;
       
  1616 
       
  1617             }
       
  1618         } else if (v->type == Value::PropertyBinding) {
       
  1619 
       
  1620             genBindingAssignment(v, prop, obj, valueTypeProperty);
       
  1621 
       
  1622         } else if (v->type == Value::Literal) {
       
  1623 
       
  1624             QMetaProperty mp = obj->metaObject()->property(prop->index);
       
  1625             genLiteralAssignment(mp, v);
       
  1626 
       
  1627         }
       
  1628 
       
  1629     }
       
  1630 
       
  1631     for (int ii = 0; ii < prop->onValues.count(); ++ii) {
       
  1632 
       
  1633         QDeclarativeParser::Value *v = prop->onValues.at(ii);
       
  1634 
       
  1635         Q_ASSERT(v->type == Value::ValueSource ||
       
  1636                  v->type == Value::ValueInterceptor);
       
  1637 
       
  1638         if (v->type == Value::ValueSource) {
       
  1639             genObject(v->object);
       
  1640 
       
  1641             QDeclarativeInstruction store;
       
  1642             store.type = QDeclarativeInstruction::StoreValueSource;
       
  1643             store.line = v->object->location.start.line;
       
  1644             if (valueTypeProperty) {
       
  1645                 store.assignValueSource.property = genValueTypeData(prop, valueTypeProperty);
       
  1646                 store.assignValueSource.owner = 1;
       
  1647             } else {
       
  1648                 store.assignValueSource.property = genPropertyData(prop);
       
  1649                 store.assignValueSource.owner = 0;
       
  1650             }
       
  1651             QDeclarativeType *valueType = toQmlType(v->object);
       
  1652             store.assignValueSource.castValue = valueType->propertyValueSourceCast();
       
  1653             output->bytecode << store;
       
  1654 
       
  1655         } else if (v->type == Value::ValueInterceptor) {
       
  1656             genObject(v->object);
       
  1657 
       
  1658             QDeclarativeInstruction store;
       
  1659             store.type = QDeclarativeInstruction::StoreValueInterceptor;
       
  1660             store.line = v->object->location.start.line;
       
  1661             if (valueTypeProperty) {
       
  1662                 store.assignValueInterceptor.property = genValueTypeData(prop, valueTypeProperty);
       
  1663                 store.assignValueInterceptor.owner = 1;
       
  1664             } else {
       
  1665                 store.assignValueInterceptor.property = genPropertyData(prop);
       
  1666                 store.assignValueInterceptor.owner = 0;
       
  1667             }
       
  1668             QDeclarativeType *valueType = toQmlType(v->object);
       
  1669             store.assignValueInterceptor.castValue = valueType->propertyValueInterceptorCast();
       
  1670             output->bytecode << store;
       
  1671         }
       
  1672 
       
  1673     }
       
  1674 }
       
  1675 
       
  1676 bool QDeclarativeCompiler::buildIdProperty(QDeclarativeParser::Property *prop,
       
  1677                                   QDeclarativeParser::Object *obj)
       
  1678 {
       
  1679     if (prop->value ||
       
  1680         prop->values.count() > 1 ||
       
  1681         prop->values.at(0)->object)
       
  1682         COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
       
  1683 
       
  1684     QDeclarativeParser::Value *idValue = prop->values.at(0);
       
  1685     QString val = idValue->primitive();
       
  1686 
       
  1687     COMPILE_CHECK(checkValidId(idValue, val));
       
  1688 
       
  1689     if (compileState.ids.contains(val))
       
  1690         COMPILE_EXCEPTION(prop, tr("id is not unique"));
       
  1691 
       
  1692     prop->values.at(0)->type = Value::Id;
       
  1693 
       
  1694     obj->id = val;
       
  1695     addId(val, obj);
       
  1696 
       
  1697     return true;
       
  1698 }
       
  1699 
       
  1700 void QDeclarativeCompiler::addId(const QString &id, QDeclarativeParser::Object *obj)
       
  1701 {
       
  1702     Q_ASSERT(!compileState.ids.contains(id));
       
  1703     Q_ASSERT(obj->id == id);
       
  1704     obj->idIndex = compileState.ids.count();
       
  1705     compileState.ids.insert(id, obj);
       
  1706     compileState.idIndexes.insert(obj->idIndex, obj);
       
  1707 }
       
  1708 
       
  1709 void QDeclarativeCompiler::addBindingReference(const BindingReference &ref)
       
  1710 {
       
  1711     Q_ASSERT(ref.value && !compileState.bindings.contains(ref.value));
       
  1712     compileState.bindings.insert(ref.value, ref);
       
  1713 }
       
  1714 
       
  1715 void QDeclarativeCompiler::saveComponentState()
       
  1716 {
       
  1717     Q_ASSERT(compileState.root);
       
  1718     Q_ASSERT(!savedCompileStates.contains(compileState.root));
       
  1719 
       
  1720     savedCompileStates.insert(compileState.root, compileState);
       
  1721     savedComponentStats.append(componentStat);
       
  1722 }
       
  1723 
       
  1724 QDeclarativeCompiler::ComponentCompileState
       
  1725 QDeclarativeCompiler::componentState(QDeclarativeParser::Object *obj)
       
  1726 {
       
  1727     Q_ASSERT(savedCompileStates.contains(obj));
       
  1728     return savedCompileStates.value(obj);
       
  1729 }
       
  1730 
       
  1731 // Build attached property object.  In this example,
       
  1732 // Text {
       
  1733 //    GridView.row: 10
       
  1734 // }
       
  1735 // GridView is an attached property object.
       
  1736 bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeParser::Property *prop,
       
  1737                                         QDeclarativeParser::Object *obj,
       
  1738                                         const BindingContext &ctxt)
       
  1739 {
       
  1740     Q_ASSERT(prop->value);
       
  1741     Q_ASSERT(prop->index != -1); // This is set in buildProperty()
       
  1742 
       
  1743     obj->addAttachedProperty(prop);
       
  1744 
       
  1745     COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
       
  1746 
       
  1747     return true;
       
  1748 }
       
  1749 
       
  1750 
       
  1751 // Build "grouped" properties. In this example:
       
  1752 // Text {
       
  1753 //     font.pointSize: 12
       
  1754 //     font.family: "Helvetica"
       
  1755 // }
       
  1756 // font is a nested property.  pointSize and family are not.
       
  1757 bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeParser::Property *prop,
       
  1758                                                 QDeclarativeParser::Object *obj,
       
  1759                                                 const BindingContext &ctxt)
       
  1760 {
       
  1761     Q_ASSERT(prop->type != 0);
       
  1762     Q_ASSERT(prop->index != -1);
       
  1763 
       
  1764     if (QDeclarativeValueTypeFactory::isValueType(prop->type)) {
       
  1765         QDeclarativeEnginePrivate *ep =
       
  1766             static_cast<QDeclarativeEnginePrivate *>(QObjectPrivate::get(engine));
       
  1767         if (prop->type >= 0 /* QVariant == -1 */ && ep->valueTypes[prop->type]) {
       
  1768 
       
  1769             if (prop->values.count()) {
       
  1770                 if (prop->values.at(0)->location < prop->value->location) {
       
  1771                     COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
       
  1772                 } else {
       
  1773                     COMPILE_EXCEPTION(prop->values.at(0), tr( "Property has already been assigned a value"));
       
  1774                 }
       
  1775             }
       
  1776 
       
  1777             if (!obj->metaObject()->property(prop->index).isWritable()) {
       
  1778                 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
       
  1779             }
       
  1780 
       
  1781             COMPILE_CHECK(buildValueTypeProperty(ep->valueTypes[prop->type],
       
  1782                                                  prop->value, obj, ctxt.incr()));
       
  1783             obj->addValueTypeProperty(prop);
       
  1784         } else {
       
  1785             COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
       
  1786         }
       
  1787 
       
  1788     } else {
       
  1789         // Load the nested property's meta type
       
  1790         prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
       
  1791         if (!prop->value->metatype)
       
  1792             COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
       
  1793 
       
  1794         if (prop->values.count()) 
       
  1795             COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign a value directly to a grouped property"));
       
  1796 
       
  1797         obj->addGroupedProperty(prop);
       
  1798 
       
  1799         COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
       
  1800     }
       
  1801 
       
  1802     return true;
       
  1803 }
       
  1804 
       
  1805 bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
       
  1806                                                   QDeclarativeParser::Object *obj,
       
  1807                                                   QDeclarativeParser::Object *baseObj,
       
  1808                                                   const BindingContext &ctxt)
       
  1809 {
       
  1810     if (obj->defaultProperty)
       
  1811         COMPILE_EXCEPTION(obj, tr("Invalid property use"));
       
  1812     obj->metatype = type->metaObject();
       
  1813 
       
  1814     foreach (Property *prop, obj->properties) {
       
  1815         int idx = type->metaObject()->indexOfProperty(prop->name.constData());
       
  1816         if (idx == -1)
       
  1817             COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name)));
       
  1818         QMetaProperty p = type->metaObject()->property(idx);
       
  1819         prop->index = idx;
       
  1820         prop->type = p.userType();
       
  1821         prop->isValueTypeSubProperty = true;
       
  1822 
       
  1823         if (prop->value)
       
  1824             COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
       
  1825 
       
  1826         if (prop->values.count() > 1) {
       
  1827             COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
       
  1828         } else if (prop->values.count()) {
       
  1829             Value *value = prop->values.at(0);
       
  1830 
       
  1831             if (value->object) {
       
  1832                 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
       
  1833             } else if (value->value.isScript()) {
       
  1834                 // ### Check for writability
       
  1835                 BindingReference reference;
       
  1836                 reference.expression = value->value;
       
  1837                 reference.property = prop;
       
  1838                 reference.value = value;
       
  1839                 reference.bindingContext = ctxt;
       
  1840                 reference.bindingContext.owner++;
       
  1841                 addBindingReference(reference);
       
  1842                 value->type = Value::PropertyBinding;
       
  1843             } else  {
       
  1844                 COMPILE_CHECK(testLiteralAssignment(p, value));
       
  1845                 value->type = Value::Literal;
       
  1846             }
       
  1847         }
       
  1848 
       
  1849         for (int ii = 0; ii < prop->onValues.count(); ++ii) {
       
  1850             Value *v = prop->onValues.at(ii);
       
  1851             Q_ASSERT(v->object);
       
  1852 
       
  1853             COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt)); 
       
  1854         }
       
  1855 
       
  1856         obj->addValueProperty(prop);
       
  1857     }
       
  1858 
       
  1859     return true;
       
  1860 }
       
  1861 
       
  1862 // Build assignments to QML lists.  QML lists are properties of type
       
  1863 // QDeclarativeListProperty<T>.  List properties can accept a list of 
       
  1864 // objects, or a single binding.
       
  1865 bool QDeclarativeCompiler::buildListProperty(QDeclarativeParser::Property *prop,
       
  1866                                              QDeclarativeParser::Object *obj,
       
  1867                                              const BindingContext &ctxt)
       
  1868 {
       
  1869     Q_ASSERT(enginePrivate->isList(prop->type));
       
  1870 
       
  1871     int t = prop->type;
       
  1872 
       
  1873     obj->addValueProperty(prop);
       
  1874 
       
  1875     int listType = enginePrivate->listType(t);
       
  1876     bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
       
  1877 
       
  1878     bool assignedBinding = false;
       
  1879     for (int ii = 0; ii < prop->values.count(); ++ii) {
       
  1880         Value *v = prop->values.at(ii);
       
  1881         if (v->object) {
       
  1882             v->type = Value::CreatedObject;
       
  1883             COMPILE_CHECK(buildObject(v->object, ctxt));
       
  1884 
       
  1885             // We check object coercian here.  We check interface assignment
       
  1886             // at runtime.
       
  1887             if (!listTypeIsInterface) {
       
  1888                 if (!canCoerce(listType, v->object)) {
       
  1889                     COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
       
  1890                 }
       
  1891             }
       
  1892 
       
  1893         } else if (v->value.isScript()) {
       
  1894             if (assignedBinding)
       
  1895                 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
       
  1896 
       
  1897             assignedBinding = true;
       
  1898             COMPILE_CHECK(buildBinding(v, prop, ctxt));
       
  1899             v->type = Value::PropertyBinding;
       
  1900         } else {
       
  1901             COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
       
  1902         }
       
  1903     }
       
  1904 
       
  1905     return true;
       
  1906 }
       
  1907 
       
  1908 // Compiles an assignment to a QDeclarativeScriptString property
       
  1909 bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeParser::Property *prop,
       
  1910                                             QDeclarativeParser::Object *obj,
       
  1911                                             const BindingContext &ctxt)
       
  1912 {
       
  1913     if (prop->values.count() > 1) 
       
  1914         COMPILE_EXCEPTION(prop->values.at(1), tr( "Cannot assign multiple values to a script property"));
       
  1915 
       
  1916     if (prop->values.at(0)->object)
       
  1917         COMPILE_EXCEPTION(prop->values.at(0), tr( "Invalid property assignment: script expected"));
       
  1918 
       
  1919     obj->addScriptStringProperty(prop, ctxt.stack);
       
  1920 
       
  1921     return true;
       
  1922 }
       
  1923 
       
  1924 // Compile regular property assignments of the form "property: <value>"
       
  1925 bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeParser::Property *prop,
       
  1926                                           QDeclarativeParser::Object *obj,
       
  1927                                           const BindingContext &ctxt)
       
  1928 {
       
  1929     obj->addValueProperty(prop);
       
  1930 
       
  1931     for (int ii = 0; ii < prop->values.count(); ++ii) {
       
  1932         Value *v = prop->values.at(ii);
       
  1933         if (v->object) {
       
  1934 
       
  1935             COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
       
  1936 
       
  1937         } else {
       
  1938 
       
  1939             COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
       
  1940 
       
  1941         }
       
  1942     }
       
  1943 
       
  1944     for (int ii = 0; ii < prop->onValues.count(); ++ii) {
       
  1945         Value *v = prop->onValues.at(ii);
       
  1946 
       
  1947         Q_ASSERT(v->object);
       
  1948         COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
       
  1949     }
       
  1950 
       
  1951     return true;
       
  1952 }
       
  1953 
       
  1954 // Compile assigning a single object instance to a regular property
       
  1955 bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeParser::Property *prop,
       
  1956                                                          QDeclarativeParser::Object *obj,
       
  1957                                                          QDeclarativeParser::Value *v,
       
  1958                                                          const BindingContext &ctxt)
       
  1959 {
       
  1960     Q_ASSERT(prop->index != -1);
       
  1961     Q_ASSERT(v->object->type != -1);
       
  1962 
       
  1963     if (!obj->metaObject()->property(prop->index).isWritable())
       
  1964         COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
       
  1965 
       
  1966     if (QDeclarativeMetaType::isInterface(prop->type)) {
       
  1967 
       
  1968         // Assigning an object to an interface ptr property
       
  1969         COMPILE_CHECK(buildObject(v->object, ctxt));
       
  1970 
       
  1971         v->type = Value::CreatedObject;
       
  1972 
       
  1973     } else if (prop->type == -1) {
       
  1974 
       
  1975         // Assigning an object to a QVariant
       
  1976         COMPILE_CHECK(buildObject(v->object, ctxt));
       
  1977 
       
  1978         v->type = Value::CreatedObject;
       
  1979     } else {
       
  1980         // Normally buildObject() will set this up, but we need the static
       
  1981         // meta object earlier to test for assignability.  It doesn't matter
       
  1982         // that there may still be outstanding synthesized meta object changes
       
  1983         // on this type, as they are not relevant for assignability testing
       
  1984         v->object->metatype = output->types.at(v->object->type).metaObject();
       
  1985         Q_ASSERT(v->object->metaObject());
       
  1986 
       
  1987         // We want to raw metaObject here as the raw metaobject is the
       
  1988         // actual property type before we applied any extensions that might
       
  1989         // effect the properties on the type, but don't effect assignability
       
  1990         const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
       
  1991 
       
  1992         // Will be true if the assgned type inherits propertyMetaObject
       
  1993         bool isAssignable = false;
       
  1994         // Determine isAssignable value
       
  1995         if (propertyMetaObject) {
       
  1996             const QMetaObject *c = v->object->metatype;
       
  1997             while(c) {
       
  1998                 isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject));
       
  1999                 c = c->superClass();
       
  2000             }
       
  2001         }
       
  2002 
       
  2003         if (isAssignable) {
       
  2004             // Simple assignment
       
  2005             COMPILE_CHECK(buildObject(v->object, ctxt));
       
  2006 
       
  2007             v->type = Value::CreatedObject;
       
  2008         } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) {
       
  2009             // Automatic "Component" insertion
       
  2010             QDeclarativeParser::Object *root = v->object;
       
  2011             QDeclarativeParser::Object *component = new QDeclarativeParser::Object;
       
  2012             component->type = componentTypeRef();
       
  2013             component->typeName = "Qt/Component";
       
  2014             component->metatype = &QDeclarativeComponent::staticMetaObject;
       
  2015             component->location = root->location;
       
  2016             QDeclarativeParser::Value *componentValue = new QDeclarativeParser::Value;
       
  2017             componentValue->object = root;
       
  2018             component->getDefaultProperty()->addValue(componentValue);
       
  2019             v->object = component;
       
  2020             COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
       
  2021         } else {
       
  2022             COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
       
  2023         }
       
  2024     }
       
  2025 
       
  2026     return true;
       
  2027 }
       
  2028 
       
  2029 // Compile assigning a single object instance to a regular property using the "on" syntax.
       
  2030 //
       
  2031 // For example:
       
  2032 //     Item {
       
  2033 //         NumberAnimation on x { }
       
  2034 //     }
       
  2035 bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeParser::Property *prop,
       
  2036                                                      QDeclarativeParser::Object *obj,
       
  2037                                                      QDeclarativeParser::Object *baseObj,
       
  2038                                                      QDeclarativeParser::Value *v,
       
  2039                                                      const BindingContext &ctxt)
       
  2040 {
       
  2041     Q_ASSERT(prop->index != -1);
       
  2042     Q_ASSERT(v->object->type != -1);
       
  2043 
       
  2044     if (!obj->metaObject()->property(prop->index).isWritable())
       
  2045         COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
       
  2046 
       
  2047 
       
  2048     // Normally buildObject() will set this up, but we need the static
       
  2049     // meta object earlier to test for assignability.  It doesn't matter
       
  2050     // that there may still be outstanding synthesized meta object changes
       
  2051     // on this type, as they are not relevant for assignability testing
       
  2052     v->object->metatype = output->types.at(v->object->type).metaObject();
       
  2053     Q_ASSERT(v->object->metaObject());
       
  2054 
       
  2055     // Will be true if the assigned type inherits QDeclarativePropertyValueSource
       
  2056     bool isPropertyValue = false;
       
  2057     // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor
       
  2058     bool isPropertyInterceptor = false;
       
  2059     if (QDeclarativeType *valueType = toQmlType(v->object)) {
       
  2060         isPropertyValue = valueType->propertyValueSourceCast() != -1;
       
  2061         isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
       
  2062     }
       
  2063 
       
  2064     if (isPropertyValue || isPropertyInterceptor) {
       
  2065         // Assign as a property value source
       
  2066         COMPILE_CHECK(buildObject(v->object, ctxt));
       
  2067 
       
  2068         if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
       
  2069             buildDynamicMeta(baseObj, ForceCreation);
       
  2070         v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
       
  2071     } else {
       
  2072         COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(QString::fromUtf8(v->object->typeName)).arg(QString::fromUtf8(prop->name.constData())));
       
  2073     }
       
  2074 
       
  2075     return true;
       
  2076 }
       
  2077 
       
  2078 // Compile assigning a literal or binding to a regular property
       
  2079 bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeParser::Property *prop,
       
  2080                                                  QDeclarativeParser::Object *obj,
       
  2081                                                  QDeclarativeParser::Value *v,
       
  2082                                                  const BindingContext &ctxt)
       
  2083 {
       
  2084     Q_ASSERT(prop->index != -1);
       
  2085 
       
  2086     if (v->value.isScript()) {
       
  2087 
       
  2088         //optimization for <Type>.<EnumValue> enum assignments
       
  2089         bool isEnumAssignment = false;
       
  2090         COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj, v, &isEnumAssignment));
       
  2091         if (isEnumAssignment) {
       
  2092             v->type = Value::Literal;
       
  2093             return true;
       
  2094         }
       
  2095 
       
  2096         COMPILE_CHECK(buildBinding(v, prop, ctxt));
       
  2097 
       
  2098         v->type = Value::PropertyBinding;
       
  2099 
       
  2100     } else {
       
  2101 
       
  2102         COMPILE_CHECK(testLiteralAssignment(obj->metaObject()->property(prop->index), v));
       
  2103 
       
  2104         v->type = Value::Literal;
       
  2105     }
       
  2106 
       
  2107     return true;
       
  2108 }
       
  2109 
       
  2110 bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop,
       
  2111                                               QDeclarativeParser::Object *obj,
       
  2112                                               QDeclarativeParser::Value *v,
       
  2113                                               bool *isAssignment)
       
  2114 {
       
  2115     *isAssignment = false;
       
  2116     if (!prop.isEnumType())
       
  2117         return true;
       
  2118 
       
  2119     if (!prop.isWritable())
       
  2120         COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
       
  2121 
       
  2122     QString string = v->value.asString();
       
  2123     if (!string.at(0).isUpper())
       
  2124         return true;
       
  2125 
       
  2126     QStringList parts = string.split(QLatin1Char('.'));
       
  2127     if (parts.count() != 2)
       
  2128         return true;
       
  2129 
       
  2130     QString typeName = parts.at(0);
       
  2131     QDeclarativeType *type = 0;
       
  2132     enginePrivate->importDatabase.resolveType(unit->imports, typeName.toUtf8(),
       
  2133                                               &type, 0, 0, 0, 0);
       
  2134 
       
  2135     if (!type || obj->typeName != type->qmlTypeName())
       
  2136         return true;
       
  2137 
       
  2138     QString enumValue = parts.at(1);
       
  2139     int value;
       
  2140     if (prop.isFlagType()) {
       
  2141         value = prop.enumerator().keysToValue(enumValue.toUtf8().constData());
       
  2142     } else
       
  2143         value = prop.enumerator().keyToValue(enumValue.toUtf8().constData());
       
  2144     if (value == -1)
       
  2145         return true;
       
  2146 
       
  2147     v->type = Value::Literal;
       
  2148     v->value = QDeclarativeParser::Variant(enumValue);
       
  2149     *isAssignment = true;
       
  2150 
       
  2151     return true;
       
  2152 }
       
  2153 
       
  2154 // Similar logic to above, but not knowing target property.
       
  2155 int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const
       
  2156 {
       
  2157     int dot = script.indexOf('.');
       
  2158     if (dot > 0) {
       
  2159         QDeclarativeType *type = 0;
       
  2160         enginePrivate->importDatabase.resolveType(unit->imports, script.left(dot), &type, 0, 0, 0, 0);
       
  2161         if (!type)
       
  2162             return -1;
       
  2163         const QMetaObject *mo = type->metaObject();
       
  2164         const char *key = script.constData() + dot+1;
       
  2165         int i = mo->enumeratorCount();
       
  2166         while (i--) {
       
  2167             int v = mo->enumerator(i).keyToValue(key);
       
  2168             if (v >= 0)
       
  2169                 return v;
       
  2170         }
       
  2171     }
       
  2172     return -1;
       
  2173 }
       
  2174 
       
  2175 // Ensures that the dynamic meta specification on obj is valid
       
  2176 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj)
       
  2177 {
       
  2178     QSet<QByteArray> propNames;
       
  2179     QSet<QByteArray> methodNames;
       
  2180     bool seenDefaultProperty = false;
       
  2181 
       
  2182     // Check properties
       
  2183     for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
       
  2184         const QDeclarativeParser::Object::DynamicProperty &prop =
       
  2185             obj->dynamicProperties.at(ii);
       
  2186 
       
  2187         if (prop.isDefaultProperty) {
       
  2188             if (seenDefaultProperty)
       
  2189                 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
       
  2190             seenDefaultProperty = true;
       
  2191         }
       
  2192 
       
  2193         if (propNames.contains(prop.name))
       
  2194             COMPILE_EXCEPTION(&prop, tr("Duplicate property name"));
       
  2195 
       
  2196         if (QString::fromUtf8(prop.name).at(0).isUpper()) 
       
  2197             COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
       
  2198         propNames.insert(prop.name);
       
  2199     }
       
  2200 
       
  2201     for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
       
  2202         QByteArray name = obj->dynamicSignals.at(ii).name;
       
  2203         if (methodNames.contains(name))
       
  2204             COMPILE_EXCEPTION(obj, tr("Duplicate signal name"));
       
  2205         if (QString::fromUtf8(name).at(0).isUpper()) 
       
  2206             COMPILE_EXCEPTION(obj, tr("Signal names cannot begin with an upper case letter"));
       
  2207         methodNames.insert(name);
       
  2208     }
       
  2209     for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
       
  2210         QByteArray name = obj->dynamicSlots.at(ii).name;
       
  2211         if (methodNames.contains(name))
       
  2212             COMPILE_EXCEPTION(obj, tr("Duplicate method name"));
       
  2213         if (QString::fromUtf8(name).at(0).isUpper()) 
       
  2214             COMPILE_EXCEPTION(obj, tr("Method names cannot begin with an upper case letter"));
       
  2215         methodNames.insert(name);
       
  2216     }
       
  2217 
       
  2218     return true;
       
  2219 }
       
  2220 
       
  2221 bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeParser::Object *obj)
       
  2222 {
       
  2223     for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
       
  2224         const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
       
  2225 
       
  2226         if (!p.defaultValue || p.type == Object::DynamicProperty::Alias)
       
  2227             continue;
       
  2228 
       
  2229         Property *property = 0;
       
  2230         if (p.isDefaultProperty) {
       
  2231             property = obj->getDefaultProperty();
       
  2232         } else {
       
  2233             property = obj->getProperty(p.name);
       
  2234             if (!property->values.isEmpty()) 
       
  2235                 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
       
  2236         }
       
  2237 
       
  2238         if (property->value)
       
  2239             COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
       
  2240 
       
  2241         for (int ii = 0; ii < p.defaultValue->values.count(); ++ii) {
       
  2242             Value *v = p.defaultValue->values.at(ii);
       
  2243             v->addref();
       
  2244             property->values.append(v);
       
  2245         }
       
  2246     }
       
  2247     return true;
       
  2248 }
       
  2249 
       
  2250 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
       
  2251 
       
  2252 bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, DynamicMetaMode mode)
       
  2253 {
       
  2254     Q_ASSERT(obj);
       
  2255     Q_ASSERT(obj->metatype);
       
  2256 
       
  2257     if (mode != ForceCreation &&
       
  2258         obj->dynamicProperties.isEmpty() &&
       
  2259         obj->dynamicSignals.isEmpty() &&
       
  2260         obj->dynamicSlots.isEmpty())
       
  2261         return true;
       
  2262 
       
  2263     QByteArray dynamicData(sizeof(QDeclarativeVMEMetaData), (char)0);
       
  2264 
       
  2265     QByteArray newClassName = obj->metatype->className();
       
  2266     newClassName.append("_QML_");
       
  2267     int idx = classIndexCounter()->fetchAndAddRelaxed(1);
       
  2268     newClassName.append(QByteArray::number(idx));
       
  2269     if (compileState.root == obj) {
       
  2270         QString path = output->url.path();
       
  2271         int lastSlash = path.lastIndexOf(QLatin1Char('/'));
       
  2272         if (lastSlash > -1) {
       
  2273             QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
       
  2274             if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
       
  2275                 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(idx);
       
  2276         }
       
  2277     }
       
  2278 
       
  2279     QMetaObjectBuilder builder;
       
  2280     builder.setClassName(newClassName);
       
  2281     builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
       
  2282 
       
  2283     bool hasAlias = false;
       
  2284     for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
       
  2285         const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
       
  2286 
       
  2287         int propIdx =
       
  2288             obj->metaObject()->indexOfProperty(p.name.constData());
       
  2289         if (-1 != propIdx) {
       
  2290             QMetaProperty prop = obj->metaObject()->property(propIdx);
       
  2291             if (prop.isFinal())
       
  2292                 COMPILE_EXCEPTION(&p, tr("Cannot override FINAL property"));
       
  2293         }
       
  2294 
       
  2295         if (p.isDefaultProperty &&
       
  2296             (p.type != Object::DynamicProperty::Alias ||
       
  2297              mode == ResolveAliases))
       
  2298             builder.addClassInfo("DefaultProperty", p.name);
       
  2299 
       
  2300         QByteArray type;
       
  2301         int propertyType = 0;
       
  2302         bool readonly = false;
       
  2303         switch(p.type) {
       
  2304         case Object::DynamicProperty::Alias:
       
  2305             hasAlias = true;
       
  2306             continue;
       
  2307             break;
       
  2308         case Object::DynamicProperty::CustomList:
       
  2309         case Object::DynamicProperty::Custom:
       
  2310             {
       
  2311                 QByteArray customTypeName;
       
  2312                 QDeclarativeType *qmltype = 0;
       
  2313                 QUrl url;
       
  2314                 if (!enginePrivate->importDatabase.resolveType(unit->imports, p.customType, &qmltype, 
       
  2315                                                                &url, 0, 0, 0)) 
       
  2316                     COMPILE_EXCEPTION(&p, tr("Invalid property type"));
       
  2317 
       
  2318                 if (!qmltype) {
       
  2319                     QDeclarativeCompositeTypeData *tdata = enginePrivate->typeManager.get(url);
       
  2320                     Q_ASSERT(tdata);
       
  2321                     Q_ASSERT(tdata->status == QDeclarativeCompositeTypeData::Complete);
       
  2322 
       
  2323                     QDeclarativeCompiledData *data = tdata->toCompiledComponent(engine);
       
  2324                     customTypeName = data->root->className();
       
  2325                 } else {
       
  2326                     customTypeName = qmltype->typeName();
       
  2327                 }
       
  2328 
       
  2329                 if (p.type == Object::DynamicProperty::Custom) {
       
  2330                     type = customTypeName + '*';
       
  2331                     propertyType = QMetaType::QObjectStar;
       
  2332                 } else {
       
  2333                     readonly = true;
       
  2334                     type = "QDeclarativeListProperty<";
       
  2335                     type.append(customTypeName);
       
  2336                     type.append(">");
       
  2337                     propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
       
  2338                 }
       
  2339             }
       
  2340             break;
       
  2341         case Object::DynamicProperty::Variant:
       
  2342             propertyType = -1;
       
  2343             type = "QVariant";
       
  2344             break;
       
  2345         case Object::DynamicProperty::Int:
       
  2346             propertyType = QVariant::Int;
       
  2347             type = "int";
       
  2348             break;
       
  2349         case Object::DynamicProperty::Bool:
       
  2350             propertyType = QVariant::Bool;
       
  2351             type = "bool";
       
  2352             break;
       
  2353         case Object::DynamicProperty::Real:
       
  2354             propertyType = QVariant::Double;
       
  2355             type = "double";
       
  2356             break;
       
  2357         case Object::DynamicProperty::String:
       
  2358             propertyType = QVariant::String;
       
  2359             type = "QString";
       
  2360             break;
       
  2361         case Object::DynamicProperty::Url:
       
  2362             propertyType = QVariant::Url;
       
  2363             type = "QUrl";
       
  2364             break;
       
  2365         case Object::DynamicProperty::Color:
       
  2366             propertyType = QVariant::Color;
       
  2367             type = "QColor";
       
  2368             break;
       
  2369         case Object::DynamicProperty::Time:
       
  2370             propertyType = QVariant::Time;
       
  2371             type = "QTime";
       
  2372             break;
       
  2373         case Object::DynamicProperty::Date:
       
  2374             propertyType = QVariant::Date;
       
  2375             type = "QDate";
       
  2376             break;
       
  2377         case Object::DynamicProperty::DateTime:
       
  2378             propertyType = QVariant::DateTime;
       
  2379             type = "QDateTime";
       
  2380             break;
       
  2381         }
       
  2382 
       
  2383         ((QDeclarativeVMEMetaData *)dynamicData.data())->propertyCount++;
       
  2384         QDeclarativeVMEMetaData::PropertyData propertyData = { propertyType };
       
  2385         dynamicData.append((char *)&propertyData, sizeof(propertyData));
       
  2386 
       
  2387         builder.addSignal(p.name + "Changed()");
       
  2388         QMetaPropertyBuilder propBuilder = 
       
  2389             builder.addProperty(p.name, type, builder.methodCount() - 1);
       
  2390         propBuilder.setScriptable(true);
       
  2391         propBuilder.setWritable(!readonly);
       
  2392     }
       
  2393 
       
  2394     if (mode == ResolveAliases) {
       
  2395         for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) {
       
  2396             const Object::DynamicProperty &p = obj->dynamicProperties.at(ii);
       
  2397 
       
  2398             if (p.type == Object::DynamicProperty::Alias) {
       
  2399                 ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++;
       
  2400                 compileAlias(builder, dynamicData, obj, p);
       
  2401             }
       
  2402         }
       
  2403     }
       
  2404 
       
  2405     for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) {
       
  2406         const Object::DynamicSignal &s = obj->dynamicSignals.at(ii);
       
  2407         QByteArray sig(s.name + '(');
       
  2408         for (int jj = 0; jj < s.parameterTypes.count(); ++jj) {
       
  2409             if (jj) sig.append(',');
       
  2410             sig.append(s.parameterTypes.at(jj));
       
  2411         }
       
  2412         sig.append(')');
       
  2413         QMetaMethodBuilder b = builder.addSignal(sig);
       
  2414         b.setParameterNames(s.parameterNames);
       
  2415         ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++;
       
  2416     }
       
  2417 
       
  2418     QStringList funcScripts;
       
  2419 
       
  2420     for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
       
  2421         Object::DynamicSlot &s = obj->dynamicSlots[ii];
       
  2422         QByteArray sig(s.name + '(');
       
  2423         QString funcScript(QLatin1String("(function("));
       
  2424 
       
  2425         for (int jj = 0; jj < s.parameterNames.count(); ++jj) {
       
  2426             if (jj) { 
       
  2427                 sig.append(',');
       
  2428                 funcScript.append(QLatin1Char(','));
       
  2429             }
       
  2430             funcScript.append(QLatin1String(s.parameterNames.at(jj)));
       
  2431             sig.append("QVariant");
       
  2432         }
       
  2433         sig.append(')');
       
  2434         funcScript.append(QLatin1Char(')'));
       
  2435         funcScript.append(s.body);
       
  2436         funcScript.append(QLatin1Char(')'));
       
  2437         funcScripts << funcScript;
       
  2438 
       
  2439         QMetaMethodBuilder b = builder.addSlot(sig);
       
  2440         b.setReturnType("QVariant");
       
  2441         b.setParameterNames(s.parameterNames);
       
  2442 
       
  2443         ((QDeclarativeVMEMetaData *)dynamicData.data())->methodCount++;
       
  2444         QDeclarativeVMEMetaData::MethodData methodData =
       
  2445              { s.parameterNames.count(), 0, funcScript.length(), s.location.start.line };
       
  2446 
       
  2447         dynamicData.append((char *)&methodData, sizeof(methodData));
       
  2448     }
       
  2449 
       
  2450     for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) {
       
  2451         const QString &funcScript = funcScripts.at(ii);
       
  2452         QDeclarativeVMEMetaData::MethodData *data =
       
  2453             ((QDeclarativeVMEMetaData *)dynamicData.data())->methodData() + ii;
       
  2454 
       
  2455         data->bodyOffset = dynamicData.size();
       
  2456 
       
  2457         dynamicData.append((const char *)funcScript.constData(),
       
  2458                            (funcScript.length() * sizeof(QChar)));
       
  2459     }
       
  2460 
       
  2461     obj->metadata = builder.toRelocatableData();
       
  2462     builder.fromRelocatableData(&obj->extObject, obj->metatype, obj->metadata);
       
  2463 
       
  2464     if (mode == IgnoreAliases && hasAlias)
       
  2465         compileState.aliasingObjects << obj;
       
  2466 
       
  2467     obj->synthdata = dynamicData;
       
  2468 
       
  2469     return true;
       
  2470 }
       
  2471 
       
  2472 bool QDeclarativeCompiler::checkValidId(QDeclarativeParser::Value *v, const QString &val)
       
  2473 {
       
  2474     if (val.isEmpty()) 
       
  2475         COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
       
  2476 
       
  2477     if (val.at(0).isLetter() && !val.at(0).isLower()) 
       
  2478         COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
       
  2479 
       
  2480     QChar u(QLatin1Char('_'));
       
  2481     for (int ii = 0; ii < val.count(); ++ii) {
       
  2482 
       
  2483         if (ii == 0 && !val.at(ii).isLetter() && val.at(ii) != u) {
       
  2484             COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
       
  2485         } else if (ii != 0 && !val.at(ii).isLetterOrNumber() && val.at(ii) != u)  {
       
  2486             COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
       
  2487         }
       
  2488 
       
  2489     }
       
  2490 
       
  2491     if (enginePrivate->globalClass->illegalNames().contains(val))
       
  2492         COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
       
  2493 
       
  2494     return true;
       
  2495 }
       
  2496 
       
  2497 #include <qdeclarativejsparser_p.h>
       
  2498 
       
  2499 static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node)
       
  2500 {
       
  2501     if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) {
       
  2502         QString name =
       
  2503             static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name->asString();
       
  2504         return QStringList() << name;
       
  2505     } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) {
       
  2506         QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node);
       
  2507 
       
  2508         QStringList rv = astNodeToStringList(expr->base);
       
  2509         if (rv.isEmpty())
       
  2510             return rv;
       
  2511         rv.append(expr->name->asString());
       
  2512         return rv;
       
  2513     }
       
  2514     return QStringList();
       
  2515 }
       
  2516 
       
  2517 bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder,
       
  2518                                QByteArray &data,
       
  2519                                Object *obj,
       
  2520                                const Object::DynamicProperty &prop)
       
  2521 {
       
  2522     if (!prop.defaultValue)
       
  2523         COMPILE_EXCEPTION(obj, tr("No property alias location"));
       
  2524 
       
  2525     if (prop.defaultValue->values.count() != 1 ||
       
  2526         prop.defaultValue->values.at(0)->object ||
       
  2527         !prop.defaultValue->values.at(0)->value.isScript())
       
  2528         COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
       
  2529 
       
  2530     QDeclarativeJS::AST::Node *node = prop.defaultValue->values.at(0)->value.asAST();
       
  2531     if (!node)
       
  2532         COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
       
  2533 
       
  2534     QStringList alias = astNodeToStringList(node);
       
  2535 
       
  2536     if (alias.count() != 1 && alias.count() != 2)
       
  2537         COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id> or <id>.<property>"));
       
  2538 
       
  2539     if (!compileState.ids.contains(alias.at(0)))
       
  2540         COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
       
  2541 
       
  2542     Object *idObject = compileState.ids[alias.at(0)];
       
  2543 
       
  2544     QByteArray typeName;
       
  2545 
       
  2546     int propIdx = -1;
       
  2547     int flags = 0;
       
  2548     bool writable = false;
       
  2549     if (alias.count() == 2) {
       
  2550         propIdx = idObject->metaObject()->indexOfProperty(alias.at(1).toUtf8().constData());
       
  2551 
       
  2552         if (-1 == propIdx)
       
  2553             COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
       
  2554 
       
  2555         QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
       
  2556         writable = aliasProperty.isWritable();
       
  2557 
       
  2558         if (aliasProperty.isEnumType()) 
       
  2559             typeName = "int";  // Avoid introducing a dependency on the aliased metaobject
       
  2560         else
       
  2561             typeName = aliasProperty.typeName();
       
  2562     } else {
       
  2563         typeName = idObject->metaObject()->className();
       
  2564 
       
  2565         //use the base type since it has been registered with metatype system
       
  2566         int index = typeName.indexOf("_QML_");
       
  2567         if (index != -1) {
       
  2568             typeName = typeName.left(index);
       
  2569         } else {
       
  2570             index = typeName.indexOf("_QMLTYPE_");
       
  2571             const QMetaObject *mo = idObject->metaObject();
       
  2572             while (index != -1 && mo) {
       
  2573                 typeName = mo->superClass()->className();
       
  2574                 index = typeName.indexOf("_QMLTYPE_");
       
  2575                 mo = mo->superClass();
       
  2576             }
       
  2577         }
       
  2578 
       
  2579         typeName += '*';
       
  2580     }
       
  2581 
       
  2582     if (typeName.endsWith('*'))
       
  2583         flags |= QML_ALIAS_FLAG_PTR;
       
  2584 
       
  2585     data.append((const char *)&idObject->idIndex, sizeof(idObject->idIndex));
       
  2586     data.append((const char *)&propIdx, sizeof(propIdx));
       
  2587     data.append((const char *)&flags, sizeof(flags));
       
  2588 
       
  2589     builder.addSignal(prop.name + "Changed()");
       
  2590     QMetaPropertyBuilder propBuilder = 
       
  2591         builder.addProperty(prop.name, typeName.constData(), builder.methodCount() - 1);
       
  2592     propBuilder.setScriptable(true);
       
  2593     propBuilder.setWritable(writable);
       
  2594     return true;
       
  2595 }
       
  2596 
       
  2597 bool QDeclarativeCompiler::buildBinding(QDeclarativeParser::Value *value,
       
  2598                                QDeclarativeParser::Property *prop,
       
  2599                                const BindingContext &ctxt)
       
  2600 {
       
  2601     Q_ASSERT(prop->index != -1);
       
  2602     Q_ASSERT(prop->parent);
       
  2603     Q_ASSERT(prop->parent->metaObject());
       
  2604 
       
  2605     QMetaProperty mp = prop->parent->metaObject()->property(prop->index);
       
  2606     if (!mp.isWritable() && !QDeclarativeMetaType::isList(prop->type))
       
  2607         COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name)));
       
  2608 
       
  2609     BindingReference reference;
       
  2610     reference.expression = value->value;
       
  2611     reference.property = prop;
       
  2612     reference.value = value;
       
  2613     reference.bindingContext = ctxt;
       
  2614     addBindingReference(reference);
       
  2615 
       
  2616     return true;
       
  2617 }
       
  2618 
       
  2619 void QDeclarativeCompiler::genBindingAssignment(QDeclarativeParser::Value *binding,
       
  2620                                                 QDeclarativeParser::Property *prop,
       
  2621                                                 QDeclarativeParser::Object *obj,
       
  2622                                                 QDeclarativeParser::Property *valueTypeProperty)
       
  2623 {
       
  2624     Q_UNUSED(obj);
       
  2625     Q_ASSERT(compileState.bindings.contains(binding));
       
  2626 
       
  2627     const BindingReference &ref = compileState.bindings.value(binding);
       
  2628     if (ref.dataType == BindingReference::Experimental) {
       
  2629         QDeclarativeInstruction store;
       
  2630         store.type = QDeclarativeInstruction::StoreCompiledBinding;
       
  2631         store.assignBinding.value = ref.compiledIndex;
       
  2632         store.assignBinding.context = ref.bindingContext.stack;
       
  2633         store.assignBinding.owner = ref.bindingContext.owner;
       
  2634         if (valueTypeProperty) 
       
  2635             store.assignBinding.property = (valueTypeProperty->index & 0xFFFF) |
       
  2636                                            ((valueTypeProperty->type & 0xFF)) << 16 |
       
  2637                                            ((prop->index & 0xFF) << 24);
       
  2638         else 
       
  2639             store.assignBinding.property = prop->index;
       
  2640         store.line = binding->location.start.line;
       
  2641         output->bytecode << store;
       
  2642         return;
       
  2643     }
       
  2644 
       
  2645     QDeclarativeInstruction store;
       
  2646     store.type = QDeclarativeInstruction::StoreBinding;
       
  2647     store.assignBinding.value = output->indexForByteArray(ref.compiledData);
       
  2648     store.assignBinding.context = ref.bindingContext.stack;
       
  2649     store.assignBinding.owner = ref.bindingContext.owner;
       
  2650     store.line = binding->location.start.line;
       
  2651 
       
  2652     Q_ASSERT(ref.bindingContext.owner == 0 ||
       
  2653              (ref.bindingContext.owner != 0 && valueTypeProperty));
       
  2654     if (ref.bindingContext.owner) {
       
  2655         store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
       
  2656     } else {
       
  2657         store.assignBinding.property = genPropertyData(prop);
       
  2658     }
       
  2659 
       
  2660     output->bytecode << store;
       
  2661 }
       
  2662 
       
  2663 int QDeclarativeCompiler::genContextCache()
       
  2664 {
       
  2665     if (compileState.ids.count() == 0)
       
  2666         return -1;
       
  2667 
       
  2668     QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache(engine);
       
  2669 
       
  2670     for (QHash<QString, QDeclarativeParser::Object *>::ConstIterator iter = compileState.ids.begin();
       
  2671          iter != compileState.ids.end();
       
  2672          ++iter) 
       
  2673         cache->add(iter.key(), (*iter)->idIndex);
       
  2674 
       
  2675     output->contextCaches.append(cache);
       
  2676     return output->contextCaches.count() - 1;
       
  2677 }
       
  2678 
       
  2679 int QDeclarativeCompiler::genValueTypeData(QDeclarativeParser::Property *valueTypeProp, 
       
  2680                                   QDeclarativeParser::Property *prop)
       
  2681 {
       
  2682     QByteArray data =
       
  2683         QDeclarativePropertyPrivate::saveValueType(prop->parent->metaObject(), prop->index, 
       
  2684                                                    enginePrivate->valueTypes[prop->type]->metaObject(), 
       
  2685                                                    valueTypeProp->index);
       
  2686 //                valueTypeProp->index, valueTypeProp->type);
       
  2687 
       
  2688     return output->indexForByteArray(data);
       
  2689 }
       
  2690 
       
  2691 int QDeclarativeCompiler::genPropertyData(QDeclarativeParser::Property *prop)
       
  2692 {
       
  2693     return output->indexForByteArray(QDeclarativePropertyPrivate::saveProperty(prop->parent->metaObject(), prop->index));
       
  2694 }
       
  2695 
       
  2696 bool QDeclarativeCompiler::completeComponentBuild()
       
  2697 {
       
  2698     componentStat.ids = compileState.ids.count();
       
  2699 
       
  2700     for (int ii = 0; ii < compileState.aliasingObjects.count(); ++ii) {
       
  2701         Object *aliasObject = compileState.aliasingObjects.at(ii);
       
  2702         COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
       
  2703     }
       
  2704 
       
  2705     QDeclarativeBindingCompiler::Expression expr;
       
  2706     expr.component = compileState.root;
       
  2707     expr.ids = compileState.ids;
       
  2708 
       
  2709     QDeclarativeBindingCompiler bindingCompiler;
       
  2710 
       
  2711     for (QHash<QDeclarativeParser::Value*,BindingReference>::Iterator iter = compileState.bindings.begin(); 
       
  2712          iter != compileState.bindings.end(); ++iter) {
       
  2713 
       
  2714         BindingReference &binding = *iter;
       
  2715 
       
  2716         expr.context = binding.bindingContext.object;
       
  2717         expr.property = binding.property;
       
  2718         expr.expression = binding.expression;
       
  2719         expr.imports = unit->imports;
       
  2720 
       
  2721         int index = bindingCompiler.compile(expr, enginePrivate);
       
  2722         if (index != -1) {
       
  2723             binding.dataType = BindingReference::Experimental;
       
  2724             binding.compiledIndex = index;
       
  2725             componentStat.optimizedBindings.append(iter.key()->location);
       
  2726             continue;
       
  2727         } 
       
  2728 
       
  2729         binding.dataType = BindingReference::QtScript;
       
  2730 
       
  2731         // Pre-rewrite the expression
       
  2732         QString expression = binding.expression.asScript();
       
  2733 
       
  2734         // ### Optimize
       
  2735         QDeclarativeRewrite::SharedBindingTester sharableTest;
       
  2736         bool isSharable = sharableTest.isSharable(expression);
       
  2737         
       
  2738         QDeclarativeRewrite::RewriteBinding rewriteBinding;
       
  2739         expression = rewriteBinding(expression);
       
  2740 
       
  2741         quint32 length = expression.length();
       
  2742         quint32 pc; 
       
  2743         
       
  2744         if (isSharable) {
       
  2745             pc = output->cachedClosures.count();
       
  2746             pc |= 0x80000000;
       
  2747             output->cachedClosures.append(0);
       
  2748         } else {
       
  2749             pc = output->cachedPrograms.length();
       
  2750             output->cachedPrograms.append(0);
       
  2751         }
       
  2752 
       
  2753         binding.compiledData =
       
  2754             QByteArray((const char *)&pc, sizeof(quint32)) +
       
  2755             QByteArray((const char *)&length, sizeof(quint32)) +
       
  2756             QByteArray((const char *)expression.constData(), 
       
  2757                        expression.length() * sizeof(QChar));
       
  2758 
       
  2759         componentStat.scriptBindings.append(iter.key()->location);
       
  2760     }
       
  2761 
       
  2762     if (bindingCompiler.isValid()) {
       
  2763         compileState.compiledBindingData = bindingCompiler.program();
       
  2764         if (bindingsDump()) 
       
  2765             QDeclarativeBindingCompiler::dump(compileState.compiledBindingData);
       
  2766     }
       
  2767 
       
  2768     saveComponentState();
       
  2769 
       
  2770     return true;
       
  2771 }
       
  2772 
       
  2773 void QDeclarativeCompiler::dumpStats()
       
  2774 {
       
  2775     qWarning().nospace() << "QML Document: " << output->url.toString();
       
  2776     for (int ii = 0; ii < savedComponentStats.count(); ++ii) {
       
  2777         const ComponentStat &stat = savedComponentStats.at(ii);
       
  2778         qWarning().nospace() << "    Component Line " << stat.lineNumber;
       
  2779         qWarning().nospace() << "        Total Objects:      " << stat.objects;
       
  2780         qWarning().nospace() << "        IDs Used:           " << stat.ids;
       
  2781         qWarning().nospace() << "        Optimized Bindings: " << stat.optimizedBindings.count();
       
  2782 
       
  2783         {
       
  2784         QByteArray output;
       
  2785         for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
       
  2786             if (0 == (ii % 10)) {
       
  2787                 if (ii) output.append("\n");
       
  2788                 output.append("            ");
       
  2789             }
       
  2790 
       
  2791             output.append("(");
       
  2792             output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
       
  2793             output.append(":");
       
  2794             output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
       
  2795             output.append(") ");
       
  2796         }
       
  2797         if (!output.isEmpty())
       
  2798             qWarning().nospace() << output.constData();
       
  2799         }
       
  2800 
       
  2801         qWarning().nospace() << "        QScript Bindings:   " << stat.scriptBindings.count();
       
  2802         {
       
  2803         QByteArray output;
       
  2804         for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
       
  2805             if (0 == (ii % 10)) {
       
  2806                 if (ii) output.append("\n");
       
  2807                 output.append("            ");
       
  2808             }
       
  2809 
       
  2810             output.append("(");
       
  2811             output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
       
  2812             output.append(":");
       
  2813             output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
       
  2814             output.append(") ");
       
  2815         }
       
  2816         if (!output.isEmpty())
       
  2817             qWarning().nospace() << output.constData();
       
  2818         }
       
  2819     }
       
  2820 }
       
  2821 
       
  2822 /*!
       
  2823     Returns true if from can be assigned to a (QObject) property of type
       
  2824     to.
       
  2825 */
       
  2826 bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeParser::Object *from)
       
  2827 {
       
  2828     const QMetaObject *toMo = 
       
  2829         enginePrivate->rawMetaObjectForType(to);
       
  2830     const QMetaObject *fromMo = from->metaObject();
       
  2831 
       
  2832     while (fromMo) {
       
  2833         if (QDeclarativePropertyPrivate::equal(fromMo, toMo))
       
  2834             return true;
       
  2835         fromMo = fromMo->superClass();
       
  2836     }
       
  2837     return false;
       
  2838 }
       
  2839 
       
  2840 QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeParser::Object *from)
       
  2841 {
       
  2842     // ### Optimize
       
  2843     const QMetaObject *mo = from->metatype;
       
  2844     QDeclarativeType *type = 0;
       
  2845     while (!type && mo) {
       
  2846         type = QDeclarativeMetaType::qmlType(mo);
       
  2847         mo = mo->superClass();
       
  2848     }
       
  2849    return type;
       
  2850 }
       
  2851 
       
  2852 QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeParser::Object *obj)
       
  2853 {
       
  2854     const QMetaObject *mo = obj->metatype;
       
  2855 
       
  2856     int idx = mo->indexOfClassInfo("DeferredPropertyNames");
       
  2857     if (idx == -1)
       
  2858         return QStringList();
       
  2859 
       
  2860     QMetaClassInfo classInfo = mo->classInfo(idx);
       
  2861     QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
       
  2862     return rv;
       
  2863 }
       
  2864 
       
  2865 QT_END_NAMESPACE