1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "private/qdeclarativecompiler_p.h"
44 #include "qdeclarativepropertyvaluesource.h"
45 #include "qdeclarativecomponent.h"
46 #include "private/qmetaobjectbuilder_p.h"
47 #include "private/qfastmetabuilder_p.h"
48 #include "private/qdeclarativestringconverters_p.h"
49 #include "private/qdeclarativeengine_p.h"
50 #include "qdeclarativeengine.h"
51 #include "qdeclarativecontext.h"
52 #include "private/qdeclarativemetatype_p.h"
53 #include "private/qdeclarativecustomparser_p_p.h"
54 #include "private/qdeclarativecontext_p.h"
55 #include "private/qdeclarativecomponent_p.h"
56 #include "parser/qdeclarativejsast_p.h"
57 #include "private/qdeclarativevmemetaobject_p.h"
58 #include "private/qdeclarativeexpression_p.h"
59 #include "private/qdeclarativeproperty_p.h"
60 #include "private/qdeclarativerewrite_p.h"
61 #include "qdeclarativescriptstring.h"
62 #include "private/qdeclarativeglobal_p.h"
63 #include "private/qdeclarativebinding_p.h"
64 #include "private/qdeclarativev4compiler_p.h"
65 #include "private/qdeclarativeutils_p.h"
73 #include <QtCore/qdebug.h>
74 #include <QtCore/qdatetime.h>
78 DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP);
79 DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS);
81 using namespace QDeclarativeScript;
82 using namespace QDeclarativeCompilerTypes;
84 static QString id_string(QLatin1String("id"));
85 static QString on_string(QLatin1String("on"));
86 static QString Changed_string(QLatin1String("Changed"));
87 static QString Component_string(QLatin1String("Component"));
90 Instantiate a new QDeclarativeCompiler.
92 QDeclarativeCompiler::QDeclarativeCompiler(QDeclarativePool *pool)
93 : pool(pool), output(0), engine(0), unitRoot(0), unit(0), componentStats(0)
95 if (compilerStatDump())
96 componentStats = pool->New<ComponentStats>();
100 Returns true if the last call to compile() caused errors.
104 bool QDeclarativeCompiler::isError() const
106 return !exceptions.isEmpty();
110 Return the list of errors from the last call to compile(), or an empty list
111 if there were no errors.
113 QList<QDeclarativeError> QDeclarativeCompiler::errors() const
119 Returns true if \a name refers to an attached property, false otherwise.
121 Attached property names are those that start with a capital letter.
123 bool QDeclarativeCompiler::isAttachedPropertyName(const QString &name)
125 return isAttachedPropertyName(QHashedStringRef(&name));
128 bool QDeclarativeCompiler::isAttachedPropertyName(const QHashedStringRef &name)
130 return !name.isEmpty() && QDeclarativeUtils::isUpper(name.at(0));
134 Returns true if \a name refers to a signal property, false otherwise.
136 Signal property names are those that start with "on", followed by a first
137 character which is either a capital letter or one or more underscores followed
138 by a capital letter, which is then followed by other allowed characters.
140 Note that although ECMA-262r3 supports dollarsigns and escaped unicode
141 character codes in property names, for simplicity and performance reasons
142 QML only supports letters, numbers and underscores.
144 bool QDeclarativeCompiler::isSignalPropertyName(const QString &name)
146 return isSignalPropertyName(QStringRef(&name));
149 bool QDeclarativeCompiler::isSignalPropertyName(const QHashedStringRef &name)
151 if (name.length() < 3) return false;
152 if (!name.startsWith(on_string)) return false;
153 int ns = name.length();
154 for (int i = 2; i < ns; ++i) {
155 const QChar curr = name.at(i);
156 if (curr.unicode() == '_') continue;
157 if (QDeclarativeUtils::isUpper(curr)) return true;
160 return false; // consists solely of underscores - invalid.
164 \macro COMPILE_EXCEPTION
166 Inserts an error into the QDeclarativeCompiler error list, and returns false
169 \a token is used to source the error line and column, and \a desc is the
170 error itself. \a desc can be an expression that can be piped into QDebug.
175 COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(property->name));
178 #define COMPILE_EXCEPTION(token, desc) \
180 QString exceptionDescription; \
181 QDeclarativeError error; \
182 error.setUrl(output->url); \
183 error.setLine((token)->location.start.line); \
184 error.setColumn((token)->location.start.column); \
185 error.setDescription(desc.trimmed()); \
186 exceptions << error; \
193 Returns false if \a is false, otherwise does nothing.
195 #define COMPILE_CHECK(a) \
197 if (!a) return false; \
201 Returns true if literal \a v can be assigned to property \a prop, otherwise
204 This test corresponds to action taken by genLiteralAssignment(). Any change
205 made here, must have a corresponding action in genLiteralAssigment().
207 bool QDeclarativeCompiler::testLiteralAssignment(QDeclarativeScript::Property *prop,
208 QDeclarativeScript::Value *v)
210 const QDeclarativeScript::Variant &value = v->value;
212 if (!prop->core.isWritable())
213 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
215 if (prop->core.isEnum()) {
216 QMetaProperty p = prop->parent->metaObject()->property(prop->index);
218 if (p.isFlagType()) {
219 enumValue = p.enumerator().keysToValue(value.asString().toUtf8().constData());
221 enumValue = p.enumerator().keyToValue(value.asString().toUtf8().constData());
224 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration"));
226 v->value = QDeclarativeScript::Variant((double)enumValue);
230 int type = prop->type;
233 case QMetaType::QVariant:
235 case QVariant::String:
236 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
238 case QVariant::ByteArray:
239 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected"));
242 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected"));
246 bool ok = v->value.isNumber();
248 double n = v->value.asNumber();
249 if (double(uint(n)) != n)
252 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected"));
257 bool ok = v->value.isNumber();
259 double n = v->value.asNumber();
260 if (double(int(n)) != n)
263 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected"));
266 case QMetaType::Float:
267 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
269 case QVariant::Double:
270 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
272 case QVariant::Color:
275 QDeclarativeStringConverters::colorFromString(value.asString(), &ok);
276 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected"));
279 #ifndef QT_NO_DATESTRING
283 QDeclarativeStringConverters::dateFromString(value.asString(), &ok);
284 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected"));
290 QDeclarativeStringConverters::timeFromString(value.asString(), &ok);
291 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected"));
294 case QVariant::DateTime:
297 QDeclarativeStringConverters::dateTimeFromString(value.asString(), &ok);
298 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected"));
301 #endif // QT_NO_DATESTRING
302 case QVariant::Point:
303 case QVariant::PointF:
306 QPointF point = QDeclarativeStringConverters::pointFFromString(value.asString(), &ok);
307 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected"));
311 case QVariant::SizeF:
314 QSizeF size = QDeclarativeStringConverters::sizeFFromString(value.asString(), &ok);
315 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected"));
319 case QVariant::RectF:
322 QRectF rect = QDeclarativeStringConverters::rectFFromString(value.asString(), &ok);
323 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected"));
328 if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected"));
331 case QVariant::Vector3D:
334 QDeclarativeStringConverters::vector3DFromString(value.asString(), &ok);
335 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected"));
338 case QVariant::Vector4D:
341 QDeclarativeStringConverters::vector4DFromString(value.asString(), &ok);
342 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 4D vector expected"));
347 QDeclarativeMetaType::StringConverter converter = QDeclarativeMetaType::customStringConverter(type);
349 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName((QVariant::Type)type))));
357 Generate a store instruction for assigning literal \a v to property \a prop.
359 Any literal assignment that is approved in testLiteralAssignment() must have
360 a corresponding action in this method.
362 void QDeclarativeCompiler::genLiteralAssignment(QDeclarativeScript::Property *prop,
363 QDeclarativeScript::Value *v)
365 QDeclarativeInstruction instr;
367 if (prop->core.isEnum()) {
368 Q_ASSERT(v->value.isNumber());
370 int value = (int)v->value.asNumber();
372 instr.setType(QDeclarativeInstruction::StoreInteger);
373 instr.storeInteger.propertyIndex = prop->index;
374 instr.storeInteger.value = value;
375 output->addInstruction(instr);
379 int type = prop->type;
381 case QMetaType::QVariant:
383 if (v->value.isNumber()) {
384 double n = v->value.asNumber();
385 if (double(int(n)) == n) {
386 instr.setType(QDeclarativeInstruction::StoreVariantInteger);
387 instr.storeInteger.propertyIndex = prop->index;
388 instr.storeInteger.value = int(n);
390 instr.setType(QDeclarativeInstruction::StoreVariantDouble);
391 instr.storeDouble.propertyIndex = prop->index;
392 instr.storeDouble.value = n;
394 } else if(v->value.isBoolean()) {
395 instr.setType(QDeclarativeInstruction::StoreVariantBool);
396 instr.storeBool.propertyIndex = prop->index;
397 instr.storeBool.value = v->value.asBoolean();
399 instr.setType(QDeclarativeInstruction::StoreVariant);
400 instr.storeString.propertyIndex = prop->index;
401 instr.storeString.value = output->indexForString(v->value.asString());
405 case QVariant::String:
407 instr.setType(QDeclarativeInstruction::StoreString);
408 instr.storeString.propertyIndex = prop->index;
409 instr.storeString.value = output->indexForString(v->value.asString());
412 case QVariant::ByteArray:
414 instr.setType(QDeclarativeInstruction::StoreByteArray);
415 instr.storeByteArray.propertyIndex = prop->index;
416 instr.storeByteArray.value = output->indexForByteArray(v->value.asString().toLatin1());
421 instr.setType(QDeclarativeInstruction::StoreUrl);
422 QString string = v->value.asString();
423 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
424 instr.storeUrl.propertyIndex = prop->index;
425 instr.storeUrl.value = output->indexForUrl(u);
430 instr.setType(QDeclarativeInstruction::StoreInteger);
431 instr.storeInteger.propertyIndex = prop->index;
432 instr.storeInteger.value = uint(v->value.asNumber());
437 instr.setType(QDeclarativeInstruction::StoreInteger);
438 instr.storeInteger.propertyIndex = prop->index;
439 instr.storeInteger.value = int(v->value.asNumber());
442 case QMetaType::Float:
444 instr.setType(QDeclarativeInstruction::StoreFloat);
445 instr.storeFloat.propertyIndex = prop->index;
446 instr.storeFloat.value = float(v->value.asNumber());
449 case QVariant::Double:
451 instr.setType(QDeclarativeInstruction::StoreDouble);
452 instr.storeDouble.propertyIndex = prop->index;
453 instr.storeDouble.value = v->value.asNumber();
456 case QVariant::Color:
458 QColor c = QDeclarativeStringConverters::colorFromString(v->value.asString());
459 instr.setType(QDeclarativeInstruction::StoreColor);
460 instr.storeColor.propertyIndex = prop->index;
461 instr.storeColor.value = c.rgba();
464 #ifndef QT_NO_DATESTRING
467 QDate d = QDeclarativeStringConverters::dateFromString(v->value.asString());
468 instr.setType(QDeclarativeInstruction::StoreDate);
469 instr.storeDate.propertyIndex = prop->index;
470 instr.storeDate.value = d.toJulianDay();
475 QTime time = QDeclarativeStringConverters::timeFromString(v->value.asString());
476 instr.setType(QDeclarativeInstruction::StoreTime);
477 instr.storeTime.propertyIndex = prop->index;
478 Q_ASSERT(sizeof(instr.storeTime.time) == sizeof(QTime));
479 ::memcpy(&instr.storeTime.time, &time, sizeof(QTime)); }
482 case QVariant::DateTime:
484 QDateTime dateTime = QDeclarativeStringConverters::dateTimeFromString(v->value.asString());
485 QTime time = dateTime.time();
486 instr.setType(QDeclarativeInstruction::StoreDateTime);
487 instr.storeDateTime.propertyIndex = prop->index;
488 instr.storeDateTime.date = dateTime.date().toJulianDay();
489 Q_ASSERT(sizeof(instr.storeDateTime.time) == sizeof(QTime));
490 ::memcpy(&instr.storeDateTime.time, &time, sizeof(QTime));
493 #endif // QT_NO_DATESTRING
494 case QVariant::Point:
497 QPoint point = QDeclarativeStringConverters::pointFFromString(v->value.asString(), &ok).toPoint();
498 instr.setType(QDeclarativeInstruction::StorePoint);
499 instr.storePoint.propertyIndex = prop->index;
500 instr.storePoint.point.xp = point.x();
501 instr.storePoint.point.yp = point.y();
504 case QVariant::PointF:
507 QPointF point = QDeclarativeStringConverters::pointFFromString(v->value.asString(), &ok);
508 instr.setType(QDeclarativeInstruction::StorePointF);
509 instr.storePointF.propertyIndex = prop->index;
510 instr.storePointF.point.xp = point.x();
511 instr.storePointF.point.yp = point.y();
517 QSize size = QDeclarativeStringConverters::sizeFFromString(v->value.asString(), &ok).toSize();
518 instr.setType(QDeclarativeInstruction::StoreSize);
519 instr.storeSize.propertyIndex = prop->index;
520 instr.storeSize.size.wd = size.width();
521 instr.storeSize.size.ht = size.height();
524 case QVariant::SizeF:
527 QSizeF size = QDeclarativeStringConverters::sizeFFromString(v->value.asString(), &ok);
528 instr.setType(QDeclarativeInstruction::StoreSizeF);
529 instr.storeSizeF.propertyIndex = prop->index;
530 instr.storeSizeF.size.wd = size.width();
531 instr.storeSizeF.size.ht = size.height();
537 QRect rect = QDeclarativeStringConverters::rectFFromString(v->value.asString(), &ok).toRect();
538 instr.setType(QDeclarativeInstruction::StoreRect);
539 instr.storeRect.propertyIndex = prop->index;
540 instr.storeRect.rect.x1 = rect.left();
541 instr.storeRect.rect.y1 = rect.top();
542 instr.storeRect.rect.x2 = rect.right();
543 instr.storeRect.rect.y2 = rect.bottom();
546 case QVariant::RectF:
549 QRectF rect = QDeclarativeStringConverters::rectFFromString(v->value.asString(), &ok);
550 instr.setType(QDeclarativeInstruction::StoreRectF);
551 instr.storeRectF.propertyIndex = prop->index;
552 instr.storeRectF.rect.xp = rect.left();
553 instr.storeRectF.rect.yp = rect.top();
554 instr.storeRectF.rect.w = rect.width();
555 instr.storeRectF.rect.h = rect.height();
560 bool b = v->value.asBoolean();
561 instr.setType(QDeclarativeInstruction::StoreBool);
562 instr.storeBool.propertyIndex = prop->index;
563 instr.storeBool.value = b;
566 case QVariant::Vector3D:
569 QVector3D vector = QDeclarativeStringConverters::vector3DFromString(v->value.asString(), &ok);
570 instr.setType(QDeclarativeInstruction::StoreVector3D);
571 instr.storeVector3D.propertyIndex = prop->index;
572 instr.storeVector3D.vector.xp = vector.x();
573 instr.storeVector3D.vector.yp = vector.y();
574 instr.storeVector3D.vector.zp = vector.z();
577 case QVariant::Vector4D:
580 QVector4D vector = QDeclarativeStringConverters::vector4DFromString(v->value.asString(), &ok);
581 instr.setType(QDeclarativeInstruction::StoreVector4D);
582 instr.storeVector4D.propertyIndex = prop->index;
583 instr.storeVector4D.vector.xp = vector.x();
584 instr.storeVector4D.vector.yp = vector.y();
585 instr.storeVector4D.vector.zp = vector.z();
586 instr.storeVector4D.vector.wp = vector.w();
591 instr.setType(QDeclarativeInstruction::AssignCustomType);
592 instr.assignCustomType.propertyIndex = prop->index;
593 instr.assignCustomType.primitive = output->indexForString(v->value.asString());
594 instr.assignCustomType.type = type;
598 output->addInstruction(instr);
602 Resets data by clearing the lists that the QDeclarativeCompiler modifies.
604 void QDeclarativeCompiler::reset(QDeclarativeCompiledData *data)
607 data->primitives.clear();
609 data->bytecode.resize(0);
613 Compile \a unit, and store the output in \a out. \a engine is the QDeclarativeEngine
614 with which the QDeclarativeCompiledData will be associated.
616 Returns true on success, false on failure. On failure, the compile errors
617 are available from errors().
619 If the environment variant QML_COMPILER_DUMP is set
620 (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
621 on a successful compiler.
623 bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine,
624 QDeclarativeTypeData *unit,
625 QDeclarativeCompiledData *out)
635 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
636 QList<QDeclarativeScript::TypeReference *> referencedTypes = unit->parser().referencedTypes();
638 for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
639 QDeclarativeCompiledData::TypeReference ref;
641 const QDeclarativeTypeData::TypeReference &tref = resolvedTypes.at(ii);
642 QDeclarativeScript::TypeReference *parserRef = referencedTypes.at(ii);
645 ref.type = tref.type;
646 if (!ref.type->isCreatable()) {
647 QString err = ref.type->noCreationReason();
649 err = tr( "Element is not creatable.");
650 COMPILE_EXCEPTION(parserRef->refObjects.first(), err);
653 if (ref.type->containsRevisionedAttributes()) {
654 QDeclarativeError cacheError;
655 ref.typePropertyCache =
656 QDeclarativeEnginePrivate::get(engine)->cache(ref.type, resolvedTypes.at(ii).minorVersion, cacheError);
658 if (!ref.typePropertyCache) {
659 COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description());
661 ref.typePropertyCache->addref();
664 } else if (tref.typeData) {
665 ref.component = tref.typeData->compiledData();
667 ref.className = parserRef->name;
671 QDeclarativeScript::Object *root = unit->parser().tree();
674 this->engine = engine;
675 this->enginePrivate = QDeclarativeEnginePrivate::get(engine);
677 this->unitRoot = root;
682 out->dumpInstructions();
685 Q_ASSERT(out->rootPropertyCache);
693 this->enginePrivate = 0;
700 void QDeclarativeCompiler::compileTree(QDeclarativeScript::Object *tree)
702 compileState = pool->New<ComponentCompileState>();
704 compileState->root = tree;
706 componentStats->componentStat.lineNumber = tree->location.start.line;
708 // Build global import scripts
709 QStringList importedScriptIndexes;
711 foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
712 importedScriptIndexes.append(script.qualifier);
714 QDeclarativeInstruction import;
715 import.setType(QDeclarativeInstruction::StoreImportedScript);
716 import.storeScript.value = output->scripts.count();
718 QDeclarativeScriptData *scriptData = script.script->scriptData();
719 scriptData->addref();
720 output->scripts << scriptData;
721 output->addInstruction(import);
724 // We generate the importCache before we build the tree so that
725 // it can be used in the binding compiler. Given we "expect" the
726 // QML compilation to succeed, this isn't a waste.
727 output->importCache = new QDeclarativeTypeNameCache(engine);
728 for (int ii = 0; ii < importedScriptIndexes.count(); ++ii)
729 output->importCache->add(importedScriptIndexes.at(ii), ii);
730 unit->imports().populateCache(output->importCache, engine);
732 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
735 QDeclarativeInstruction init;
736 init.setType(QDeclarativeInstruction::Init);
737 init.init.bindingsSize = compileState->bindings.count();
738 init.init.parserStatusSize = compileState->parserStatusCount;
739 init.init.contextCache = genContextCache();
740 if (compileState->compiledBindingData.isEmpty())
741 init.init.compiledBinding = -1;
743 init.init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
744 output->addInstruction(init);
746 if (!compileState->v8BindingProgram.isEmpty()) {
747 QDeclarativeInstruction bindings;
748 bindings.setType(QDeclarativeInstruction::InitV8Bindings);
749 bindings.initV8Bindings.program = output->indexForString(compileState->v8BindingProgram);
750 bindings.initV8Bindings.programIndex = compileState->v8BindingProgramIndex;
751 bindings.initV8Bindings.line = compileState->v8BindingProgramLine;
752 output->addInstruction(bindings);
757 QDeclarativeInstruction def;
758 def.setType(QDeclarativeInstruction::SetDefault);
759 output->addInstruction(def);
761 QDeclarativeInstruction done;
762 done.setType(QDeclarativeInstruction::Done);
763 output->addInstruction(done);
765 Q_ASSERT(tree->metatype);
767 if (tree->metadata.isEmpty()) {
768 output->root = tree->metatype;
770 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
771 output->root = &output->rootData;
773 if (!tree->metadata.isEmpty())
774 enginePrivate->registerCompositeType(output);
777 static bool QStringList_contains(const QStringList &list, const QHashedStringRef &string)
779 for (int ii = 0; ii < list.count(); ++ii)
780 if (string == list.at(ii))
786 bool QDeclarativeCompiler::buildObject(QDeclarativeScript::Object *obj, const BindingContext &ctxt)
789 componentStats->componentStat.objects++;
791 Q_ASSERT (obj->type != -1);
792 const QDeclarativeCompiledData::TypeReference &tr =
793 output->types.at(obj->type);
794 obj->metatype = tr.metaObject();
797 obj->typeName = tr.type->qmlTypeName();
799 // This object is a "Component" element
800 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
801 COMPILE_CHECK(buildComponent(obj, ctxt));
805 // Object instantiations reset the binding context
806 BindingContext objCtxt(obj);
808 // Create the synthesized meta object, ignoring aliases
809 COMPILE_CHECK(checkDynamicMeta(obj));
810 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
811 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
813 // Find the native type and check for the QDeclarativeParserStatus interface
814 QDeclarativeType *type = toQmlType(obj);
816 obj->parserStatusCast = type->parserStatusCast();
817 if (obj->parserStatusCast != -1)
818 compileState->parserStatusCount++;
820 // Check if this is a custom parser type. Custom parser types allow
821 // assignments to non-existent properties. These assignments are then
822 // compiled by the type.
823 bool isCustomParser = output->types.at(obj->type).type &&
824 output->types.at(obj->type).type->customParser() != 0;
825 QList<QDeclarativeCustomParserProperty> customProps;
827 // Fetch the list of deferred properties
828 QStringList deferredList = deferredProperties(obj);
830 // Must do id property first. This is to ensure that the id given to any
831 // id reference created matches the order in which the objects are
833 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
834 if (prop->name() == id_string) {
835 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
841 Property *defaultProperty = 0;
842 Property *skipProperty = 0;
843 if (obj->defaultProperty) {
844 defaultProperty = obj->defaultProperty;
846 Property *explicitProperty = 0;
848 const QMetaObject *mo = obj->metatype;
849 int idx = mo->indexOfClassInfo("DefaultProperty");
851 QMetaClassInfo info = mo->classInfo(idx);
852 const char *p = info.value();
856 while (char c = p[plen++]) { ord |= c; };
860 // Utf8 - unoptimal, but seldom hit
861 QString *s = pool->NewString(QString::fromUtf8(p, plen));
862 QHashedStringRef r(*s);
864 if (obj->propertiesHashField.test(r.hash())) {
865 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
866 if (ep->name() == r) {
867 explicitProperty = ep;
873 if (!explicitProperty)
874 defaultProperty->setName(r);
877 QHashedCStringRef r(p, plen);
879 if (obj->propertiesHashField.test(r.hash())) {
880 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
881 if (ep->name() == r) {
882 explicitProperty = ep;
888 if (!explicitProperty) {
889 // Set the default property name
890 QChar *buffer = pool->NewRawArray<QChar>(r.length());
891 r.writeUtf16(buffer);
892 defaultProperty->setName(QHashedStringRef(buffer, r.length(), r.hash()));
898 if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) {
900 skipProperty = explicitProperty; // We merge the values into defaultProperty
902 // Find the correct insertion point
903 Value *insertPos = 0;
905 for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) {
906 if (!(v->location.start < explicitProperty->values.first()->location.start))
911 defaultProperty->values.insertAfter(insertPos, explicitProperty->values);
915 QDeclarativeCustomParser *cp = 0;
917 cp = output->types.at(obj->type).type->customParser();
919 // Build all explicit properties specified
920 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
922 if (prop == skipProperty)
924 if (prop->name() == id_string)
927 bool canDefer = false;
928 if (isCustomParser) {
929 if (doesPropertyExist(prop, obj) &&
930 (!(cp->flags() & QDeclarativeCustomParser::AcceptsAttachedProperties) ||
931 !isAttachedPropertyName(prop->name()))) {
932 int ids = compileState->ids.count();
933 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
934 canDefer = ids == compileState->ids.count();
935 } else if (isSignalPropertyName(prop->name()) &&
936 (cp->flags() & QDeclarativeCustomParser::AcceptsSignalHandlers)) {
937 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
939 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
942 if (isSignalPropertyName(prop->name())) {
943 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
945 int ids = compileState->ids.count();
946 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
947 canDefer = ids == compileState->ids.count();
951 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
952 prop->isDeferred = true;
956 // Build the default property
957 if (defaultProperty) {
958 Property *prop = defaultProperty;
960 bool canDefer = false;
961 if (isCustomParser) {
962 if (doesPropertyExist(prop, obj)) {
963 int ids = compileState->ids.count();
964 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
965 canDefer = ids == compileState->ids.count();
967 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
970 int ids = compileState->ids.count();
971 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
972 canDefer = ids == compileState->ids.count();
975 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
976 prop->isDeferred = true;
979 // Compile custom parser parts
980 if (isCustomParser && !customProps.isEmpty()) {
984 obj->custom = cp->compile(customProps);
987 foreach (QDeclarativeError err, cp->errors()) {
988 err.setUrl(output->url);
996 void QDeclarativeCompiler::genObject(QDeclarativeScript::Object *obj)
998 QDeclarativeCompiledData::TypeReference &tr = output->types[obj->type];
999 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
1004 // Create the object
1005 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
1006 !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) {
1008 QDeclarativeInstruction create;
1009 create.setType(QDeclarativeInstruction::CreateSimpleObject);
1010 create.createSimple.create = output->types.at(obj->type).type->createFunction();
1011 create.createSimple.typeSize = output->types.at(obj->type).type->createSize();
1012 create.createSimple.type = obj->type;
1013 create.createSimple.line = obj->location.start.line;
1014 create.createSimple.column = obj->location.start.column;
1015 output->addInstruction(create);
1019 QDeclarativeInstruction create;
1020 create.setType(QDeclarativeInstruction::CreateObject);
1021 create.create.line = obj->location.start.line;
1022 create.create.column = obj->location.start.column;
1023 create.create.data = -1;
1024 if (!obj->custom.isEmpty())
1025 create.create.data = output->indexForByteArray(obj->custom);
1026 create.create.type = obj->type;
1027 if (!output->types.at(create.create.type).type &&
1028 !obj->bindingBitmask.isEmpty()) {
1029 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
1030 create.create.bindingBits =
1031 output->indexForByteArray(obj->bindingBitmask);
1033 create.create.bindingBits = -1;
1035 output->addInstruction(create);
1039 // Setup the synthesized meta object if necessary
1040 if (!obj->metadata.isEmpty()) {
1041 QDeclarativeInstruction meta;
1042 meta.setType(QDeclarativeInstruction::StoreMetaObject);
1043 meta.storeMeta.data = output->indexForByteArray(obj->metadata);
1044 meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata);
1045 meta.storeMeta.propertyCache = output->propertyCaches.count();
1047 QDeclarativePropertyCache *propertyCache = obj->synthCache;
1048 Q_ASSERT(propertyCache);
1049 propertyCache->addref();
1051 // Add flag for alias properties
1052 if (!obj->synthdata.isEmpty()) {
1053 const QDeclarativeVMEMetaData *vmeMetaData =
1054 reinterpret_cast<const QDeclarativeVMEMetaData *>(obj->synthdata.constData());
1055 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
1056 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
1057 QDeclarativePropertyCache::Data *data = propertyCache->property(index);
1058 data->setFlags(data->getFlags() | QDeclarativePropertyCache::Data::IsAlias);
1062 if (obj == unitRoot) {
1063 propertyCache->addref();
1064 output->rootPropertyCache = propertyCache;
1067 output->propertyCaches << propertyCache;
1068 output->addInstruction(meta);
1069 } else if (obj == unitRoot) {
1070 output->rootPropertyCache = tr.createPropertyCache(engine);
1071 output->rootPropertyCache->addref();
1074 // Set the object id
1075 if (!obj->id.isEmpty()) {
1076 QDeclarativeInstruction id;
1077 id.setType(QDeclarativeInstruction::SetId);
1078 id.setId.value = output->indexForString(obj->id);
1079 id.setId.index = obj->idIndex;
1080 output->addInstruction(id);
1084 if (tr.type && obj->parserStatusCast != -1) {
1085 QDeclarativeInstruction begin;
1086 begin.setType(QDeclarativeInstruction::BeginObject);
1087 begin.begin.castValue = obj->parserStatusCast;
1088 output->addInstruction(begin);
1094 void QDeclarativeCompiler::genObjectBody(QDeclarativeScript::Object *obj)
1096 for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1097 Q_ASSERT(prop->scriptStringScope != -1);
1098 const QString &script = prop->values.first()->value.asScript();
1099 QDeclarativeInstruction ss;
1100 ss.setType(QDeclarativeInstruction::StoreScriptString);
1101 ss.storeScriptString.propertyIndex = prop->index;
1102 ss.storeScriptString.value = output->indexForString(script);
1103 ss.storeScriptString.scope = prop->scriptStringScope;
1104 // ss.storeScriptString.bindingId = rewriteBinding(script, prop->name());
1105 ss.storeScriptString.bindingId = rewriteBinding(script, QString()); // XXX
1106 ss.storeScriptString.line = prop->location.start.line;
1107 output->addInstruction(ss);
1110 bool seenDefer = false;
1111 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1112 if (prop->isDeferred) {
1117 genValueProperty(prop, obj);
1120 QDeclarativeInstruction defer;
1121 defer.setType(QDeclarativeInstruction::Defer);
1122 defer.defer.deferCount = 0;
1123 int deferIdx = output->addInstruction(defer);
1124 int nextInstructionIndex = output->nextInstructionIndex();
1126 QDeclarativeInstruction init;
1127 init.setType(QDeclarativeInstruction::Init);
1128 init.init.bindingsSize = compileState->bindings.count(); // XXX - bigger than necessary
1129 init.init.parserStatusSize = compileState->parserStatusCount; // XXX - bigger than necessary
1130 init.init.contextCache = -1;
1131 init.init.compiledBinding = -1;
1132 output->addInstruction(init);
1134 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1135 if (!prop->isDeferred)
1137 genValueProperty(prop, obj);
1140 QDeclarativeInstruction done;
1141 done.setType(QDeclarativeInstruction::Done);
1142 output->addInstruction(done);
1144 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1147 for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1149 QDeclarativeScript::Value *v = prop->values.first();
1151 if (v->type == Value::SignalObject) {
1153 genObject(v->object);
1155 QDeclarativeInstruction assign;
1156 assign.setType(QDeclarativeInstruction::AssignSignalObject);
1157 assign.assignSignalObject.line = v->location.start.line;
1158 assign.assignSignalObject.signal = output->indexForString(prop->name().toString());
1159 output->addInstruction(assign);
1161 } else if (v->type == Value::SignalExpression) {
1163 QDeclarativeInstruction store;
1164 store.setType(QDeclarativeInstruction::StoreSignal);
1165 store.storeSignal.signalIndex = prop->index;
1166 store.storeSignal.value =
1167 output->indexForString(v->value.asScript().trimmed());
1168 store.storeSignal.context = v->signalExpressionContextStack;
1169 store.storeSignal.name = output->indexForByteArray(prop->name().toUtf8());
1170 store.storeSignal.line = v->location.start.line;
1171 output->addInstruction(store);
1177 for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1178 QDeclarativeInstruction fetch;
1179 fetch.setType(QDeclarativeInstruction::FetchAttached);
1180 fetch.fetchAttached.id = prop->index;
1181 fetch.fetchAttached.line = prop->location.start.line;
1182 output->addInstruction(fetch);
1184 genObjectBody(prop->value);
1186 QDeclarativeInstruction pop;
1187 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1188 output->addInstruction(pop);
1191 for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1192 QDeclarativeInstruction fetch;
1193 fetch.setType(QDeclarativeInstruction::FetchObject);
1194 fetch.fetch.property = prop->index;
1195 fetch.fetch.line = prop->location.start.line;
1196 output->addInstruction(fetch);
1198 if (!prop->value->metadata.isEmpty()) {
1199 QDeclarativeInstruction meta;
1200 meta.setType(QDeclarativeInstruction::StoreMetaObject);
1201 meta.storeMeta.data = output->indexForByteArray(prop->value->metadata);
1202 meta.storeMeta.aliasData = output->indexForByteArray(prop->value->synthdata);
1203 meta.storeMeta.propertyCache = -1;
1204 output->addInstruction(meta);
1207 genObjectBody(prop->value);
1209 QDeclarativeInstruction pop;
1210 pop.setType(QDeclarativeInstruction::PopFetchedObject);
1211 output->addInstruction(pop);
1214 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1216 genValueTypeProperty(obj, prop);
1219 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1220 if (prop->isDeferred)
1223 genValueProperty(prop, obj);
1226 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1228 genValueTypeProperty(obj, prop);
1232 void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeScript::Object *obj,QDeclarativeScript::Property *prop)
1234 QDeclarativeInstruction fetch;
1235 fetch.setType(QDeclarativeInstruction::FetchValueType);
1236 fetch.fetchValue.property = prop->index;
1237 fetch.fetchValue.type = prop->type;
1238 fetch.fetchValue.bindingSkipList = 0;
1240 if (obj->type == -1 || output->types.at(obj->type).component) {
1241 // We only have to do this if this is a composite type. If it is a builtin
1242 // type it can't possibly already have bindings that need to be cleared.
1243 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1244 if (!vprop->values.isEmpty()) {
1245 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1246 fetch.fetchValue.bindingSkipList |= (1 << vprop->index);
1251 output->addInstruction(fetch);
1253 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1254 genPropertyAssignment(vprop, prop->value, prop);
1257 QDeclarativeInstruction pop;
1258 pop.setType(QDeclarativeInstruction::PopValueType);
1259 pop.fetchValue.property = prop->index;
1260 pop.fetchValue.type = prop->type;
1261 pop.fetchValue.bindingSkipList = 0;
1262 output->addInstruction(pop);
1265 void QDeclarativeCompiler::genComponent(QDeclarativeScript::Object *obj)
1267 QDeclarativeScript::Object *root = obj->defaultProperty->values.first()->object;
1270 QDeclarativeInstruction create;
1271 create.setType(QDeclarativeInstruction::CreateComponent);
1272 create.createComponent.line = root->location.start.line;
1273 create.createComponent.column = root->location.start.column;
1274 create.createComponent.endLine = root->location.end.line;
1275 int createInstruction = output->addInstruction(create);
1276 int nextInstructionIndex = output->nextInstructionIndex();
1278 ComponentCompileState *oldCompileState = compileState;
1279 compileState = componentState(root);
1281 QDeclarativeInstruction init;
1282 init.setType(QDeclarativeInstruction::Init);
1283 init.init.bindingsSize = compileState->bindings.count();
1284 init.init.parserStatusSize = compileState->parserStatusCount;
1285 init.init.contextCache = genContextCache();
1286 if (compileState->compiledBindingData.isEmpty())
1287 init.init.compiledBinding = -1;
1289 init.init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
1290 output->addInstruction(init);
1292 if (!compileState->v8BindingProgram.isEmpty()) {
1293 QDeclarativeInstruction bindings;
1294 bindings.setType(QDeclarativeInstruction::InitV8Bindings);
1295 bindings.initV8Bindings.program = output->indexForString(compileState->v8BindingProgram);
1296 bindings.initV8Bindings.programIndex = compileState->v8BindingProgramIndex;
1297 bindings.initV8Bindings.line = compileState->v8BindingProgramLine;
1298 output->addInstruction(bindings);
1303 QDeclarativeInstruction def;
1304 def.setType(QDeclarativeInstruction::SetDefault);
1305 output->addInstruction(def);
1307 QDeclarativeInstruction done;
1308 done.setType(QDeclarativeInstruction::Done);
1309 output->addInstruction(done);
1311 output->instruction(createInstruction)->createComponent.count =
1312 output->nextInstructionIndex() - nextInstructionIndex;
1314 compileState = oldCompileState;
1316 if (!obj->id.isEmpty()) {
1317 QDeclarativeInstruction id;
1318 id.setType(QDeclarativeInstruction::SetId);
1319 id.setId.value = output->indexForString(obj->id);
1320 id.setId.index = obj->idIndex;
1321 output->addInstruction(id);
1324 if (obj == unitRoot) {
1325 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1326 output->rootPropertyCache->addref();
1330 bool QDeclarativeCompiler::buildComponent(QDeclarativeScript::Object *obj,
1331 const BindingContext &ctxt)
1333 // The special "Component" element can only have the id property and a
1334 // default property, that actually defines the component's tree
1336 // Find, check and set the "id" property (if any)
1337 Property *idProp = 0;
1338 if (obj->properties.isMany() ||
1339 (obj->properties.isOne() && obj->properties.first()->name() != id_string))
1340 COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
1342 if (!obj->properties.isEmpty())
1343 idProp = obj->properties.first();
1346 if (idProp->value || idProp->values.isMany() || idProp->values.first()->object)
1347 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1348 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1350 QString idVal = idProp->values.first()->primitive();
1352 if (compileState->ids.value(idVal))
1353 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1359 // Check the Component tree is well formed
1360 if (obj->defaultProperty &&
1361 (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
1362 (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
1363 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1365 if (!obj->dynamicProperties.isEmpty())
1366 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1367 if (!obj->dynamicSignals.isEmpty())
1368 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1369 if (!obj->dynamicSlots.isEmpty())
1370 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1372 QDeclarativeScript::Object *root = 0;
1373 if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
1374 root = obj->defaultProperty->values.first()->object;
1377 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1379 // Build the component tree
1380 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1385 bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeScript::Object *obj,
1386 const BindingContext &ctxt)
1388 ComponentCompileState *oldComponentCompileState = compileState;
1389 compileState = pool->New<ComponentCompileState>();
1390 compileState->root = obj;
1391 compileState->nested = true;
1393 if (componentStats) {
1394 ComponentStat oldComponentStat = componentStats->componentStat;
1396 componentStats->componentStat = ComponentStat();
1397 componentStats->componentStat.lineNumber = obj->location.start.line;
1400 COMPILE_CHECK(buildObject(obj, ctxt));
1402 COMPILE_CHECK(completeComponentBuild());
1404 componentStats->componentStat = oldComponentStat;
1407 COMPILE_CHECK(buildObject(obj, ctxt));
1409 COMPILE_CHECK(completeComponentBuild());
1412 compileState = oldComponentCompileState;
1418 // Build a sub-object. A sub-object is one that was not created directly by
1419 // QML - such as a grouped property object, or an attached object. Sub-object's
1420 // can't have an id, involve a custom parser, have attached properties etc.
1421 bool QDeclarativeCompiler::buildSubObject(QDeclarativeScript::Object *obj, const BindingContext &ctxt)
1423 Q_ASSERT(obj->metatype);
1424 Q_ASSERT(!obj->defaultProperty);
1425 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1428 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1429 if (isSignalPropertyName(prop->name())) {
1430 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1432 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1439 int QDeclarativeCompiler::componentTypeRef()
1441 QDeclarativeType *t = QDeclarativeMetaType::qmlType(QLatin1String("QtQuick/Component"),2,0);
1442 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1443 if (output->types.at(ii).type == t)
1446 QDeclarativeCompiledData::TypeReference ref;
1447 ref.className = Component_string;
1449 output->types << ref;
1450 return output->types.count() - 1;
1453 bool QDeclarativeCompiler::buildSignal(QDeclarativeScript::Property *prop, QDeclarativeScript::Object *obj,
1454 const BindingContext &ctxt)
1456 Q_ASSERT(obj->metaObject());
1458 const QHashedStringRef &propName = prop->name();
1460 Q_ASSERT(propName.startsWith(on_string));
1461 QString name = propName.mid(2, -1).toString();
1463 // Note that the property name could start with any alpha or '_' or '$' character,
1464 // so we need to do the lower-casing of the first alpha character.
1465 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1466 if (QDeclarativeUtils::isUpper(name.at(firstAlphaIndex))) {
1467 name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1472 bool notInRevision = false;
1474 QDeclarativePropertyCache::Data *sig = signal(obj, QStringRef(&name), ¬InRevision);
1478 if (notInRevision && 0 == property(obj, propName, 0)) {
1479 Q_ASSERT(obj->type != -1);
1480 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1481 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1483 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(elementName(obj)).arg(prop->name().toString()).arg(type.type->module()).arg(type.majorVersion).arg(type.minorVersion));
1485 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1489 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1491 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1495 if (prop->value || !prop->values.isOne())
1496 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1498 prop->index = sig->coreIndex;
1501 obj->addSignalProperty(prop);
1503 if (prop->values.first()->object) {
1504 COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1505 prop->values.first()->type = Value::SignalObject;
1507 prop->values.first()->type = Value::SignalExpression;
1509 if (!prop->values.first()->value.isScript())
1510 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1512 QString script = prop->values.first()->value.asScript().trimmed();
1513 if (script.isEmpty())
1514 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1516 prop->values.first()->signalExpressionContextStack = ctxt.stack;
1525 Returns true if (value) property \a prop exists on obj, false otherwise.
1527 bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeScript::Property *prop,
1528 QDeclarativeScript::Object *obj)
1530 if (prop->name().isEmpty())
1532 if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1535 return property(obj, prop->name()) != 0;
1538 bool QDeclarativeCompiler::buildProperty(QDeclarativeScript::Property *prop,
1539 QDeclarativeScript::Object *obj,
1540 const BindingContext &ctxt)
1542 if (prop->isEmpty())
1543 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1545 const QMetaObject *metaObject = obj->metaObject();
1546 Q_ASSERT(metaObject);
1548 if (isAttachedPropertyName(prop->name())) {
1549 // Setup attached property data
1551 if (ctxt.isSubContext()) {
1552 // Attached properties cannot be used on sub-objects. Sub-objects
1553 // always exist in a binding sub-context, which is what we test
1555 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1558 QDeclarativeType *type = 0;
1559 QDeclarativeImportedNamespace *typeNamespace = 0;
1560 unit->imports().resolveType(prop->name().toString(), &type, 0, 0, 0, &typeNamespace);
1562 if (typeNamespace) {
1563 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1566 } else if (!type || !type->attachedPropertiesType()) {
1567 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1571 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1573 Q_ASSERT(type->attachedPropertiesFunction());
1574 prop->index = type->attachedPropertiesId();
1575 prop->value->metatype = type->attachedPropertiesType();
1577 // Setup regular property data
1578 bool notInRevision = false;
1579 QDeclarativePropertyCache::Data *d =
1580 prop->name().isEmpty()?0:property(obj, prop->name(), ¬InRevision);
1582 if (d == 0 && notInRevision) {
1583 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1584 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1586 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(elementName(obj)).arg(prop->name().toString()).arg(type.type->module()).arg(type.majorVersion).arg(type.minorVersion));
1588 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1591 prop->index = d->coreIndex;
1593 } else if (prop->isDefault) {
1594 QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
1595 QDeclarativePropertyCache::Data defaultPropertyData;
1596 defaultPropertyData.load(p, engine);
1598 prop->setName(p.name());
1599 prop->core = defaultPropertyData;
1600 prop->index = prop->core.coreIndex;
1603 // We can't error here as the "id" property does not require a
1604 // successful index resolution
1605 if (prop->index != -1)
1606 prop->type = prop->core.propType;
1608 // Check if this is an alias
1609 if (prop->index != -1 &&
1611 prop->parent->type != -1 &&
1612 output->types.at(prop->parent->type).component) {
1614 QDeclarativePropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1615 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1616 prop->isAlias = true;
1619 if (prop->index != -1 && !prop->values.isEmpty())
1620 prop->parent->setBindingBit(prop->index);
1623 if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1625 // The magic "id" behavior doesn't apply when "id" is resolved as a
1626 // default property or to sub-objects (which are always in binding
1628 COMPILE_CHECK(buildIdProperty(prop, obj));
1629 if (prop->type == QVariant::String &&
1630 prop->values.first()->value.isString())
1631 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1633 } else if (isAttachedPropertyName(prop->name())) {
1635 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1637 } else if (prop->index == -1) {
1639 if (prop->isDefault) {
1640 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1642 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1645 } else if (prop->value) {
1647 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1649 } else if (prop->core.isQList()) {
1651 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1653 } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) {
1655 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1659 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1666 bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
1667 QDeclarativeScript::Property *nsProp,
1668 QDeclarativeScript::Object *obj,
1669 const BindingContext &ctxt)
1672 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1674 for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1676 if (!isAttachedPropertyName(prop->name()))
1677 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1679 // Setup attached property data
1681 QDeclarativeType *type = 0;
1682 unit->imports().resolveType(ns, prop->name().toString(), &type, 0, 0, 0);
1684 if (!type || !type->attachedPropertiesType())
1685 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1688 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1690 Q_ASSERT(type->attachedPropertiesFunction());
1691 prop->index = type->index();
1692 prop->value->metatype = type->attachedPropertiesType();
1694 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1700 void QDeclarativeCompiler::genValueProperty(QDeclarativeScript::Property *prop,
1701 QDeclarativeScript::Object *obj)
1703 if (prop->core.isQList()) {
1704 genListProperty(prop, obj);
1706 genPropertyAssignment(prop, obj);
1710 void QDeclarativeCompiler::genListProperty(QDeclarativeScript::Property *prop,
1711 QDeclarativeScript::Object *obj)
1713 int listType = enginePrivate->listType(prop->type);
1715 QDeclarativeInstruction fetch;
1716 fetch.setType(QDeclarativeInstruction::FetchQList);
1717 fetch.fetchQmlList.property = prop->index;
1718 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1719 fetch.fetchQmlList.type = listType;
1720 output->addInstruction(fetch);
1722 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1724 if (v->type == Value::CreatedObject) {
1726 genObject(v->object);
1727 if (listTypeIsInterface) {
1728 QDeclarativeInstruction assign;
1729 assign.setType(QDeclarativeInstruction::AssignObjectList);
1730 assign.assignObjectList.line = prop->location.start.line;
1731 output->addInstruction(assign);
1733 QDeclarativeInstruction store;
1734 store.setType(QDeclarativeInstruction::StoreObjectQList);
1735 output->addInstruction(store);
1738 } else if (v->type == Value::PropertyBinding) {
1740 genBindingAssignment(v, prop, obj);
1746 QDeclarativeInstruction pop;
1747 pop.setType(QDeclarativeInstruction::PopQList);
1748 output->addInstruction(pop);
1751 void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeScript::Property *prop,
1752 QDeclarativeScript::Object *obj,
1753 QDeclarativeScript::Property *valueTypeProperty)
1755 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1757 Q_ASSERT(v->type == Value::CreatedObject ||
1758 v->type == Value::PropertyBinding ||
1759 v->type == Value::Literal);
1761 if (v->type == Value::CreatedObject) {
1763 genObject(v->object);
1765 if (QDeclarativeMetaType::isInterface(prop->type)) {
1767 QDeclarativeInstruction store;
1768 store.setType(QDeclarativeInstruction::StoreInterface);
1769 store.storeObject.line = v->object->location.start.line;
1770 store.storeObject.propertyIndex = prop->index;
1771 output->addInstruction(store);
1773 } else if (prop->type == QMetaType::QVariant) {
1775 QDeclarativeInstruction store;
1776 store.setType(QDeclarativeInstruction::StoreVariantObject);
1777 store.storeObject.line = v->object->location.start.line;
1778 store.storeObject.propertyIndex = prop->index;
1779 output->addInstruction(store);
1783 QDeclarativeInstruction store;
1784 store.setType(QDeclarativeInstruction::StoreObject);
1785 store.storeObject.line = v->object->location.start.line;
1786 store.storeObject.propertyIndex = prop->index;
1787 output->addInstruction(store);
1790 } else if (v->type == Value::PropertyBinding) {
1792 genBindingAssignment(v, prop, obj, valueTypeProperty);
1794 } else if (v->type == Value::Literal) {
1796 genLiteralAssignment(prop, v);
1802 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
1804 Q_ASSERT(v->type == Value::ValueSource ||
1805 v->type == Value::ValueInterceptor);
1807 if (v->type == Value::ValueSource) {
1808 genObject(v->object);
1810 QDeclarativeInstruction store;
1811 store.setType(QDeclarativeInstruction::StoreValueSource);
1812 if (valueTypeProperty) {
1813 store.assignValueSource.property = genValueTypeData(prop, valueTypeProperty);
1814 store.assignValueSource.owner = 1;
1816 store.assignValueSource.property = genPropertyData(prop);
1817 store.assignValueSource.owner = 0;
1819 QDeclarativeType *valueType = toQmlType(v->object);
1820 store.assignValueSource.castValue = valueType->propertyValueSourceCast();
1821 output->addInstruction(store);
1823 } else if (v->type == Value::ValueInterceptor) {
1824 genObject(v->object);
1826 QDeclarativeInstruction store;
1827 store.setType(QDeclarativeInstruction::StoreValueInterceptor);
1828 if (valueTypeProperty) {
1829 store.assignValueInterceptor.property = genValueTypeData(prop, valueTypeProperty);
1830 store.assignValueInterceptor.owner = 1;
1832 store.assignValueInterceptor.property = genPropertyData(prop);
1833 store.assignValueInterceptor.owner = 0;
1835 QDeclarativeType *valueType = toQmlType(v->object);
1836 store.assignValueInterceptor.castValue = valueType->propertyValueInterceptorCast();
1837 output->addInstruction(store);
1843 bool QDeclarativeCompiler::buildIdProperty(QDeclarativeScript::Property *prop,
1844 QDeclarativeScript::Object *obj)
1847 prop->values.isMany() ||
1848 prop->values.first()->object)
1849 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
1851 QDeclarativeScript::Value *idValue = prop->values.first();
1852 QString val = idValue->primitive();
1854 COMPILE_CHECK(checkValidId(idValue, val));
1856 if (compileState->ids.value(val))
1857 COMPILE_EXCEPTION(prop, tr("id is not unique"));
1859 prop->values.first()->type = Value::Id;
1867 void QDeclarativeCompiler::addId(const QString &id, QDeclarativeScript::Object *obj)
1869 Q_ASSERT(!compileState->ids.value(id));
1870 Q_ASSERT(obj->id == id);
1871 obj->idIndex = compileState->ids.count();
1872 compileState->ids.append(obj);
1875 void QDeclarativeCompiler::addBindingReference(BindingReference *ref)
1877 Q_ASSERT(ref->value && !ref->value->bindingReference);
1878 ref->value->bindingReference = ref;
1879 compileState->bindings.prepend(ref);
1882 void QDeclarativeCompiler::saveComponentState()
1884 Q_ASSERT(compileState->root);
1885 Q_ASSERT(compileState->root->componentCompileState == 0);
1887 compileState->root->componentCompileState = compileState;
1890 componentStats->savedComponentStats.append(componentStats->componentStat);
1893 QDeclarativeCompilerTypes::ComponentCompileState *
1894 QDeclarativeCompiler::componentState(QDeclarativeScript::Object *obj)
1896 Q_ASSERT(obj->componentCompileState);
1897 return obj->componentCompileState;
1900 // Build attached property object. In this example,
1904 // GridView is an attached property object.
1905 bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeScript::Property *prop,
1906 QDeclarativeScript::Object *obj,
1907 const BindingContext &ctxt)
1909 Q_ASSERT(prop->value);
1910 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
1912 obj->addAttachedProperty(prop);
1914 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1920 // Build "grouped" properties. In this example:
1922 // font.pointSize: 12
1923 // font.family: "Helvetica"
1925 // font is a nested property. pointSize and family are not.
1926 bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeScript::Property *prop,
1927 QDeclarativeScript::Object *obj,
1928 const BindingContext &ctxt)
1930 Q_ASSERT(prop->type != 0);
1931 Q_ASSERT(prop->index != -1);
1933 if (QDeclarativeValueTypeFactory::isValueType(prop->type)) {
1934 if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
1936 if (!prop->values.isEmpty()) {
1937 if (prop->values.first()->location < prop->value->location) {
1938 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
1940 COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
1944 if (!obj->metaObject()->property(prop->index).isWritable()) {
1945 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
1949 if (prop->isAlias) {
1950 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
1951 vtProp->isAlias = true;
1955 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
1956 prop->value, obj, ctxt.incr()));
1957 obj->addValueTypeProperty(prop);
1959 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1963 // Load the nested property's meta type
1964 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
1965 if (!prop->value->metatype)
1966 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
1968 if (!prop->values.isEmpty())
1969 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
1971 obj->addGroupedProperty(prop);
1973 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1979 bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
1980 QDeclarativeScript::Object *obj,
1981 QDeclarativeScript::Object *baseObj,
1982 const BindingContext &ctxt)
1984 if (obj->defaultProperty)
1985 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
1986 obj->metatype = type->metaObject();
1988 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1990 QDeclarativePropertyCache::Data *d = property(obj, prop->name());
1992 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1994 prop->index = d->coreIndex;
1995 prop->type = d->propType;
1997 prop->isValueTypeSubProperty = true;
2000 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
2002 if (prop->values.isMany()) {
2003 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
2004 } else if (!prop->values.isEmpty()) {
2005 QDeclarativeScript::Value *value = prop->values.first();
2007 if (value->object) {
2008 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
2009 } else if (value->value.isScript()) {
2010 // ### Check for writability
2012 //optimization for <Type>.<EnumValue> enum assignments
2013 bool isEnumAssignment = false;
2015 if (prop->core.isEnum())
2016 COMPILE_CHECK(testQualifiedEnumAssignment(obj->metatype->property(prop->index), obj,
2017 value, &isEnumAssignment));
2019 if (isEnumAssignment) {
2020 value->type = Value::Literal;
2022 BindingReference *reference = pool->New<BindingReference>();
2023 reference->expression = value->value;
2024 reference->property = prop;
2025 reference->value = value;
2026 reference->bindingContext = ctxt;
2027 reference->bindingContext.owner++;
2028 addBindingReference(reference);
2029 value->type = Value::PropertyBinding;
2032 COMPILE_CHECK(testLiteralAssignment(prop, value));
2033 value->type = Value::Literal;
2037 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2038 Q_ASSERT(v->object);
2040 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
2043 obj->addValueProperty(prop);
2049 // Build assignments to QML lists. QML lists are properties of type
2050 // QDeclarativeListProperty<T>. List properties can accept a list of
2051 // objects, or a single binding.
2052 bool QDeclarativeCompiler::buildListProperty(QDeclarativeScript::Property *prop,
2053 QDeclarativeScript::Object *obj,
2054 const BindingContext &ctxt)
2056 Q_ASSERT(prop->core.isQList());
2060 obj->addValueProperty(prop);
2062 int listType = enginePrivate->listType(t);
2063 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
2065 bool assignedBinding = false;
2066 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2068 v->type = Value::CreatedObject;
2069 COMPILE_CHECK(buildObject(v->object, ctxt));
2071 // We check object coercian here. We check interface assignment
2073 if (!listTypeIsInterface) {
2074 if (!canCoerce(listType, v->object)) {
2075 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2079 } else if (v->value.isScript()) {
2080 if (assignedBinding)
2081 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2083 assignedBinding = true;
2084 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2085 v->type = Value::PropertyBinding;
2087 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2094 // Compiles an assignment to a QDeclarativeScriptString property
2095 bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeScript::Property *prop,
2096 QDeclarativeScript::Object *obj,
2097 const BindingContext &ctxt)
2099 if (prop->values.isMany())
2100 COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2102 if (prop->values.first()->object)
2103 COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2105 prop->scriptStringScope = ctxt.stack;
2106 obj->addScriptStringProperty(prop);
2111 // Compile regular property assignments of the form "property: <value>"
2112 bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeScript::Property *prop,
2113 QDeclarativeScript::Object *obj,
2114 const BindingContext &ctxt)
2116 obj->addValueProperty(prop);
2118 if (prop->values.isMany())
2119 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2121 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2124 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2128 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2133 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2134 Q_ASSERT(v->object);
2135 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2141 // Compile assigning a single object instance to a regular property
2142 bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeScript::Property *prop,
2143 QDeclarativeScript::Object *obj,
2144 QDeclarativeScript::Value *v,
2145 const BindingContext &ctxt)
2147 Q_ASSERT(prop->index != -1);
2148 Q_ASSERT(v->object->type != -1);
2150 if (!obj->metaObject()->property(prop->index).isWritable())
2151 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2153 if (QDeclarativeMetaType::isInterface(prop->type)) {
2155 // Assigning an object to an interface ptr property
2156 COMPILE_CHECK(buildObject(v->object, ctxt));
2158 v->type = Value::CreatedObject;
2160 } else if (prop->type == QMetaType::QVariant) {
2162 // Assigning an object to a QVariant
2163 COMPILE_CHECK(buildObject(v->object, ctxt));
2165 v->type = Value::CreatedObject;
2167 // Normally buildObject() will set this up, but we need the static
2168 // meta object earlier to test for assignability. It doesn't matter
2169 // that there may still be outstanding synthesized meta object changes
2170 // on this type, as they are not relevant for assignability testing
2171 v->object->metatype = output->types.at(v->object->type).metaObject();
2172 Q_ASSERT(v->object->metaObject());
2174 // We want to raw metaObject here as the raw metaobject is the
2175 // actual property type before we applied any extensions that might
2176 // effect the properties on the type, but don't effect assignability
2177 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2179 // Will be true if the assgned type inherits propertyMetaObject
2180 bool isAssignable = false;
2181 // Determine isAssignable value
2182 if (propertyMetaObject) {
2183 const QMetaObject *c = v->object->metatype;
2185 isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject));
2186 c = c->superClass();
2191 // Simple assignment
2192 COMPILE_CHECK(buildObject(v->object, ctxt));
2194 v->type = Value::CreatedObject;
2195 } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) {
2196 // Automatic "Component" insertion
2197 QDeclarativeScript::Object *root = v->object;
2198 QDeclarativeScript::Object *component = pool->New<Object>();
2199 component->type = componentTypeRef();
2200 component->typeName = "Qt/Component";
2201 component->metatype = &QDeclarativeComponent::staticMetaObject;
2202 component->location = root->location;
2203 QDeclarativeScript::Value *componentValue = pool->New<Value>();
2204 componentValue->object = root;
2205 component->getDefaultProperty()->addValue(componentValue);
2206 v->object = component;
2207 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2209 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2216 // Compile assigning a single object instance to a regular property using the "on" syntax.
2220 // NumberAnimation on x { }
2222 bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeScript::Property *prop,
2223 QDeclarativeScript::Object *obj,
2224 QDeclarativeScript::Object *baseObj,
2225 QDeclarativeScript::Value *v,
2226 const BindingContext &ctxt)
2228 Q_ASSERT(prop->index != -1);
2229 Q_ASSERT(v->object->type != -1);
2231 if (!obj->metaObject()->property(prop->index).isWritable())
2232 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2235 // Normally buildObject() will set this up, but we need the static
2236 // meta object earlier to test for assignability. It doesn't matter
2237 // that there may still be outstanding synthesized meta object changes
2238 // on this type, as they are not relevant for assignability testing
2239 v->object->metatype = output->types.at(v->object->type).metaObject();
2240 Q_ASSERT(v->object->metaObject());
2242 // Will be true if the assigned type inherits QDeclarativePropertyValueSource
2243 bool isPropertyValue = false;
2244 // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor
2245 bool isPropertyInterceptor = false;
2246 if (QDeclarativeType *valueType = toQmlType(v->object)) {
2247 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2248 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2251 if (isPropertyValue || isPropertyInterceptor) {
2252 // Assign as a property value source
2253 COMPILE_CHECK(buildObject(v->object, ctxt));
2255 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2256 buildDynamicMeta(baseObj, ForceCreation);
2257 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2259 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(QString::fromUtf8(v->object->typeName)).arg(prop->name().toString()));
2265 // Compile assigning a literal or binding to a regular property
2266 bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeScript::Property *prop,
2267 QDeclarativeScript::Object *obj,
2268 QDeclarativeScript::Value *v,
2269 const BindingContext &ctxt)
2271 Q_ASSERT(prop->index != -1);
2273 if (v->value.isScript()) {
2275 //optimization for <Type>.<EnumValue> enum assignments
2276 if (prop->core.isEnum()) {
2277 bool isEnumAssignment = false;
2278 COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj,
2279 v, &isEnumAssignment));
2280 if (isEnumAssignment) {
2281 v->type = Value::Literal;
2286 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2288 v->type = Value::PropertyBinding;
2292 COMPILE_CHECK(testLiteralAssignment(prop, v));
2294 v->type = Value::Literal;
2300 bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop,
2301 QDeclarativeScript::Object *obj,
2302 QDeclarativeScript::Value *v,
2305 *isAssignment = false;
2306 if (!prop.isEnumType())
2309 if (!prop.isWritable())
2310 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
2312 QString string = v->value.asString();
2313 if (!QDeclarativeUtils::isUpper(string.at(0)))
2316 QStringList parts = string.split(QLatin1Char('.'));
2317 if (parts.count() != 2)
2320 QString typeName = parts.at(0);
2321 QDeclarativeType *type = 0;
2322 unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
2324 //handle enums on value types (where obj->typeName is empty)
2325 QByteArray objTypeName = obj->typeName;
2326 if (objTypeName.isEmpty()) {
2327 QDeclarativeType *objType = toQmlType(obj);
2329 objTypeName = objType->qmlTypeName();
2335 QString enumValue = parts.at(1);
2338 if (objTypeName == type->qmlTypeName()) {
2339 // When these two match, we can short cut the search
2340 if (prop.isFlagType()) {
2341 value = prop.enumerator().keysToValue(enumValue.toUtf8().constData());
2343 value = prop.enumerator().keyToValue(enumValue.toUtf8().constData());
2346 // Otherwise we have to search the whole type
2347 // This matches the logic in QV8TypeWrapper
2348 QByteArray enumName = enumValue.toUtf8();
2349 const QMetaObject *metaObject = type->baseMetaObject();
2350 for (int ii = metaObject->enumeratorCount() - 1; value == -1 && ii >= 0; --ii) {
2351 QMetaEnum e = metaObject->enumerator(ii);
2352 value = e.keyToValue(enumName.constData());
2359 v->type = Value::Literal;
2360 v->value = QDeclarativeScript::Variant((double)value);
2361 *isAssignment = true;
2366 struct StaticQtMetaObject : public QObject
2368 static const QMetaObject *get()
2369 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2372 // Similar logic to above, but not knowing target property.
2373 int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const
2375 int dot = script.indexOf('.');
2377 const QByteArray &scope = script.left(dot);
2378 QDeclarativeType *type = 0;
2379 unit->imports().resolveType(QString::fromUtf8(script.left(dot)), &type, 0, 0, 0, 0);
2380 if (!type && scope != "Qt")
2382 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2383 const char *key = script.constData() + dot+1;
2384 int i = mo->enumeratorCount();
2386 int v = mo->enumerator(i).keyToValue(key);
2394 const QMetaObject *QDeclarativeCompiler::resolveType(const QByteArray& name) const
2396 QDeclarativeType *qmltype = 0;
2397 if (!unit->imports().resolveType(QString::fromUtf8(name), &qmltype, 0, 0, 0, 0))
2401 return qmltype->metaObject();
2404 // similar to logic of completeComponentBuild, but also sticks data
2405 // into primitives at the end
2406 int QDeclarativeCompiler::rewriteBinding(const QString& expression, const QString& name)
2408 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2409 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf('.') + 1));
2411 QString rewrite = rewriteBinding(expression, 0, 0);
2413 return output->indexForString(rewrite);
2416 // Ensures that the dynamic meta specification on obj is valid
2417 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeScript::Object *obj)
2419 bool seenDefaultProperty = false;
2421 // We use a coarse grain, 31 bit hash to check if there are duplicates.
2422 // Calculating the hash for the names is not a waste as we have to test
2423 // them against the illegalNames set anyway.
2424 QHashField propNames;
2425 QHashField methodNames;
2428 int dpCount = obj->dynamicProperties.count();
2429 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2430 const QDeclarativeScript::Object::DynamicProperty &prop = *p;
2432 if (prop.isDefaultProperty) {
2433 if (seenDefaultProperty)
2434 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2435 seenDefaultProperty = true;
2438 if (propNames.testAndSet(prop.name.hash())) {
2439 for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p;
2440 p2 = obj->dynamicProperties.next(p2)) {
2441 if (p2->name == prop.name)
2442 COMPILE_EXCEPTION(&prop, tr("Duplicate property name"));
2446 if (QDeclarativeUtils::isUpper(prop.name.at(0)))
2447 COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
2449 if (enginePrivate->v8engine()->illegalNames().contains(prop.name))
2450 COMPILE_EXCEPTION(&prop, tr("Illegal property name"));
2453 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2454 const QDeclarativeScript::Object::DynamicSignal &currSig = *s;
2456 if (methodNames.testAndSet(currSig.name.hash())) {
2457 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2458 s2 = obj->dynamicSignals.next(s2)) {
2459 if (s2->name == currSig.name)
2460 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2464 if (currSig.name.at(0).isUpper())
2465 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2466 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2467 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2470 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2471 const QDeclarativeScript::Object::DynamicSlot &currSlot = *s;
2473 if (methodNames.testAndSet(currSlot.name.hash())) {
2474 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2475 s2 = obj->dynamicSignals.next(s2)) {
2476 if (s2->name == currSlot.name)
2477 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2479 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2480 s2 = obj->dynamicSlots.next(s2)) {
2481 if (s2->name == currSlot.name)
2482 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2486 if (currSlot.name.at(0).isUpper())
2487 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2488 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2489 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2495 bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeScript::Object *obj)
2497 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2499 if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2502 Property *property = 0;
2503 if (p->isDefaultProperty) {
2504 property = obj->getDefaultProperty();
2506 property = obj->getProperty(p->name);
2507 if (!property->values.isEmpty())
2508 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2511 if (property->value)
2512 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2514 property->values.append(p->defaultValue->values);
2519 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2521 bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeScript::Object *obj, DynamicMetaMode mode)
2524 Q_ASSERT(obj->metatype);
2526 if (mode != ForceCreation &&
2527 obj->dynamicProperties.isEmpty() &&
2528 obj->dynamicSignals.isEmpty() &&
2529 obj->dynamicSlots.isEmpty())
2532 bool resolveAlias = (mode == ResolveAliases);
2534 const Object::DynamicProperty *defaultProperty = 0;
2537 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2539 if (p->type == Object::DynamicProperty::Alias)
2542 if (p->isDefaultProperty &&
2543 (resolveAlias || p->type != Object::DynamicProperty::Alias))
2544 defaultProperty = p;
2546 if (!resolveAlias) {
2547 // No point doing this for both the alias and non alias cases
2548 QDeclarativePropertyCache::Data *d = property(obj, p->name);
2549 if (d && d->isFinal())
2550 COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2554 bool buildData = resolveAlias || aliasCount == 0;
2556 QByteArray dynamicData;
2558 typedef QDeclarativeVMEMetaData VMD;
2560 dynamicData = QByteArray(sizeof(QDeclarativeVMEMetaData) +
2561 (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) +
2562 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2563 aliasCount * sizeof(VMD::AliasData), 0);
2566 int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1);
2568 QByteArray newClassName = obj->metatype->className();
2569 newClassName.append("_QML_");
2570 newClassName.append(QByteArray::number(uniqueClassId));
2572 if (compileState->root == obj && !compileState->nested) {
2573 QString path = output->url.path();
2574 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2575 if (lastSlash > -1) {
2576 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2577 if (!nameBase.isEmpty() && QDeclarativeUtils::isUpper(nameBase.at(0)))
2578 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId);
2582 QFastMetaBuilder builder;
2583 QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(),
2584 obj->dynamicProperties.count() - (resolveAlias?0:aliasCount),
2585 obj->dynamicSlots.count(),
2586 obj->dynamicSignals.count() + obj->dynamicProperties.count(),
2587 defaultProperty?1:0);
2590 Object::DynamicProperty::Type dtype;
2592 const char *cppType;
2593 } builtinTypes[] = {
2594 { Object::DynamicProperty::Variant, 0, "QVariant" },
2595 { Object::DynamicProperty::Int, QMetaType::Int, "int" },
2596 { Object::DynamicProperty::Bool, QMetaType::Bool, "bool" },
2597 { Object::DynamicProperty::Real, QMetaType::Double, "double" },
2598 { Object::DynamicProperty::String, QMetaType::QString, "QString" },
2599 { Object::DynamicProperty::Url, QMetaType::QUrl, "QUrl" },
2600 { Object::DynamicProperty::Color, QMetaType::QColor, "QColor" },
2601 { Object::DynamicProperty::Time, QMetaType::QTime, "QTime" },
2602 { Object::DynamicProperty::Date, QMetaType::QDate, "QDate" },
2603 { Object::DynamicProperty::DateTime, QMetaType::QDateTime, "QDateTime" },
2605 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2606 QFastMetaBuilder::StringRef typeRefs[builtinTypeCount];
2608 // Reserve dynamic properties
2609 if (obj->dynamicProperties.count()) {
2610 typedef QDeclarativeVMEMetaData VMD;
2612 int effectivePropertyIndex = 0;
2613 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2615 // Reserve space for name
2616 p->nameRef = builder.newString(p->name.utf8length());
2618 int propertyType = 0;
2619 bool readonly = false;
2620 QFastMetaBuilder::StringRef typeRef;
2622 if (p->type == Object::DynamicProperty::Alias) {
2624 } else if (p->type < builtinTypeCount) {
2625 Q_ASSERT(builtinTypes[p->type].dtype == p->type);
2626 propertyType = builtinTypes[p->type].metaType;
2627 if (typeRefs[p->type].isEmpty())
2628 typeRefs[p->type] = builder.newString(strlen(builtinTypes[p->type].cppType));
2629 typeRef = typeRefs[p->type];
2630 if (p->type == Object::DynamicProperty::Variant)
2634 Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
2635 p->type == Object::DynamicProperty::Custom);
2637 // XXX don't double resolve this in the case of an alias run
2639 QByteArray customTypeName;
2640 QDeclarativeType *qmltype = 0;
2642 if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
2643 COMPILE_EXCEPTION(p, tr("Invalid property type"));
2646 QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(QUrl(url));
2648 Q_ASSERT(tdata->isComplete());
2650 QDeclarativeCompiledData *data = tdata->compiledData();
2651 customTypeName = data->root->className();
2655 customTypeName = qmltype->typeName();
2658 if (p->type == Object::DynamicProperty::Custom) {
2659 customTypeName += '*';
2660 propertyType = QMetaType::QObjectStar;
2663 customTypeName = QByteArray("QDeclarativeListProperty<") + customTypeName + QByteArray(">");
2664 propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
2667 p->resolvedCustomTypeName = pool->NewByteArray(customTypeName);
2668 p->typeRef = builder.newString(customTypeName.length());
2669 typeRef = p->typeRef;
2673 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2674 vmd->propertyCount++;
2675 (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType;
2678 if (p->type < builtinTypeCount)
2679 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef, (QMetaType::Type)propertyType,
2680 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2681 effectivePropertyIndex);
2683 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef,
2684 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2685 effectivePropertyIndex);
2687 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2688 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2690 effectivePropertyIndex++;
2695 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2696 if (p->type == Object::DynamicProperty::Alias) {
2698 Q_ASSERT(buildData);
2699 ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++;
2700 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex,
2703 // Even if we aren't resolving the alias, we need a fake signal so that the
2704 // metaobject remains consistent across the resolve and non-resolve alias runs
2705 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2706 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2707 effectivePropertyIndex++;
2714 // Reserve default property
2715 QFastMetaBuilder::StringRef defPropRef;
2716 if (defaultProperty) {
2717 defPropRef = builder.newString(strlen("DefaultProperty"));
2718 builder.setClassInfo(0, defPropRef, defaultProperty->nameRef);
2721 // Reserve dynamic signals
2722 int signalIndex = 0;
2723 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2725 int paramCount = s->parameterNames.count();
2727 int signatureSize = s->name.utf8length() + 2 /* paren */;
2729 if (paramCount) signatureSize += s->parameterTypesLength() + (paramCount - 1) /* commas */;
2730 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1) /* commas */;
2732 s->signatureRef = builder.newString(signatureSize);
2733 if (namesSize) s->parameterNamesRef = builder.newString(namesSize);
2736 ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++;
2738 builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->signatureRef, s->parameterNamesRef);
2742 // Reserve dynamic slots
2743 if (obj->dynamicSlots.count()) {
2745 // Allocate QVariant string
2746 if (typeRefs[0].isEmpty())
2747 typeRefs[0] = builder.newString(strlen(builtinTypes[0].cppType));
2749 typedef QDeclarativeVMEMetaData VMD;
2751 int methodIndex = 0;
2752 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2753 int paramCount = s->parameterNames.count();
2755 int signatureSize = s->name.utf8length() + 2 /* paren */;
2757 if (paramCount) signatureSize += (paramCount * strlen("QVariant") + (paramCount - 1));
2758 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
2760 s->signatureRef = builder.newString(signatureSize);
2761 if (namesSize) s->parameterNamesRef = builder.newString(namesSize);
2763 builder.setMethod(methodIndex, s->signatureRef, s->parameterNamesRef, typeRefs[0]);
2767 funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ +
2768 namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
2769 funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
2770 for (int jj = 0; jj < paramCount; ++jj) {
2771 if (jj) funcScript.append(QLatin1Char(','));
2772 funcScript.append(QLatin1String(s->parameterNames.at(jj)));
2774 funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
2776 VMD::MethodData methodData = { s->parameterNames.count(), 0,
2777 funcScript.length(),
2778 s->location.start.line };
2780 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2783 VMD::MethodData &md = *(vmd->methodData() + methodIndex);
2785 md.bodyOffset = dynamicData.size();
2787 dynamicData.append((const char *)funcScript.constData(),
2788 (funcScript.length() * sizeof(QChar)));
2795 // Now allocate used builtin types
2796 for (int ii = 0; ii < builtinTypeCount; ++ii) {
2797 if (!typeRefs[ii].isEmpty())
2798 typeRefs[ii].load(builtinTypes[ii].cppType);
2801 // Now allocate properties
2802 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2804 char *d = p->changedSignatureRef.data();
2805 p->name.writeUtf8(d);
2806 strcpy(d + p->name.utf8length(), "Changed()");
2808 if (p->type == Object::DynamicProperty::Alias && !resolveAlias)
2811 p->nameRef.load(p->name);
2813 if (p->type >= builtinTypeCount) {
2814 Q_ASSERT(p->resolvedCustomTypeName);
2815 p->typeRef.load(*p->resolvedCustomTypeName);
2819 // Allocate default property if necessary
2820 if (defaultProperty)
2821 strcpy(defPropRef.data(), "DefaultProperty");
2823 // Now allocate signals
2824 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2826 char *d = s->signatureRef.data();
2827 char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data();
2828 s->name.writeUtf8(d); d += s->name.utf8length();
2831 for (int jj = 0; jj < s->parameterNames.count(); ++jj) {
2832 if (jj != 0) { *d++ = ','; *d2++ = ','; }
2833 strcpy(d, s->parameterTypes.at(jj).constData());
2834 d += s->parameterTypes.at(jj).length();
2835 s->parameterNames.at(jj).writeUtf8(d2);
2836 d2 += s->parameterNames.at(jj).utf8length();
2843 // Now allocate methods
2844 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2845 char *d = s->signatureRef.data();
2846 char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data();
2847 s->name.writeUtf8(d); d += s->name.utf8length();
2849 for (int jj = 0; jj < s->parameterNames.count(); ++jj) {
2850 if (jj != 0) { *d++ = ','; *d2++ = ','; }
2851 strcpy(d, "QVariant");
2852 d += strlen("QVariant");
2853 strcpy(d2, s->parameterNames.at(jj).constData());
2854 d2 += s->parameterNames.at(jj).length();
2861 // Now allocate class name
2862 classNameRef.load(newClassName);
2864 obj->metadata = builder.toData();
2865 builder.fromData(&obj->extObject, obj->metatype, obj->metadata);
2867 if (mode == IgnoreAliases && aliasCount)
2868 compileState->aliasingObjects.append(obj);
2870 obj->synthdata = dynamicData;
2872 if (obj->synthCache) {
2873 obj->synthCache->release();
2874 obj->synthCache = 0;
2877 if (obj->type != -1) {
2878 QDeclarativePropertyCache *cache = output->types[obj->type].createPropertyCache(engine)->copy();
2879 cache->append(engine, &obj->extObject, QDeclarativePropertyCache::Data::NoFlags,
2880 QDeclarativePropertyCache::Data::IsVMEFunction,
2881 QDeclarativePropertyCache::Data::IsVMESignal);
2882 obj->synthCache = cache;
2888 bool QDeclarativeCompiler::checkValidId(QDeclarativeScript::Value *v, const QString &val)
2891 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
2893 QChar ch = val.at(0);
2894 if (QDeclarativeUtils::isLetter(ch) && !QDeclarativeUtils::isLower(ch))
2895 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
2897 QChar u(QLatin1Char('_'));
2898 if (!QDeclarativeUtils::isLetter(ch) && ch != u)
2899 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
2901 for (int ii = 1; ii < val.count(); ++ii) {
2903 if (!QDeclarativeUtils::isLetterOrNumber(ch) && ch != u)
2904 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
2907 if (enginePrivate->v8engine()->illegalNames().contains(val))
2908 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
2913 #include <qdeclarativejsparser_p.h>
2915 static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node)
2917 if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) {
2919 static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name.toString();
2920 return QStringList() << name;
2921 } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) {
2922 QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node);
2924 QStringList rv = astNodeToStringList(expr->base);
2927 rv.append(expr->name.toString());
2930 return QStringList();
2933 bool QDeclarativeCompiler::compileAlias(QFastMetaBuilder &builder,
2935 QDeclarativeScript::Object *obj,
2936 int propIndex, int aliasIndex,
2937 Object::DynamicProperty &prop)
2939 if (!prop.defaultValue)
2940 COMPILE_EXCEPTION(obj, tr("No property alias location"));
2942 if (!prop.defaultValue->values.isOne() ||
2943 prop.defaultValue->values.first()->object ||
2944 !prop.defaultValue->values.first()->value.isScript())
2945 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2947 QDeclarativeJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST();
2949 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
2951 QStringList alias = astNodeToStringList(node);
2953 if (alias.count() < 1 || alias.count() > 3)
2954 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
2956 QDeclarativeScript::Object *idObject = compileState->ids.value(alias.at(0));
2958 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
2960 QByteArray typeName;
2965 bool writable = false;
2966 bool resettable = false;
2967 if (alias.count() == 2 || alias.count() == 3) {
2968 propIdx = indexOfProperty(idObject, alias.at(1));
2970 if (-1 == propIdx) {
2971 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2972 } else if (propIdx > 0xFFFF) {
2973 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
2976 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
2977 if (!aliasProperty.isScriptable())
2978 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2980 writable = aliasProperty.isWritable();
2981 resettable = aliasProperty.isResettable();
2983 if (aliasProperty.type() < QVariant::UserType)
2984 type = aliasProperty.type();
2986 if (alias.count() == 3) {
2987 QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
2989 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2991 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
2993 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
2994 if (valueTypeIndex == -1)
2995 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
2996 Q_ASSERT(valueTypeIndex <= 0xFF);
2998 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
2999 propIdx |= (valueTypeIndex << 16);
3001 // update the property type
3002 type = aliasProperty.type();
3003 if (type >= QVariant::UserType)
3007 if (aliasProperty.isEnumType())
3008 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
3010 typeName = aliasProperty.typeName();
3012 Q_ASSERT(idObject->type != -1); // How else did it get an id?
3014 const QDeclarativeCompiledData::TypeReference &ref = output->types.at(idObject->type);
3016 typeName = ref.type->typeName();
3018 typeName = ref.component->root->className();
3023 if (typeName.endsWith('*'))
3024 flags |= QML_ALIAS_FLAG_PTR;
3026 QDeclarativeVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags };
3028 typedef QDeclarativeVMEMetaData VMD;
3029 VMD *vmd = (QDeclarativeVMEMetaData *)data.data();
3030 *(vmd->aliasData() + aliasIndex) = aliasData;
3032 prop.nameRef = builder.newString(prop.name.utf8length());
3033 prop.resolvedCustomTypeName = pool->NewByteArray(typeName);
3034 prop.typeRef = builder.newString(typeName.length());
3036 builder.setProperty(propIndex, prop.nameRef, prop.typeRef, (QMetaType::Type)type,
3037 (QFastMetaBuilder::PropertyFlag)(writable?int(QFastMetaBuilder::Writable):0),
3043 bool QDeclarativeCompiler::buildBinding(QDeclarativeScript::Value *value,
3044 QDeclarativeScript::Property *prop,
3045 const BindingContext &ctxt)
3047 Q_ASSERT(prop->index != -1);
3048 Q_ASSERT(prop->parent);
3049 Q_ASSERT(prop->parent->metaObject());
3051 if (!prop->core.isWritable() && !prop->core.isQList())
3052 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3054 BindingReference *reference = pool->New<BindingReference>();
3055 reference->expression = value->value;
3056 reference->property = prop;
3057 reference->value = value;
3058 reference->bindingContext = ctxt;
3059 addBindingReference(reference);
3064 void QDeclarativeCompiler::genBindingAssignment(QDeclarativeScript::Value *binding,
3065 QDeclarativeScript::Property *prop,
3066 QDeclarativeScript::Object *obj,
3067 QDeclarativeScript::Property *valueTypeProperty)
3070 Q_ASSERT(binding->bindingReference);
3072 const BindingReference &ref = *binding->bindingReference;
3073 if (ref.dataType == BindingReference::V4) {
3074 QDeclarativeInstruction store;
3075 store.setType(QDeclarativeInstruction::StoreV4Binding);
3076 store.assignBinding.value = ref.compiledIndex;
3077 store.assignBinding.context = ref.bindingContext.stack;
3078 store.assignBinding.owner = ref.bindingContext.owner;
3079 if (valueTypeProperty)
3080 store.assignBinding.property = (valueTypeProperty->index & 0xFFFF) |
3081 ((valueTypeProperty->type & 0xFF)) << 16 |
3082 ((prop->index & 0xFF) << 24);
3084 store.assignBinding.property = prop->index;
3085 store.assignBinding.line = binding->location.start.line;
3086 output->addInstruction(store);
3087 } else if (ref.dataType == BindingReference::V8) {
3088 QDeclarativeInstruction store;
3089 store.setType(QDeclarativeInstruction::StoreV8Binding);
3090 store.assignBinding.value = ref.compiledIndex;
3091 store.assignBinding.context = ref.bindingContext.stack;
3092 store.assignBinding.owner = ref.bindingContext.owner;
3093 store.assignBinding.line = binding->location.start.line;
3095 Q_ASSERT(ref.bindingContext.owner == 0 ||
3096 (ref.bindingContext.owner != 0 && valueTypeProperty));
3097 if (ref.bindingContext.owner) {
3098 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
3100 store.assignBinding.property = genPropertyData(prop);
3103 output->addInstruction(store);
3105 QDeclarativeInstruction store;
3107 store.setType(QDeclarativeInstruction::StoreBinding);
3109 store.setType(QDeclarativeInstruction::StoreBindingOnAlias);
3110 store.assignBinding.value = output->indexForString(ref.rewrittenExpression);
3111 store.assignBinding.context = ref.bindingContext.stack;
3112 store.assignBinding.owner = ref.bindingContext.owner;
3113 store.assignBinding.line = binding->location.start.line;
3115 Q_ASSERT(ref.bindingContext.owner == 0 ||
3116 (ref.bindingContext.owner != 0 && valueTypeProperty));
3117 if (ref.bindingContext.owner) {
3118 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
3120 store.assignBinding.property = genPropertyData(prop);
3122 output->addInstruction(store);
3126 int QDeclarativeCompiler::genContextCache()
3128 if (compileState->ids.count() == 0)
3131 QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache();
3132 cache->reserve(compileState->ids.count());
3133 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
3134 cache->add(o->id, o->idIndex);
3136 output->contextCaches.append(cache);
3137 return output->contextCaches.count() - 1;
3140 int QDeclarativeCompiler::genValueTypeData(QDeclarativeScript::Property *valueTypeProp,
3141 QDeclarativeScript::Property *prop)
3143 typedef QDeclarativePropertyPrivate QDPP;
3144 QByteArray data = QDPP::saveValueType(prop->parent->metaObject(), prop->index,
3145 enginePrivate->valueTypes[prop->type]->metaObject(),
3146 valueTypeProp->index, engine);
3148 return output->indexForByteArray(data);
3151 int QDeclarativeCompiler::genPropertyData(QDeclarativeScript::Property *prop)
3153 typedef QDeclarativePropertyPrivate QDPP;
3154 QByteArray data = QDPP::saveProperty(prop->parent->metaObject(), prop->index, engine);
3156 return output->indexForByteArray(data);
3159 bool QDeclarativeCompiler::completeComponentBuild()
3162 componentStats->componentStat.ids = compileState->ids.count();
3164 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
3165 aliasObject = compileState->aliasingObjects.next(aliasObject))
3166 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
3168 QDeclarativeV4Compiler::Expression expr(unit->imports());
3169 expr.component = compileState->root;
3170 expr.ids = &compileState->ids;
3171 expr.importCache = output->importCache;
3173 QDeclarativeV4Compiler bindingCompiler;
3175 QList<BindingReference*> sharedBindings;
3177 for (BindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3179 BindingReference &binding = *b;
3181 // ### We don't currently optimize for bindings on alias's - because
3182 // of the solution to QTBUG-13719
3183 if (!binding.property->isAlias) {
3184 expr.context = binding.bindingContext.object;
3185 expr.property = binding.property;
3186 expr.expression = binding.expression;
3188 int index = bindingCompiler.compile(expr, enginePrivate);
3190 binding.dataType = BindingReference::V4;
3191 binding.compiledIndex = index;
3193 componentStats->componentStat.optimizedBindings.append(b->value->location);
3198 // Pre-rewrite the expression
3199 QString expression = binding.expression.asScript();
3201 QDeclarativeRewrite::RewriteBinding rewriteBinding;
3202 rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3203 bool isSharable = false;
3204 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3206 if (isSharable && !binding.property->isAlias /* See above re alias */ &&
3207 binding.property->type != qMetaTypeId<QDeclarativeBinding*>()) {
3208 binding.dataType = BindingReference::V8;
3209 sharedBindings.append(b);
3211 binding.dataType = BindingReference::QtScript;
3215 componentStats->componentStat.scriptBindings.append(b->value->location);
3218 if (!sharedBindings.isEmpty()) {
3220 static bool lt(const BindingReference *lhs, const BindingReference *rhs)
3222 return lhs->value->location.start.line < rhs->value->location.start.line;
3226 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3228 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3229 int lineNumber = startLineNumber;
3231 QString functionArray(QLatin1String("["));
3232 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3233 BindingReference *reference = sharedBindings.at(ii);
3234 QDeclarativeScript::Value *value = reference->value;
3235 const QString &expression = reference->rewrittenExpression;
3237 if (ii != 0) functionArray += QLatin1String(",");
3239 while (lineNumber < value->location.start.line) {
3241 functionArray += QLatin1String("\n");
3244 functionArray += expression;
3245 reference->compiledIndex = ii;
3247 functionArray += QLatin1String("]");
3249 compileState->v8BindingProgram = functionArray;
3250 compileState->v8BindingProgramLine = startLineNumber;
3251 compileState->v8BindingProgramIndex = output->v8bindings.count();
3252 output->v8bindings.append(v8::Persistent<v8::Array>());
3255 if (bindingCompiler.isValid())
3256 compileState->compiledBindingData = bindingCompiler.program();
3258 saveComponentState();
3263 void QDeclarativeCompiler::dumpStats()
3265 Q_ASSERT(componentStats);
3266 qWarning().nospace() << "QML Document: " << output->url.toString();
3267 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3268 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3269 qWarning().nospace() << " Component Line " << stat.lineNumber;
3270 qWarning().nospace() << " Total Objects: " << stat.objects;
3271 qWarning().nospace() << " IDs Used: " << stat.ids;
3272 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3276 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3277 if (0 == (ii % 10)) {
3278 if (ii) output.append("\n");
3283 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3285 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3286 output.append(") ");
3288 if (!output.isEmpty())
3289 qWarning().nospace() << output.constData();
3292 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3295 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3296 if (0 == (ii % 10)) {
3297 if (ii) output.append("\n");
3302 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3304 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3305 output.append(") ");
3307 if (!output.isEmpty())
3308 qWarning().nospace() << output.constData();
3314 Returns true if from can be assigned to a (QObject) property of type
3317 bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeScript::Object *from)
3319 const QMetaObject *toMo =
3320 enginePrivate->rawMetaObjectForType(to);
3321 const QMetaObject *fromMo = from->metaObject();
3324 if (QDeclarativePropertyPrivate::equal(fromMo, toMo))
3326 fromMo = fromMo->superClass();
3332 Returns the element name, as written in the QML file, for o.
3334 QString QDeclarativeCompiler::elementName(QDeclarativeScript::Object *o)
3337 if (o->type != -1) {
3338 return output->types.at(o->type).className;
3344 QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeScript::Object *from)
3347 const QMetaObject *mo = from->metatype;
3348 QDeclarativeType *type = 0;
3349 while (!type && mo) {
3350 type = QDeclarativeMetaType::qmlType(mo);
3351 mo = mo->superClass();
3356 QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeScript::Object *obj)
3358 const QMetaObject *mo = obj->metatype;
3360 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3362 return QStringList();
3364 QMetaClassInfo classInfo = mo->classInfo(idx);
3365 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3369 QDeclarativePropertyCache::Data *
3370 QDeclarativeCompiler::property(QDeclarativeScript::Object *object, int index)
3372 QDeclarativePropertyCache *cache = 0;
3374 if (object->synthCache)
3375 cache = object->synthCache;
3376 else if (object->type != -1)
3377 cache = output->types[object->type].createPropertyCache(engine);
3379 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3381 return cache->property(index);
3384 QDeclarativePropertyCache::Data *
3385 QDeclarativeCompiler::property(QDeclarativeScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3387 if (notInRevision) *notInRevision = false;
3389 QDeclarativePropertyCache *cache = 0;
3391 if (object->synthCache)
3392 cache = object->synthCache;
3393 else if (object->type != -1)
3394 cache = output->types[object->type].createPropertyCache(engine);
3396 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3398 QDeclarativePropertyCache::Data *d = cache->property(name);
3400 // Find the first property
3401 while (d && d->isFunction())
3402 d = cache->overrideData(d);
3404 if (d && !cache->isAllowedInRevision(d)) {
3405 if (notInRevision) *notInRevision = true;
3412 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3413 QDeclarativePropertyCache::Data *
3414 QDeclarativeCompiler::signal(QDeclarativeScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3416 if (notInRevision) *notInRevision = false;
3418 QDeclarativePropertyCache *cache = 0;
3420 if (object->synthCache)
3421 cache = object->synthCache;
3422 else if (object->type != -1)
3423 cache = output->types[object->type].createPropertyCache(engine);
3425 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3428 QDeclarativePropertyCache::Data *d = cache->property(name);
3429 if (notInRevision) *notInRevision = false;
3431 while (d && !(d->isFunction()))
3432 d = cache->overrideData(d);
3434 if (d && !cache->isAllowedInRevision(d)) {
3435 if (notInRevision) *notInRevision = true;
3441 if (name.endsWith(Changed_string)) {
3442 QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3444 d = property(object, propName, notInRevision);
3446 return cache->method(d->notifyIndex);
3452 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3453 int QDeclarativeCompiler::indexOfSignal(QDeclarativeScript::Object *object, const QString &name,
3454 bool *notInRevision)
3456 QDeclarativePropertyCache::Data *d = signal(object, QStringRef(&name), notInRevision);
3457 return d?d->coreIndex:-1;
3460 int QDeclarativeCompiler::indexOfProperty(QDeclarativeScript::Object *object, const QString &name,
3461 bool *notInRevision)
3463 return indexOfProperty(object, QStringRef(&name), notInRevision);
3466 int QDeclarativeCompiler::indexOfProperty(QDeclarativeScript::Object *object, const QHashedStringRef &name,
3467 bool *notInRevision)
3469 QDeclarativePropertyCache::Data *d = property(object, name, notInRevision);
3470 return d?d->coreIndex:-1;