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 "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 "qdeclarativestringconverters_p.h"
49 #include "qdeclarativeengine_p.h"
50 #include "qdeclarativeengine.h"
51 #include "qdeclarativecontext.h"
52 #include "qdeclarativemetatype_p.h"
53 #include "qdeclarativecustomparser_p_p.h"
54 #include "qdeclarativecontext_p.h"
55 #include "qdeclarativecomponent_p.h"
56 #include <private/qdeclarativejsast_p.h>
57 #include "qdeclarativevmemetaobject_p.h"
58 #include "qdeclarativeexpression_p.h"
59 #include "qdeclarativeproperty_p.h"
60 #include "qdeclarativerewrite_p.h"
61 #include "qdeclarativescriptstring.h"
62 #include "qdeclarativeglobal_p.h"
63 #include "qdeclarativebinding_p.h"
64 #include <private/qv4compiler_p.h>
72 #include <QtCore/qdebug.h>
73 #include <QtCore/qdatetime.h>
77 DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP);
78 DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS);
80 using namespace QDeclarativeScript;
81 using namespace QDeclarativeCompilerTypes;
83 static QString id_string(QLatin1String("id"));
84 static QString on_string(QLatin1String("on"));
85 static QString Changed_string(QLatin1String("Changed"));
86 static QString Component_string(QLatin1String("Component"));
89 Instantiate a new QDeclarativeCompiler.
91 QDeclarativeCompiler::QDeclarativeCompiler(QDeclarativePool *pool)
92 : pool(pool), output(0), engine(0), unitRoot(0), unit(0), componentStats(0)
94 if (compilerStatDump())
95 componentStats = pool->New<ComponentStats>();
99 Returns true if the last call to compile() caused errors.
103 bool QDeclarativeCompiler::isError() const
105 return !exceptions.isEmpty();
109 Return the list of errors from the last call to compile(), or an empty list
110 if there were no errors.
112 QList<QDeclarativeError> QDeclarativeCompiler::errors() const
118 Returns true if \a name refers to an attached property, false otherwise.
120 Attached property names are those that start with a capital letter.
122 bool QDeclarativeCompiler::isAttachedPropertyName(const QString &name)
124 return isAttachedPropertyName(QHashedStringRef(&name));
127 bool QDeclarativeCompiler::isAttachedPropertyName(const QHashedStringRef &name)
129 return !name.isEmpty() && name.at(0).isUpper();
133 Returns true if \a name refers to a signal property, false otherwise.
135 Signal property names are those that start with "on", followed by a first
136 character which is either a capital letter or one or more underscores followed
137 by a capital letter, which is then followed by other allowed characters.
139 Note that although ECMA-262r3 supports dollarsigns and escaped unicode
140 character codes in property names, for simplicity and performance reasons
141 QML only supports letters, numbers and underscores.
143 bool QDeclarativeCompiler::isSignalPropertyName(const QString &name)
145 return isSignalPropertyName(QStringRef(&name));
148 bool QDeclarativeCompiler::isSignalPropertyName(const QHashedStringRef &name)
150 if (name.length() < 3) return false;
151 if (!name.startsWith(on_string)) return false;
152 int ns = name.length();
153 for (int i = 2; i < ns; ++i) {
154 const QChar curr = name.at(i);
155 if (curr.unicode() == '_') continue;
156 if (curr.isUpper()) return true;
159 return false; // consists solely of underscores - invalid.
163 \macro COMPILE_EXCEPTION
165 Inserts an error into the QDeclarativeCompiler error list, and returns false
168 \a token is used to source the error line and column, and \a desc is the
169 error itself. \a desc can be an expression that can be piped into QDebug.
174 COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(property->name));
177 #define COMPILE_EXCEPTION(token, desc) \
179 QString exceptionDescription; \
180 QDeclarativeError error; \
181 error.setUrl(output->url); \
182 error.setLine((token)->location.start.line); \
183 error.setColumn((token)->location.start.column); \
184 error.setDescription(desc.trimmed()); \
185 exceptions << error; \
192 Returns false if \a is false, otherwise does nothing.
194 #define COMPILE_CHECK(a) \
196 if (!a) return false; \
200 Returns true if literal \a v can be assigned to property \a prop, otherwise
203 This test corresponds to action taken by genLiteralAssignment(). Any change
204 made here, must have a corresponding action in genLiteralAssigment().
206 bool QDeclarativeCompiler::testLiteralAssignment(QDeclarativeScript::Property *prop,
207 QDeclarativeScript::Value *v)
209 const QDeclarativeScript::Variant &value = v->value;
211 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
212 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
214 if (prop->core.isEnum()) {
215 QMetaProperty p = prop->parent->metaObject()->property(prop->index);
218 if (p.isFlagType()) {
219 enumValue = p.enumerator().keysToValue(value.asString().toUtf8().constData(), &ok);
221 enumValue = p.enumerator().keyToValue(value.asString().toUtf8().constData(), &ok);
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 QDeclarativeStringConverters::pointFFromString(value.asString(), &ok);
307 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected"));
311 case QVariant::SizeF:
314 QDeclarativeStringConverters::sizeFFromString(value.asString(), &ok);
315 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected"));
319 case QVariant::RectF:
322 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 if (prop->core.isEnum()) {
366 Q_ASSERT(v->value.isNumber());
368 int value = (int)v->value.asNumber();
370 Instruction::StoreInteger instr;
371 instr.propertyIndex = prop->index;
373 output->addInstruction(instr);
377 int type = prop->type;
379 case QMetaType::QVariant:
381 if (v->value.isNumber()) {
382 double n = v->value.asNumber();
383 if (double(int(n)) == n) {
384 if (prop->core.isVMEProperty()) {
385 Instruction::StoreVarInteger instr;
386 instr.propertyIndex = prop->index;
387 instr.value = int(n);
388 output->addInstruction(instr);
390 Instruction::StoreVariantInteger instr;
391 instr.propertyIndex = prop->index;
392 instr.value = int(n);
393 output->addInstruction(instr);
396 if (prop->core.isVMEProperty()) {
397 Instruction::StoreVarDouble instr;
398 instr.propertyIndex = prop->index;
400 output->addInstruction(instr);
402 Instruction::StoreVariantDouble instr;
403 instr.propertyIndex = prop->index;
405 output->addInstruction(instr);
408 } else if (v->value.isBoolean()) {
409 if (prop->core.isVMEProperty()) {
410 Instruction::StoreVarBool instr;
411 instr.propertyIndex = prop->index;
412 instr.value = v->value.asBoolean();
413 output->addInstruction(instr);
415 Instruction::StoreVariantBool instr;
416 instr.propertyIndex = prop->index;
417 instr.value = v->value.asBoolean();
418 output->addInstruction(instr);
421 if (prop->core.isVMEProperty()) {
422 Instruction::StoreVar instr;
423 instr.propertyIndex = prop->index;
424 instr.value = output->indexForString(v->value.asString());
425 output->addInstruction(instr);
427 Instruction::StoreVariant instr;
428 instr.propertyIndex = prop->index;
429 instr.value = output->indexForString(v->value.asString());
430 output->addInstruction(instr);
435 case QVariant::String:
437 Instruction::StoreString instr;
438 instr.propertyIndex = prop->index;
439 instr.value = output->indexForString(v->value.asString());
440 output->addInstruction(instr);
443 case QVariant::ByteArray:
445 Instruction::StoreByteArray instr;
446 instr.propertyIndex = prop->index;
447 instr.value = output->indexForByteArray(v->value.asString().toLatin1());
448 output->addInstruction(instr);
453 Instruction::StoreUrl instr;
454 QString string = v->value.asString();
455 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
456 instr.propertyIndex = prop->index;
457 instr.value = output->indexForUrl(u);
458 output->addInstruction(instr);
463 Instruction::StoreInteger instr;
464 instr.propertyIndex = prop->index;
465 instr.value = uint(v->value.asNumber());
466 output->addInstruction(instr);
471 Instruction::StoreInteger instr;
472 instr.propertyIndex = prop->index;
473 instr.value = int(v->value.asNumber());
474 output->addInstruction(instr);
477 case QMetaType::Float:
479 Instruction::StoreFloat instr;
480 instr.propertyIndex = prop->index;
481 instr.value = float(v->value.asNumber());
482 output->addInstruction(instr);
485 case QVariant::Double:
487 Instruction::StoreDouble instr;
488 instr.propertyIndex = prop->index;
489 instr.value = v->value.asNumber();
490 output->addInstruction(instr);
493 case QVariant::Color:
495 Instruction::StoreColor instr;
496 QColor c = QDeclarativeStringConverters::colorFromString(v->value.asString());
497 instr.propertyIndex = prop->index;
498 instr.value = c.rgba();
499 output->addInstruction(instr);
502 #ifndef QT_NO_DATESTRING
505 Instruction::StoreDate instr;
506 QDate d = QDeclarativeStringConverters::dateFromString(v->value.asString());
507 instr.propertyIndex = prop->index;
508 instr.value = d.toJulianDay();
509 output->addInstruction(instr);
514 Instruction::StoreTime instr;
515 QTime time = QDeclarativeStringConverters::timeFromString(v->value.asString());
516 instr.propertyIndex = prop->index;
517 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
518 ::memcpy(&instr.time, &time, sizeof(QTime));
519 output->addInstruction(instr);
522 case QVariant::DateTime:
524 Instruction::StoreDateTime instr;
525 QDateTime dateTime = QDeclarativeStringConverters::dateTimeFromString(v->value.asString());
526 QTime time = dateTime.time();
527 instr.propertyIndex = prop->index;
528 instr.date = dateTime.date().toJulianDay();
529 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
530 ::memcpy(&instr.time, &time, sizeof(QTime));
531 output->addInstruction(instr);
534 #endif // QT_NO_DATESTRING
535 case QVariant::Point:
537 Instruction::StorePoint instr;
539 QPoint point = QDeclarativeStringConverters::pointFFromString(v->value.asString(), &ok).toPoint();
540 instr.propertyIndex = prop->index;
541 instr.point.xp = point.x();
542 instr.point.yp = point.y();
543 output->addInstruction(instr);
546 case QVariant::PointF:
548 Instruction::StorePointF instr;
550 QPointF point = QDeclarativeStringConverters::pointFFromString(v->value.asString(), &ok);
551 instr.propertyIndex = prop->index;
552 instr.point.xp = point.x();
553 instr.point.yp = point.y();
554 output->addInstruction(instr);
559 Instruction::StoreSize instr;
561 QSize size = QDeclarativeStringConverters::sizeFFromString(v->value.asString(), &ok).toSize();
562 instr.propertyIndex = prop->index;
563 instr.size.wd = size.width();
564 instr.size.ht = size.height();
565 output->addInstruction(instr);
568 case QVariant::SizeF:
570 Instruction::StoreSizeF instr;
572 QSizeF size = QDeclarativeStringConverters::sizeFFromString(v->value.asString(), &ok);
573 instr.propertyIndex = prop->index;
574 instr.size.wd = size.width();
575 instr.size.ht = size.height();
576 output->addInstruction(instr);
581 Instruction::StoreRect instr;
583 QRect rect = QDeclarativeStringConverters::rectFFromString(v->value.asString(), &ok).toRect();
584 instr.propertyIndex = prop->index;
585 instr.rect.x1 = rect.left();
586 instr.rect.y1 = rect.top();
587 instr.rect.x2 = rect.right();
588 instr.rect.y2 = rect.bottom();
589 output->addInstruction(instr);
592 case QVariant::RectF:
594 Instruction::StoreRectF instr;
596 QRectF rect = QDeclarativeStringConverters::rectFFromString(v->value.asString(), &ok);
597 instr.propertyIndex = prop->index;
598 instr.rect.xp = rect.left();
599 instr.rect.yp = rect.top();
600 instr.rect.w = rect.width();
601 instr.rect.h = rect.height();
602 output->addInstruction(instr);
607 Instruction::StoreBool instr;
608 bool b = v->value.asBoolean();
609 instr.propertyIndex = prop->index;
611 output->addInstruction(instr);
614 case QVariant::Vector3D:
616 Instruction::StoreVector3D instr;
618 QVector3D vector = QDeclarativeStringConverters::vector3DFromString(v->value.asString(), &ok);
619 instr.propertyIndex = prop->index;
620 instr.vector.xp = vector.x();
621 instr.vector.yp = vector.y();
622 instr.vector.zp = vector.z();
623 output->addInstruction(instr);
626 case QVariant::Vector4D:
628 Instruction::StoreVector4D instr;
630 QVector4D vector = QDeclarativeStringConverters::vector4DFromString(v->value.asString(), &ok);
631 instr.propertyIndex = prop->index;
632 instr.vector.xp = vector.x();
633 instr.vector.yp = vector.y();
634 instr.vector.zp = vector.z();
635 instr.vector.wp = vector.w();
636 output->addInstruction(instr);
641 Instruction::AssignCustomType instr;
642 instr.propertyIndex = prop->index;
643 instr.primitive = output->indexForString(v->value.asString());
645 output->addInstruction(instr);
652 Resets data by clearing the lists that the QDeclarativeCompiler modifies.
654 void QDeclarativeCompiler::reset(QDeclarativeCompiledData *data)
657 data->primitives.clear();
659 data->bytecode.resize(0);
663 Compile \a unit, and store the output in \a out. \a engine is the QDeclarativeEngine
664 with which the QDeclarativeCompiledData will be associated.
666 Returns true on success, false on failure. On failure, the compile errors
667 are available from errors().
669 If the environment variant QML_COMPILER_DUMP is set
670 (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
671 on a successful compiler.
673 bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine,
674 QDeclarativeTypeData *unit,
675 QDeclarativeCompiledData *out)
682 QDeclarativeScript::Object *root = unit->parser().tree();
685 this->engine = engine;
686 this->enginePrivate = QDeclarativeEnginePrivate::get(engine);
688 this->unitRoot = root;
692 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
693 QList<QDeclarativeScript::TypeReference *> referencedTypes = unit->parser().referencedTypes();
695 for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
696 QDeclarativeCompiledData::TypeReference ref;
698 const QDeclarativeTypeData::TypeReference &tref = resolvedTypes.at(ii);
699 QDeclarativeScript::TypeReference *parserRef = referencedTypes.at(ii);
702 ref.type = tref.type;
703 if (!ref.type->isCreatable()) {
704 QString err = ref.type->noCreationReason();
706 err = tr( "Element is not creatable.");
707 COMPILE_EXCEPTION(parserRef->refObjects.first(), err);
710 if (ref.type->containsRevisionedAttributes()) {
711 QDeclarativeError cacheError;
712 ref.typePropertyCache = enginePrivate->cache(ref.type, resolvedTypes.at(ii).minorVersion,
714 if (!ref.typePropertyCache)
715 COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description());
716 ref.typePropertyCache->addref();
719 } else if (tref.typeData) {
720 ref.component = tref.typeData->compiledData();
722 ref.className = parserRef->name;
730 out->dumpInstructions();
733 Q_ASSERT(out->rootPropertyCache);
741 this->enginePrivate = 0;
748 void QDeclarativeCompiler::compileTree(QDeclarativeScript::Object *tree)
750 compileState = pool->New<ComponentCompileState>();
752 compileState->root = tree;
754 componentStats->componentStat.lineNumber = tree->location.start.line;
756 // Build global import scripts
757 QStringList importedScriptIndexes;
759 foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
760 importedScriptIndexes.append(script.qualifier);
763 // We generate the importCache before we build the tree so that
764 // it can be used in the binding compiler. Given we "expect" the
765 // QML compilation to succeed, this isn't a waste.
766 output->importCache = new QDeclarativeTypeNameCache();
767 for (int ii = 0; ii < importedScriptIndexes.count(); ++ii)
768 output->importCache->add(importedScriptIndexes.at(ii), ii);
769 unit->imports().populateCache(output->importCache, engine);
771 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
774 Instruction::Init init;
775 init.bindingsSize = compileState->totalBindingsCount;
776 init.parserStatusSize = compileState->parserStatusCount;
777 init.contextCache = genContextCache();
778 init.objectStackSize = compileState->objectDepth.maxDepth();
779 init.listStackSize = compileState->listDepth.maxDepth();
780 if (compileState->compiledBindingData.isEmpty())
781 init.compiledBinding = -1;
783 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
784 output->addInstruction(init);
786 foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
787 Instruction::StoreImportedScript import;
788 import.value = output->scripts.count();
790 QDeclarativeScriptData *scriptData = script.script->scriptData();
791 scriptData->addref();
792 output->scripts << scriptData;
793 output->addInstruction(import);
796 if (!compileState->v8BindingProgram.isEmpty()) {
797 Instruction::InitV8Bindings bindings;
798 bindings.program = output->indexForString(compileState->v8BindingProgram);
799 bindings.programIndex = compileState->v8BindingProgramIndex;
800 bindings.line = compileState->v8BindingProgramLine;
801 output->addInstruction(bindings);
806 Instruction::SetDefault def;
807 output->addInstruction(def);
809 Instruction::Done done;
810 output->addInstruction(done);
812 Q_ASSERT(tree->metatype);
814 if (tree->metadata.isEmpty()) {
815 output->root = tree->metatype;
817 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
818 output->root = &output->rootData;
820 if (!tree->metadata.isEmpty())
821 enginePrivate->registerCompositeType(output);
824 static bool QStringList_contains(const QStringList &list, const QHashedStringRef &string)
826 for (int ii = 0; ii < list.count(); ++ii)
827 if (string == list.at(ii))
833 bool QDeclarativeCompiler::buildObject(QDeclarativeScript::Object *obj, const BindingContext &ctxt)
836 componentStats->componentStat.objects++;
838 Q_ASSERT (obj->type != -1);
839 const QDeclarativeCompiledData::TypeReference &tr = output->types.at(obj->type);
840 obj->metatype = tr.metaObject();
843 obj->typeName = tr.type->qmlTypeName();
845 // This object is a "Component" element
846 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
847 COMPILE_CHECK(buildComponent(obj, ctxt));
852 typedef QDeclarativeInstruction I;
853 const I *init = ((const I *)tr.component->bytecode.constData());
854 Q_ASSERT(init && tr.component->instructionType(init) == QDeclarativeInstruction::Init);
856 // Adjust stack depths to include nested components
857 compileState->objectDepth.pushPop(init->init.objectStackSize);
858 compileState->listDepth.pushPop(init->init.listStackSize);
859 compileState->parserStatusCount += init->init.parserStatusSize;
860 compileState->totalBindingsCount += init->init.bindingsSize;
863 compileState->objectDepth.push();
865 // Object instantiations reset the binding context
866 BindingContext objCtxt(obj);
868 // Create the synthesized meta object, ignoring aliases
869 COMPILE_CHECK(checkDynamicMeta(obj));
870 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
871 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
873 // Find the native type and check for the QDeclarativeParserStatus interface
874 QDeclarativeType *type = toQmlType(obj);
876 obj->parserStatusCast = type->parserStatusCast();
877 if (obj->parserStatusCast != -1)
878 compileState->parserStatusCount++;
880 // Check if this is a custom parser type. Custom parser types allow
881 // assignments to non-existent properties. These assignments are then
882 // compiled by the type.
883 bool isCustomParser = output->types.at(obj->type).type &&
884 output->types.at(obj->type).type->customParser() != 0;
885 QList<QDeclarativeCustomParserProperty> customProps;
887 // Fetch the list of deferred properties
888 QStringList deferredList = deferredProperties(obj);
890 // Must do id property first. This is to ensure that the id given to any
891 // id reference created matches the order in which the objects are
893 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
894 if (prop->name() == id_string) {
895 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
901 Property *defaultProperty = 0;
902 Property *skipProperty = 0;
903 if (obj->defaultProperty) {
904 defaultProperty = obj->defaultProperty;
906 Property *explicitProperty = 0;
908 const QMetaObject *mo = obj->metatype;
909 int idx = mo->indexOfClassInfo("DefaultProperty");
911 QMetaClassInfo info = mo->classInfo(idx);
912 const char *p = info.value();
916 while (char c = p[plen++]) { ord |= c; };
920 // Utf8 - unoptimal, but seldom hit
921 QString *s = pool->NewString(QString::fromUtf8(p, plen));
922 QHashedStringRef r(*s);
924 if (obj->propertiesHashField.test(r.hash())) {
925 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
926 if (ep->name() == r) {
927 explicitProperty = ep;
933 if (!explicitProperty)
934 defaultProperty->setName(r);
937 QHashedCStringRef r(p, plen);
939 if (obj->propertiesHashField.test(r.hash())) {
940 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
941 if (ep->name() == r) {
942 explicitProperty = ep;
948 if (!explicitProperty) {
949 // Set the default property name
950 QChar *buffer = pool->NewRawArray<QChar>(r.length());
951 r.writeUtf16(buffer);
952 defaultProperty->setName(QHashedStringRef(buffer, r.length(), r.hash()));
958 if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) {
960 skipProperty = explicitProperty; // We merge the values into defaultProperty
962 // Find the correct insertion point
963 Value *insertPos = 0;
965 for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) {
966 if (!(v->location.start < explicitProperty->values.first()->location.start))
971 defaultProperty->values.insertAfter(insertPos, explicitProperty->values);
975 QDeclarativeCustomParser *cp = 0;
977 cp = output->types.at(obj->type).type->customParser();
979 // Build all explicit properties specified
980 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
982 if (prop == skipProperty)
984 if (prop->name() == id_string)
987 bool canDefer = false;
988 if (isCustomParser) {
989 if (doesPropertyExist(prop, obj) &&
990 (!(cp->flags() & QDeclarativeCustomParser::AcceptsAttachedProperties) ||
991 !isAttachedPropertyName(prop->name()))) {
992 int ids = compileState->ids.count();
993 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
994 canDefer = ids == compileState->ids.count();
995 } else if (isSignalPropertyName(prop->name()) &&
996 (cp->flags() & QDeclarativeCustomParser::AcceptsSignalHandlers)) {
997 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
999 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
1002 if (isSignalPropertyName(prop->name())) {
1003 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1005 int ids = compileState->ids.count();
1006 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1007 canDefer = ids == compileState->ids.count();
1011 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1012 prop->isDeferred = true;
1016 // Build the default property
1017 if (defaultProperty) {
1018 Property *prop = defaultProperty;
1020 bool canDefer = false;
1021 if (isCustomParser) {
1022 if (doesPropertyExist(prop, obj)) {
1023 int ids = compileState->ids.count();
1024 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1025 canDefer = ids == compileState->ids.count();
1027 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
1030 int ids = compileState->ids.count();
1031 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1032 canDefer = ids == compileState->ids.count();
1035 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1036 prop->isDeferred = true;
1039 // Compile custom parser parts
1040 if (isCustomParser && !customProps.isEmpty()) {
1042 cp->compiler = this;
1044 obj->custom = cp->compile(customProps);
1047 foreach (QDeclarativeError err, cp->errors()) {
1048 err.setUrl(output->url);
1053 compileState->objectDepth.pop();
1058 void QDeclarativeCompiler::genObject(QDeclarativeScript::Object *obj)
1060 QDeclarativeCompiledData::TypeReference &tr = output->types[obj->type];
1061 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
1066 // Create the object
1067 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
1068 !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) {
1070 Instruction::CreateSimpleObject create;
1071 create.create = output->types.at(obj->type).type->createFunction();
1072 create.typeSize = output->types.at(obj->type).type->createSize();
1073 create.type = obj->type;
1074 create.line = obj->location.start.line;
1075 create.column = obj->location.start.column;
1076 output->addInstruction(create);
1080 if (output->types.at(obj->type).type) {
1081 Instruction::CreateCppObject create;
1082 create.line = obj->location.start.line;
1083 create.column = obj->location.start.column;
1085 if (!obj->custom.isEmpty())
1086 create.data = output->indexForByteArray(obj->custom);
1087 create.type = obj->type;
1088 create.isRoot = (compileState->root == obj);
1089 output->addInstruction(create);
1091 Instruction::CreateQMLObject create;
1092 create.type = obj->type;
1093 create.isRoot = (compileState->root == obj);
1095 if (!obj->bindingBitmask.isEmpty()) {
1096 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
1097 create.bindingBits = output->indexForByteArray(obj->bindingBitmask);
1099 create.bindingBits = -1;
1101 output->addInstruction(create);
1103 Instruction::CompleteQMLObject complete;
1104 complete.line = obj->location.start.line;
1105 complete.column = obj->location.start.column;
1106 complete.isRoot = (compileState->root == obj);
1107 output->addInstruction(complete);
1111 // Setup the synthesized meta object if necessary
1112 if (!obj->metadata.isEmpty()) {
1113 Instruction::StoreMetaObject meta;
1114 meta.data = output->indexForByteArray(obj->metadata);
1115 meta.aliasData = output->indexForByteArray(obj->synthdata);
1116 meta.propertyCache = output->propertyCaches.count();
1118 QDeclarativePropertyCache *propertyCache = obj->synthCache;
1119 Q_ASSERT(propertyCache);
1120 propertyCache->addref();
1122 // Add flag for alias properties
1123 if (!obj->synthdata.isEmpty()) {
1124 const QDeclarativeVMEMetaData *vmeMetaData =
1125 reinterpret_cast<const QDeclarativeVMEMetaData *>(obj->synthdata.constData());
1126 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
1127 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
1128 QDeclarativePropertyData *data = propertyCache->property(index);
1129 data->setFlags(data->getFlags() | QDeclarativePropertyData::IsAlias);
1133 if (obj == unitRoot) {
1134 propertyCache->addref();
1135 output->rootPropertyCache = propertyCache;
1138 output->propertyCaches << propertyCache;
1139 output->addInstruction(meta);
1140 } else if (obj == unitRoot) {
1141 output->rootPropertyCache = tr.createPropertyCache(engine);
1142 output->rootPropertyCache->addref();
1145 // Set the object id
1146 if (!obj->id.isEmpty()) {
1147 Instruction::SetId id;
1148 id.value = output->indexForString(obj->id);
1149 id.index = obj->idIndex;
1150 output->addInstruction(id);
1154 if (tr.type && obj->parserStatusCast != -1) {
1155 Instruction::BeginObject begin;
1156 begin.castValue = obj->parserStatusCast;
1157 output->addInstruction(begin);
1163 void QDeclarativeCompiler::genObjectBody(QDeclarativeScript::Object *obj)
1165 for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1166 Q_ASSERT(prop->scriptStringScope != -1);
1167 const QString &script = prop->values.first()->value.asScript();
1168 Instruction::StoreScriptString ss;
1169 ss.propertyIndex = prop->index;
1170 ss.value = output->indexForString(script);
1171 ss.scope = prop->scriptStringScope;
1172 // ss.bindingId = rewriteBinding(script, prop->name());
1173 ss.bindingId = rewriteBinding(prop->values.first()->value, QString()); // XXX
1174 ss.line = prop->location.start.line;
1175 output->addInstruction(ss);
1178 bool seenDefer = false;
1179 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1180 if (prop->isDeferred) {
1185 genValueProperty(prop, obj);
1188 Instruction::Defer defer;
1189 defer.deferCount = 0;
1190 int deferIdx = output->addInstruction(defer);
1191 int nextInstructionIndex = output->nextInstructionIndex();
1193 Instruction::DeferInit dinit;
1194 // XXX - these are now massive over allocations
1195 dinit.bindingsSize = compileState->totalBindingsCount;
1196 dinit.parserStatusSize = compileState->parserStatusCount;
1197 dinit.objectStackSize = compileState->objectDepth.maxDepth();
1198 dinit.listStackSize = compileState->listDepth.maxDepth();
1199 output->addInstruction(dinit);
1201 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1202 if (!prop->isDeferred)
1204 genValueProperty(prop, obj);
1207 Instruction::Done done;
1208 output->addInstruction(done);
1210 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1213 for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1215 QDeclarativeScript::Value *v = prop->values.first();
1217 if (v->type == Value::SignalObject) {
1219 genObject(v->object);
1221 Instruction::AssignSignalObject assign;
1222 assign.line = v->location.start.line;
1223 assign.signal = output->indexForString(prop->name().toString());
1224 output->addInstruction(assign);
1226 } else if (v->type == Value::SignalExpression) {
1228 Instruction::StoreSignal store;
1229 store.signalIndex = prop->index;
1230 QDeclarativeRewrite::RewriteSignalHandler rewriteSignalHandler;
1231 const QString &rewrite =
1232 rewriteSignalHandler(v->value.asScript().trimmed(), prop->name().toString());
1233 store.value = output->indexForString(rewrite);
1234 store.context = v->signalExpressionContextStack;
1235 store.line = v->location.start.line;
1236 output->addInstruction(store);
1242 for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1243 Instruction::FetchAttached fetch;
1244 fetch.id = prop->index;
1245 fetch.line = prop->location.start.line;
1246 output->addInstruction(fetch);
1248 genObjectBody(prop->value);
1250 Instruction::PopFetchedObject pop;
1251 output->addInstruction(pop);
1254 for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1255 Instruction::FetchObject fetch;
1256 fetch.property = prop->index;
1257 fetch.line = prop->location.start.line;
1258 output->addInstruction(fetch);
1260 if (!prop->value->metadata.isEmpty()) {
1261 Instruction::StoreMetaObject meta;
1262 meta.data = output->indexForByteArray(prop->value->metadata);
1263 meta.aliasData = output->indexForByteArray(prop->value->synthdata);
1264 meta.propertyCache = -1;
1265 output->addInstruction(meta);
1268 genObjectBody(prop->value);
1270 Instruction::PopFetchedObject pop;
1271 output->addInstruction(pop);
1274 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1276 genValueTypeProperty(obj, prop);
1279 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1280 if (prop->isDeferred)
1283 genValueProperty(prop, obj);
1286 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1288 genValueTypeProperty(obj, prop);
1292 void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeScript::Object *obj,QDeclarativeScript::Property *prop)
1294 Instruction::FetchValueType fetch;
1295 fetch.property = prop->index;
1296 fetch.type = prop->type;
1297 fetch.bindingSkipList = 0;
1299 if (obj->type == -1 || output->types.at(obj->type).component) {
1300 // We only have to do this if this is a composite type. If it is a builtin
1301 // type it can't possibly already have bindings that need to be cleared.
1302 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1303 if (!vprop->values.isEmpty()) {
1304 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1305 fetch.bindingSkipList |= (1 << vprop->index);
1310 output->addInstruction(fetch);
1312 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1313 genPropertyAssignment(vprop, prop->value, prop);
1316 Instruction::PopValueType pop;
1317 pop.property = prop->index;
1318 pop.type = prop->type;
1319 pop.bindingSkipList = 0;
1320 output->addInstruction(pop);
1323 void QDeclarativeCompiler::genComponent(QDeclarativeScript::Object *obj)
1325 QDeclarativeScript::Object *root = obj->defaultProperty->values.first()->object;
1328 Instruction::CreateComponent create;
1329 create.line = root->location.start.line;
1330 create.column = root->location.start.column;
1331 create.endLine = root->location.end.line;
1332 create.isRoot = (compileState->root == obj);
1333 int createInstruction = output->addInstruction(create);
1334 int nextInstructionIndex = output->nextInstructionIndex();
1336 ComponentCompileState *oldCompileState = compileState;
1337 compileState = componentState(root);
1339 Instruction::Init init;
1340 init.bindingsSize = compileState->totalBindingsCount;
1341 init.parserStatusSize = compileState->parserStatusCount;
1342 init.contextCache = genContextCache();
1343 init.objectStackSize = compileState->objectDepth.maxDepth();
1344 init.listStackSize = compileState->listDepth.maxDepth();
1345 if (compileState->compiledBindingData.isEmpty())
1346 init.compiledBinding = -1;
1348 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
1349 output->addInstruction(init);
1351 if (!compileState->v8BindingProgram.isEmpty()) {
1352 Instruction::InitV8Bindings bindings;
1353 bindings.program = output->indexForString(compileState->v8BindingProgram);
1354 bindings.programIndex = compileState->v8BindingProgramIndex;
1355 bindings.line = compileState->v8BindingProgramLine;
1356 output->addInstruction(bindings);
1361 Instruction::SetDefault def;
1362 output->addInstruction(def);
1364 Instruction::Done done;
1365 output->addInstruction(done);
1367 output->instruction(createInstruction)->createComponent.count =
1368 output->nextInstructionIndex() - nextInstructionIndex;
1370 compileState = oldCompileState;
1372 if (!obj->id.isEmpty()) {
1373 Instruction::SetId id;
1374 id.value = output->indexForString(obj->id);
1375 id.index = obj->idIndex;
1376 output->addInstruction(id);
1379 if (obj == unitRoot) {
1380 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1381 output->rootPropertyCache->addref();
1385 bool QDeclarativeCompiler::buildComponent(QDeclarativeScript::Object *obj,
1386 const BindingContext &ctxt)
1388 // The special "Component" element can only have the id property and a
1389 // default property, that actually defines the component's tree
1391 compileState->objectDepth.push();
1393 // Find, check and set the "id" property (if any)
1394 Property *idProp = 0;
1395 if (obj->properties.isMany() ||
1396 (obj->properties.isOne() && obj->properties.first()->name() != id_string))
1397 COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
1399 if (!obj->properties.isEmpty())
1400 idProp = obj->properties.first();
1403 if (idProp->value || idProp->values.isMany() || idProp->values.first()->object)
1404 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1405 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1407 QString idVal = idProp->values.first()->primitive();
1409 if (compileState->ids.value(idVal))
1410 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1416 // Check the Component tree is well formed
1417 if (obj->defaultProperty &&
1418 (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
1419 (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
1420 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1422 if (!obj->dynamicProperties.isEmpty())
1423 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1424 if (!obj->dynamicSignals.isEmpty())
1425 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1426 if (!obj->dynamicSlots.isEmpty())
1427 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1429 QDeclarativeScript::Object *root = 0;
1430 if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
1431 root = obj->defaultProperty->values.first()->object;
1434 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1436 // Build the component tree
1437 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1439 compileState->objectDepth.pop();
1444 bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeScript::Object *obj,
1445 const BindingContext &ctxt)
1447 ComponentCompileState *oldComponentCompileState = compileState;
1448 compileState = pool->New<ComponentCompileState>();
1449 compileState->root = obj;
1450 compileState->nested = true;
1452 if (componentStats) {
1453 ComponentStat oldComponentStat = componentStats->componentStat;
1455 componentStats->componentStat = ComponentStat();
1456 componentStats->componentStat.lineNumber = obj->location.start.line;
1459 COMPILE_CHECK(buildObject(obj, ctxt));
1461 COMPILE_CHECK(completeComponentBuild());
1463 componentStats->componentStat = oldComponentStat;
1466 COMPILE_CHECK(buildObject(obj, ctxt));
1468 COMPILE_CHECK(completeComponentBuild());
1471 compileState = oldComponentCompileState;
1477 // Build a sub-object. A sub-object is one that was not created directly by
1478 // QML - such as a grouped property object, or an attached object. Sub-object's
1479 // can't have an id, involve a custom parser, have attached properties etc.
1480 bool QDeclarativeCompiler::buildSubObject(QDeclarativeScript::Object *obj, const BindingContext &ctxt)
1482 Q_ASSERT(obj->metatype);
1483 Q_ASSERT(!obj->defaultProperty);
1484 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1487 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1488 if (isSignalPropertyName(prop->name())) {
1489 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1491 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1498 int QDeclarativeCompiler::componentTypeRef()
1500 QDeclarativeType *t = QDeclarativeMetaType::qmlType(QLatin1String("QtQuick/Component"),2,0);
1501 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1502 if (output->types.at(ii).type == t)
1505 QDeclarativeCompiledData::TypeReference ref;
1506 ref.className = Component_string;
1508 output->types << ref;
1509 return output->types.count() - 1;
1512 bool QDeclarativeCompiler::buildSignal(QDeclarativeScript::Property *prop, QDeclarativeScript::Object *obj,
1513 const BindingContext &ctxt)
1515 Q_ASSERT(obj->metaObject());
1517 const QHashedStringRef &propName = prop->name();
1519 Q_ASSERT(propName.startsWith(on_string));
1520 QString name = propName.mid(2, -1).toString();
1522 // Note that the property name could start with any alpha or '_' or '$' character,
1523 // so we need to do the lower-casing of the first alpha character.
1524 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1525 if (name.at(firstAlphaIndex).isUpper()) {
1526 name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1531 bool notInRevision = false;
1533 QDeclarativePropertyData *sig = signal(obj, QStringRef(&name), ¬InRevision);
1537 if (notInRevision && 0 == property(obj, propName, 0)) {
1538 Q_ASSERT(obj->type != -1);
1539 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1540 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1542 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));
1544 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1548 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1550 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1554 if (prop->value || !prop->values.isOne())
1555 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1557 prop->index = sig->coreIndex;
1560 obj->addSignalProperty(prop);
1562 if (prop->values.first()->object) {
1563 COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1564 prop->values.first()->type = Value::SignalObject;
1566 prop->values.first()->type = Value::SignalExpression;
1568 if (!prop->values.first()->value.isScript())
1569 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1571 QString script = prop->values.first()->value.asScript().trimmed();
1572 if (script.isEmpty())
1573 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1575 prop->values.first()->signalExpressionContextStack = ctxt.stack;
1584 Returns true if (value) property \a prop exists on obj, false otherwise.
1586 bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeScript::Property *prop,
1587 QDeclarativeScript::Object *obj)
1589 if (prop->name().isEmpty())
1591 if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1594 return property(obj, prop->name()) != 0;
1597 bool QDeclarativeCompiler::buildProperty(QDeclarativeScript::Property *prop,
1598 QDeclarativeScript::Object *obj,
1599 const BindingContext &ctxt)
1601 if (prop->isEmpty())
1602 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1604 const QMetaObject *metaObject = obj->metaObject();
1605 Q_ASSERT(metaObject);
1607 if (isAttachedPropertyName(prop->name())) {
1608 // Setup attached property data
1610 if (ctxt.isSubContext()) {
1611 // Attached properties cannot be used on sub-objects. Sub-objects
1612 // always exist in a binding sub-context, which is what we test
1614 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1617 QDeclarativeType *type = 0;
1618 QDeclarativeImportedNamespace *typeNamespace = 0;
1619 unit->imports().resolveType(prop->name().toString(), &type, 0, 0, 0, &typeNamespace);
1621 if (typeNamespace) {
1622 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1625 } else if (!type || !type->attachedPropertiesType()) {
1626 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1630 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1632 Q_ASSERT(type->attachedPropertiesFunction());
1633 prop->index = type->attachedPropertiesId();
1634 prop->value->metatype = type->attachedPropertiesType();
1636 // Setup regular property data
1637 bool notInRevision = false;
1638 QDeclarativePropertyData *d =
1639 prop->name().isEmpty()?0:property(obj, prop->name(), ¬InRevision);
1641 if (d == 0 && notInRevision) {
1642 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1643 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1645 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));
1647 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1650 prop->index = d->coreIndex;
1652 } else if (prop->isDefault) {
1653 QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
1654 QDeclarativePropertyData defaultPropertyData;
1655 defaultPropertyData.load(p, engine);
1657 prop->setName(QLatin1String(p.name()));
1658 prop->core = defaultPropertyData;
1659 prop->index = prop->core.coreIndex;
1662 // We can't error here as the "id" property does not require a
1663 // successful index resolution
1664 if (prop->index != -1)
1665 prop->type = prop->core.propType;
1667 // Check if this is an alias
1668 if (prop->index != -1 &&
1670 prop->parent->type != -1 &&
1671 output->types.at(prop->parent->type).component) {
1673 QDeclarativePropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1674 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1675 prop->isAlias = true;
1678 if (prop->index != -1 && !prop->values.isEmpty())
1679 prop->parent->setBindingBit(prop->index);
1682 if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1684 // The magic "id" behavior doesn't apply when "id" is resolved as a
1685 // default property or to sub-objects (which are always in binding
1687 COMPILE_CHECK(buildIdProperty(prop, obj));
1688 if (prop->type == QVariant::String &&
1689 prop->values.first()->value.isString())
1690 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1692 } else if (isAttachedPropertyName(prop->name())) {
1694 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1696 } else if (prop->index == -1) {
1698 if (prop->isDefault) {
1699 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1701 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1704 } else if (prop->value) {
1706 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1708 } else if (prop->core.isQList()) {
1710 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1712 } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) {
1714 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1718 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1725 bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
1726 QDeclarativeScript::Property *nsProp,
1727 QDeclarativeScript::Object *obj,
1728 const BindingContext &ctxt)
1731 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1733 for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1735 if (!isAttachedPropertyName(prop->name()))
1736 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1738 // Setup attached property data
1740 QDeclarativeType *type = 0;
1741 unit->imports().resolveType(ns, prop->name().toString(), &type, 0, 0, 0);
1743 if (!type || !type->attachedPropertiesType())
1744 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1747 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1749 Q_ASSERT(type->attachedPropertiesFunction());
1750 prop->index = type->index();
1751 prop->value->metatype = type->attachedPropertiesType();
1753 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1759 void QDeclarativeCompiler::genValueProperty(QDeclarativeScript::Property *prop,
1760 QDeclarativeScript::Object *obj)
1762 if (prop->core.isQList()) {
1763 genListProperty(prop, obj);
1765 genPropertyAssignment(prop, obj);
1769 void QDeclarativeCompiler::genListProperty(QDeclarativeScript::Property *prop,
1770 QDeclarativeScript::Object *obj)
1772 int listType = enginePrivate->listType(prop->type);
1774 Instruction::FetchQList fetch;
1775 fetch.property = prop->index;
1776 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1777 fetch.type = listType;
1778 output->addInstruction(fetch);
1780 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1782 if (v->type == Value::CreatedObject) {
1784 genObject(v->object);
1785 if (listTypeIsInterface) {
1786 Instruction::AssignObjectList assign;
1787 assign.line = prop->location.start.line;
1788 output->addInstruction(assign);
1790 Instruction::StoreObjectQList store;
1791 output->addInstruction(store);
1794 } else if (v->type == Value::PropertyBinding) {
1796 genBindingAssignment(v, prop, obj);
1802 Instruction::PopQList pop;
1803 output->addInstruction(pop);
1806 void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeScript::Property *prop,
1807 QDeclarativeScript::Object *obj,
1808 QDeclarativeScript::Property *valueTypeProperty)
1810 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1812 Q_ASSERT(v->type == Value::CreatedObject ||
1813 v->type == Value::PropertyBinding ||
1814 v->type == Value::Literal);
1816 if (v->type == Value::CreatedObject) {
1818 genObject(v->object);
1820 if (QDeclarativeMetaType::isInterface(prop->type)) {
1822 Instruction::StoreInterface store;
1823 store.line = v->object->location.start.line;
1824 store.propertyIndex = prop->index;
1825 output->addInstruction(store);
1827 } else if (prop->type == QMetaType::QVariant) {
1829 if (prop->core.isVMEProperty()) {
1830 Instruction::StoreVarObject store;
1831 store.line = v->object->location.start.line;
1832 store.propertyIndex = prop->index;
1833 output->addInstruction(store);
1835 Instruction::StoreVariantObject store;
1836 store.line = v->object->location.start.line;
1837 store.propertyIndex = prop->index;
1838 output->addInstruction(store);
1844 Instruction::StoreObject store;
1845 store.line = v->object->location.start.line;
1846 store.propertyIndex = prop->index;
1847 output->addInstruction(store);
1850 } else if (v->type == Value::PropertyBinding) {
1852 genBindingAssignment(v, prop, obj, valueTypeProperty);
1854 } else if (v->type == Value::Literal) {
1856 genLiteralAssignment(prop, v);
1862 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
1864 Q_ASSERT(v->type == Value::ValueSource ||
1865 v->type == Value::ValueInterceptor);
1867 if (v->type == Value::ValueSource) {
1868 genObject(v->object);
1870 Instruction::StoreValueSource store;
1871 if (valueTypeProperty) {
1872 store.property = genValueTypeData(prop, valueTypeProperty);
1875 store.property = prop->core;
1878 QDeclarativeType *valueType = toQmlType(v->object);
1879 store.castValue = valueType->propertyValueSourceCast();
1880 output->addInstruction(store);
1882 } else if (v->type == Value::ValueInterceptor) {
1883 genObject(v->object);
1885 Instruction::StoreValueInterceptor store;
1886 if (valueTypeProperty) {
1887 store.property = genValueTypeData(prop, valueTypeProperty);
1890 store.property = prop->core;
1893 QDeclarativeType *valueType = toQmlType(v->object);
1894 store.castValue = valueType->propertyValueInterceptorCast();
1895 output->addInstruction(store);
1901 bool QDeclarativeCompiler::buildIdProperty(QDeclarativeScript::Property *prop,
1902 QDeclarativeScript::Object *obj)
1905 prop->values.isMany() ||
1906 prop->values.first()->object)
1907 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
1909 QDeclarativeScript::Value *idValue = prop->values.first();
1910 QString val = idValue->primitive();
1912 COMPILE_CHECK(checkValidId(idValue, val));
1914 if (compileState->ids.value(val))
1915 COMPILE_EXCEPTION(prop, tr("id is not unique"));
1917 prop->values.first()->type = Value::Id;
1925 void QDeclarativeCompiler::addId(const QString &id, QDeclarativeScript::Object *obj)
1928 Q_ASSERT(!compileState->ids.value(id));
1929 Q_ASSERT(obj->id == id);
1930 obj->idIndex = compileState->ids.count();
1931 compileState->ids.append(obj);
1934 void QDeclarativeCompiler::addBindingReference(BindingReference *ref)
1936 Q_ASSERT(ref->value && !ref->value->bindingReference);
1937 ref->value->bindingReference = ref;
1938 compileState->totalBindingsCount++;
1939 compileState->bindings.prepend(ref);
1942 void QDeclarativeCompiler::saveComponentState()
1944 Q_ASSERT(compileState->root);
1945 Q_ASSERT(compileState->root->componentCompileState == 0);
1947 compileState->root->componentCompileState = compileState;
1950 componentStats->savedComponentStats.append(componentStats->componentStat);
1953 QDeclarativeCompilerTypes::ComponentCompileState *
1954 QDeclarativeCompiler::componentState(QDeclarativeScript::Object *obj)
1956 Q_ASSERT(obj->componentCompileState);
1957 return obj->componentCompileState;
1960 // Build attached property object. In this example,
1964 // GridView is an attached property object.
1965 bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeScript::Property *prop,
1966 QDeclarativeScript::Object *obj,
1967 const BindingContext &ctxt)
1969 Q_ASSERT(prop->value);
1970 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
1972 compileState->objectDepth.push();
1974 obj->addAttachedProperty(prop);
1976 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1978 compileState->objectDepth.pop();
1984 // Build "grouped" properties. In this example:
1986 // font.pointSize: 12
1987 // font.family: "Helvetica"
1989 // font is a nested property. pointSize and family are not.
1990 bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeScript::Property *prop,
1991 QDeclarativeScript::Object *obj,
1992 const BindingContext &ctxt)
1994 Q_ASSERT(prop->type != 0);
1995 Q_ASSERT(prop->index != -1);
1997 if (QDeclarativeValueTypeFactory::isValueType(prop->type)) {
1998 if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
2000 if (!prop->values.isEmpty()) {
2001 if (prop->values.first()->location < prop->value->location) {
2002 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
2004 COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
2008 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) {
2009 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2013 if (prop->isAlias) {
2014 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
2015 vtProp->isAlias = true;
2019 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
2020 prop->value, obj, ctxt.incr()));
2021 obj->addValueTypeProperty(prop);
2023 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2027 // Load the nested property's meta type
2028 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
2029 if (!prop->value->metatype)
2030 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2032 if (!prop->values.isEmpty())
2033 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
2035 obj->addGroupedProperty(prop);
2037 compileState->objectDepth.push();
2039 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2041 compileState->objectDepth.pop();
2047 bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
2048 QDeclarativeScript::Object *obj,
2049 QDeclarativeScript::Object *baseObj,
2050 const BindingContext &ctxt)
2052 compileState->objectDepth.push();
2054 if (obj->defaultProperty)
2055 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
2056 obj->metatype = type->metaObject();
2058 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
2060 QDeclarativePropertyData *d = property(obj, prop->name());
2062 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
2064 prop->index = d->coreIndex;
2065 prop->type = d->propType;
2067 prop->isValueTypeSubProperty = true;
2070 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
2072 if (prop->values.isMany()) {
2073 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
2074 } else if (!prop->values.isEmpty()) {
2075 QDeclarativeScript::Value *value = prop->values.first();
2077 if (value->object) {
2078 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
2079 } else if (value->value.isScript()) {
2080 // ### Check for writability
2082 //optimization for <Type>.<EnumValue> enum assignments
2083 bool isEnumAssignment = false;
2085 if (prop->core.isEnum())
2086 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, value, &isEnumAssignment));
2088 if (isEnumAssignment) {
2089 value->type = Value::Literal;
2091 BindingReference *reference = pool->New<BindingReference>();
2092 reference->expression = value->value;
2093 reference->property = prop;
2094 reference->value = value;
2095 reference->bindingContext = ctxt;
2096 reference->bindingContext.owner++;
2097 addBindingReference(reference);
2098 value->type = Value::PropertyBinding;
2101 COMPILE_CHECK(testLiteralAssignment(prop, value));
2102 value->type = Value::Literal;
2106 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2107 Q_ASSERT(v->object);
2109 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
2112 obj->addValueProperty(prop);
2115 compileState->objectDepth.pop();
2120 // Build assignments to QML lists. QML lists are properties of type
2121 // QDeclarativeListProperty<T>. List properties can accept a list of
2122 // objects, or a single binding.
2123 bool QDeclarativeCompiler::buildListProperty(QDeclarativeScript::Property *prop,
2124 QDeclarativeScript::Object *obj,
2125 const BindingContext &ctxt)
2127 Q_ASSERT(prop->core.isQList());
2129 compileState->listDepth.push();
2133 obj->addValueProperty(prop);
2135 int listType = enginePrivate->listType(t);
2136 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
2138 bool assignedBinding = false;
2139 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2141 v->type = Value::CreatedObject;
2142 COMPILE_CHECK(buildObject(v->object, ctxt));
2144 // We check object coercian here. We check interface assignment
2146 if (!listTypeIsInterface) {
2147 if (!canCoerce(listType, v->object)) {
2148 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2152 } else if (v->value.isScript()) {
2153 if (assignedBinding)
2154 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2156 assignedBinding = true;
2157 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2158 v->type = Value::PropertyBinding;
2160 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2164 compileState->listDepth.pop();
2169 // Compiles an assignment to a QDeclarativeScriptString property
2170 bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeScript::Property *prop,
2171 QDeclarativeScript::Object *obj,
2172 const BindingContext &ctxt)
2174 if (prop->values.isMany())
2175 COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2177 if (prop->values.first()->object)
2178 COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2180 prop->scriptStringScope = ctxt.stack;
2181 obj->addScriptStringProperty(prop);
2186 // Compile regular property assignments of the form "property: <value>"
2187 bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeScript::Property *prop,
2188 QDeclarativeScript::Object *obj,
2189 const BindingContext &ctxt)
2191 obj->addValueProperty(prop);
2193 if (prop->values.isMany())
2194 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2196 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2199 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2203 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2208 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2209 Q_ASSERT(v->object);
2210 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2216 // Compile assigning a single object instance to a regular property
2217 bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeScript::Property *prop,
2218 QDeclarativeScript::Object *obj,
2219 QDeclarativeScript::Value *v,
2220 const BindingContext &ctxt)
2222 Q_ASSERT(prop->index != -1);
2223 Q_ASSERT(v->object->type != -1);
2225 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2226 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2228 if (QDeclarativeMetaType::isInterface(prop->type)) {
2230 // Assigning an object to an interface ptr property
2231 COMPILE_CHECK(buildObject(v->object, ctxt));
2233 v->type = Value::CreatedObject;
2235 } else if (prop->type == QMetaType::QVariant) {
2237 // Assigning an object to a QVariant
2238 COMPILE_CHECK(buildObject(v->object, ctxt));
2240 v->type = Value::CreatedObject;
2242 // Normally buildObject() will set this up, but we need the static
2243 // meta object earlier to test for assignability. It doesn't matter
2244 // that there may still be outstanding synthesized meta object changes
2245 // on this type, as they are not relevant for assignability testing
2246 v->object->metatype = output->types.at(v->object->type).metaObject();
2247 Q_ASSERT(v->object->metaObject());
2249 // We want to raw metaObject here as the raw metaobject is the
2250 // actual property type before we applied any extensions that might
2251 // effect the properties on the type, but don't effect assignability
2252 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2254 // Will be true if the assgned type inherits propertyMetaObject
2255 bool isAssignable = false;
2256 // Determine isAssignable value
2257 if (propertyMetaObject) {
2258 const QMetaObject *c = v->object->metatype;
2260 isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject));
2261 c = c->superClass();
2266 // Simple assignment
2267 COMPILE_CHECK(buildObject(v->object, ctxt));
2269 v->type = Value::CreatedObject;
2270 } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) {
2271 // Automatic "Component" insertion
2272 QDeclarativeScript::Object *root = v->object;
2273 QDeclarativeScript::Object *component = pool->New<Object>();
2274 component->type = componentTypeRef();
2275 component->typeName = QStringLiteral("Qt/Component");
2276 component->metatype = &QDeclarativeComponent::staticMetaObject;
2277 component->location = root->location;
2278 QDeclarativeScript::Value *componentValue = pool->New<Value>();
2279 componentValue->object = root;
2280 component->getDefaultProperty()->addValue(componentValue);
2281 v->object = component;
2282 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2284 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2291 // Compile assigning a single object instance to a regular property using the "on" syntax.
2295 // NumberAnimation on x { }
2297 bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeScript::Property *prop,
2298 QDeclarativeScript::Object *obj,
2299 QDeclarativeScript::Object *baseObj,
2300 QDeclarativeScript::Value *v,
2301 const BindingContext &ctxt)
2303 Q_ASSERT(prop->index != -1);
2304 Q_ASSERT(v->object->type != -1);
2308 if (!prop->core.isWritable())
2309 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2312 // Normally buildObject() will set this up, but we need the static
2313 // meta object earlier to test for assignability. It doesn't matter
2314 // that there may still be outstanding synthesized meta object changes
2315 // on this type, as they are not relevant for assignability testing
2316 v->object->metatype = output->types.at(v->object->type).metaObject();
2317 Q_ASSERT(v->object->metaObject());
2319 // Will be true if the assigned type inherits QDeclarativePropertyValueSource
2320 bool isPropertyValue = false;
2321 // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor
2322 bool isPropertyInterceptor = false;
2323 if (QDeclarativeType *valueType = toQmlType(v->object)) {
2324 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2325 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2328 if (isPropertyValue || isPropertyInterceptor) {
2329 // Assign as a property value source
2330 COMPILE_CHECK(buildObject(v->object, ctxt));
2332 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2333 buildDynamicMeta(baseObj, ForceCreation);
2334 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2336 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(v->object->typeName).arg(prop->name().toString()));
2342 // Compile assigning a literal or binding to a regular property
2343 bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeScript::Property *prop,
2344 QDeclarativeScript::Object *obj,
2345 QDeclarativeScript::Value *v,
2346 const BindingContext &ctxt)
2348 Q_ASSERT(prop->index != -1);
2350 if (v->value.isScript()) {
2352 //optimization for <Type>.<EnumValue> enum assignments
2353 if (prop->core.isEnum()) {
2354 bool isEnumAssignment = false;
2355 COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, v, &isEnumAssignment));
2356 if (isEnumAssignment) {
2357 v->type = Value::Literal;
2362 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2364 v->type = Value::PropertyBinding;
2368 COMPILE_CHECK(testLiteralAssignment(prop, v));
2370 v->type = Value::Literal;
2376 bool QDeclarativeCompiler::testQualifiedEnumAssignment(QDeclarativeScript::Property *prop,
2377 QDeclarativeScript::Object *obj,
2378 QDeclarativeScript::Value *v,
2381 *isAssignment = false;
2382 if (!prop->core.isEnum())
2385 QMetaProperty mprop = obj->metaObject()->property(prop->index);
2387 if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
2388 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2390 QString string = v->value.asString();
2391 if (!string.at(0).isUpper())
2394 QStringList parts = string.split(QLatin1Char('.'));
2395 if (parts.count() != 2)
2398 QString typeName = parts.at(0);
2399 QDeclarativeType *type = 0;
2400 unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
2402 //handle enums on value types (where obj->typeName is empty)
2403 QString objTypeName = obj->typeName;
2404 if (objTypeName.isEmpty()) {
2405 QDeclarativeType *objType = toQmlType(obj);
2407 objTypeName = objType->qmlTypeName();
2413 QString enumValue = parts.at(1);
2417 if (objTypeName == type->qmlTypeName()) {
2418 // When these two match, we can short cut the search
2419 if (mprop.isFlagType()) {
2420 value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
2422 value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
2425 // Otherwise we have to search the whole type
2426 // This matches the logic in QV8TypeWrapper
2427 QByteArray enumName = enumValue.toUtf8();
2428 const QMetaObject *metaObject = type->baseMetaObject();
2430 for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
2431 QMetaEnum e = metaObject->enumerator(ii);
2432 value = e.keyToValue(enumName.constData(), &ok);
2439 v->type = Value::Literal;
2440 v->value = QDeclarativeScript::Variant((double)value);
2441 *isAssignment = true;
2446 struct StaticQtMetaObject : public QObject
2448 static const QMetaObject *get()
2449 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2452 // Similar logic to above, but not knowing target property.
2453 int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const
2455 int dot = script.indexOf('.');
2457 const QByteArray &scope = script.left(dot);
2458 QDeclarativeType *type = 0;
2459 unit->imports().resolveType(QString::fromUtf8(script.left(dot)), &type, 0, 0, 0, 0);
2460 if (!type && scope != "Qt")
2462 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2463 const char *key = script.constData() + dot+1;
2464 int i = mo->enumeratorCount();
2467 int v = mo->enumerator(i).keyToValue(key, &ok);
2475 const QMetaObject *QDeclarativeCompiler::resolveType(const QString& name) const
2477 QDeclarativeType *qmltype = 0;
2478 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2482 return qmltype->metaObject();
2485 // similar to logic of completeComponentBuild, but also sticks data
2486 // into primitives at the end
2487 int QDeclarativeCompiler::rewriteBinding(const QDeclarativeScript::Variant& value, const QString& name)
2489 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2490 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1));
2492 QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0);
2494 return output->indexForString(rewrite);
2497 QString QDeclarativeCompiler::rewriteSignalHandler(const QString &handler, const QString &name)
2499 QDeclarativeRewrite::RewriteSignalHandler rewriteSignalHandler;
2500 return rewriteSignalHandler(handler, name);
2503 // Ensures that the dynamic meta specification on obj is valid
2504 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeScript::Object *obj)
2506 bool seenDefaultProperty = false;
2508 // We use a coarse grain, 31 bit hash to check if there are duplicates.
2509 // Calculating the hash for the names is not a waste as we have to test
2510 // them against the illegalNames set anyway.
2511 QHashField propNames;
2512 QHashField methodNames;
2515 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2516 const QDeclarativeScript::Object::DynamicProperty &prop = *p;
2518 if (prop.isDefaultProperty) {
2519 if (seenDefaultProperty)
2520 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2521 seenDefaultProperty = true;
2524 if (propNames.testAndSet(prop.name.hash())) {
2525 for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p;
2526 p2 = obj->dynamicProperties.next(p2)) {
2527 if (p2->name == prop.name)
2528 COMPILE_EXCEPTION(&prop, tr("Duplicate property name"));
2532 if (prop.name.at(0).isUpper())
2533 COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
2535 if (enginePrivate->v8engine()->illegalNames().contains(prop.name))
2536 COMPILE_EXCEPTION(&prop, tr("Illegal property name"));
2539 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2540 const QDeclarativeScript::Object::DynamicSignal &currSig = *s;
2542 if (methodNames.testAndSet(currSig.name.hash())) {
2543 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2544 s2 = obj->dynamicSignals.next(s2)) {
2545 if (s2->name == currSig.name)
2546 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2550 if (currSig.name.at(0).isUpper())
2551 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2552 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2553 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2556 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2557 const QDeclarativeScript::Object::DynamicSlot &currSlot = *s;
2559 if (methodNames.testAndSet(currSlot.name.hash())) {
2560 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2561 s2 = obj->dynamicSignals.next(s2)) {
2562 if (s2->name == currSlot.name)
2563 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2565 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2566 s2 = obj->dynamicSlots.next(s2)) {
2567 if (s2->name == currSlot.name)
2568 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2572 if (currSlot.name.at(0).isUpper())
2573 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2574 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2575 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2581 bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeScript::Object *obj)
2583 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
2584 p = obj->dynamicProperties.next(p)) {
2586 if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2589 Property *property = 0;
2590 if (p->isDefaultProperty) {
2591 property = obj->getDefaultProperty();
2593 property = obj->getProperty(p->name);
2594 if (!property->values.isEmpty())
2595 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2599 property->isReadOnlyDeclaration = true;
2601 if (property->value)
2602 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2604 property->values.append(p->defaultValue->values);
2609 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2611 bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeScript::Object *obj, DynamicMetaMode mode)
2614 Q_ASSERT(obj->metatype);
2616 if (mode != ForceCreation &&
2617 obj->dynamicProperties.isEmpty() &&
2618 obj->dynamicSignals.isEmpty() &&
2619 obj->dynamicSlots.isEmpty())
2622 bool resolveAlias = (mode == ResolveAliases);
2624 const Object::DynamicProperty *defaultProperty = 0;
2626 int varPropCount = 0;
2627 int totalPropCount = 0;
2628 int firstPropertyVarIndex = 0;
2630 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2632 if (p->type == Object::DynamicProperty::Alias)
2634 if (p->type == Object::DynamicProperty::Var)
2637 if (p->isDefaultProperty &&
2638 (resolveAlias || p->type != Object::DynamicProperty::Alias))
2639 defaultProperty = p;
2641 if (!resolveAlias) {
2642 // No point doing this for both the alias and non alias cases
2643 QDeclarativePropertyData *d = property(obj, p->name);
2644 if (d && d->isFinal())
2645 COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2649 bool buildData = resolveAlias || aliasCount == 0;
2651 QByteArray dynamicData;
2653 typedef QDeclarativeVMEMetaData VMD;
2655 dynamicData = QByteArray(sizeof(QDeclarativeVMEMetaData) +
2656 (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) +
2657 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2658 aliasCount * sizeof(VMD::AliasData), 0);
2661 int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1);
2663 QByteArray newClassName = obj->metatype->className();
2664 newClassName.append("_QML_");
2665 newClassName.append(QByteArray::number(uniqueClassId));
2667 if (compileState->root == obj && !compileState->nested) {
2668 QString path = output->url.path();
2669 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2670 if (lastSlash > -1) {
2671 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2672 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2673 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId);
2677 QFastMetaBuilder builder;
2678 QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(),
2679 obj->dynamicProperties.count() - (resolveAlias?0:aliasCount),
2680 obj->dynamicSlots.count(),
2681 obj->dynamicSignals.count() + obj->dynamicProperties.count(),
2682 defaultProperty?1:0);
2685 Object::DynamicProperty::Type dtype;
2687 const char *cppType;
2688 } builtinTypes[] = {
2689 { Object::DynamicProperty::Var, 0, "QVariant" },
2690 { Object::DynamicProperty::Variant, 0, "QVariant" },
2691 { Object::DynamicProperty::Int, QMetaType::Int, "int" },
2692 { Object::DynamicProperty::Bool, QMetaType::Bool, "bool" },
2693 { Object::DynamicProperty::Real, QMetaType::Double, "double" },
2694 { Object::DynamicProperty::String, QMetaType::QString, "QString" },
2695 { Object::DynamicProperty::Url, QMetaType::QUrl, "QUrl" },
2696 { Object::DynamicProperty::Color, QMetaType::QColor, "QColor" },
2697 { Object::DynamicProperty::Time, QMetaType::QTime, "QTime" },
2698 { Object::DynamicProperty::Date, QMetaType::QDate, "QDate" },
2699 { Object::DynamicProperty::DateTime, QMetaType::QDateTime, "QDateTime" },
2701 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2702 QFastMetaBuilder::StringRef typeRefs[builtinTypeCount];
2704 // Reserve dynamic properties
2705 if (obj->dynamicProperties.count()) {
2706 typedef QDeclarativeVMEMetaData VMD;
2708 int effectivePropertyIndex = 0;
2709 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2711 // Reserve space for name
2712 p->nameRef = builder.newString(p->name.utf8length());
2714 int propertyType = 0;
2715 bool readonly = false;
2716 QFastMetaBuilder::StringRef typeRef;
2718 if (p->type == Object::DynamicProperty::Alias) {
2720 } else if (p->type < builtinTypeCount) {
2721 Q_ASSERT(builtinTypes[p->type].dtype == p->type);
2722 propertyType = builtinTypes[p->type].metaType;
2723 if (typeRefs[p->type].isEmpty())
2724 typeRefs[p->type] = builder.newString(strlen(builtinTypes[p->type].cppType));
2725 typeRef = typeRefs[p->type];
2726 if (p->type == Object::DynamicProperty::Variant)
2730 Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
2731 p->type == Object::DynamicProperty::Custom);
2733 // XXX don't double resolve this in the case of an alias run
2735 QByteArray customTypeName;
2736 QDeclarativeType *qmltype = 0;
2738 if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
2739 COMPILE_EXCEPTION(p, tr("Invalid property type"));
2742 QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(QUrl(url));
2744 Q_ASSERT(tdata->isComplete());
2746 QDeclarativeCompiledData *data = tdata->compiledData();
2747 customTypeName = data->root->className();
2751 customTypeName = qmltype->typeName();
2754 if (p->type == Object::DynamicProperty::Custom) {
2755 customTypeName += '*';
2756 propertyType = QMetaType::QObjectStar;
2759 customTypeName = QByteArray("QDeclarativeListProperty<") + customTypeName + QByteArray(">");
2760 propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
2763 p->resolvedCustomTypeName = pool->NewByteArray(customTypeName);
2764 p->typeRef = builder.newString(customTypeName.length());
2765 typeRef = p->typeRef;
2768 if (p->type == Object::DynamicProperty::Var)
2775 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2776 vmd->propertyCount++;
2777 (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType;
2780 if (p->type < builtinTypeCount)
2781 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef, (QMetaType::Type)propertyType,
2782 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2783 effectivePropertyIndex);
2785 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef,
2786 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2787 effectivePropertyIndex);
2789 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2790 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2792 effectivePropertyIndex++;
2796 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2798 vmd->varPropertyCount = varPropCount;
2799 firstPropertyVarIndex = effectivePropertyIndex;
2800 totalPropCount = varPropCount + effectivePropertyIndex;
2801 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2802 if (p->type == Object::DynamicProperty::Var) {
2803 QFastMetaBuilder::StringRef typeRef = typeRefs[p->type];
2805 vmd->propertyCount++;
2806 (vmd->propertyData() + effectivePropertyIndex)->propertyType = -1;
2809 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef,
2810 (QMetaType::Type)-1,
2811 p->isReadOnly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2812 effectivePropertyIndex);
2814 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2815 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2817 effectivePropertyIndex++;
2824 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2825 if (p->type == Object::DynamicProperty::Alias) {
2827 Q_ASSERT(buildData);
2828 ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++;
2829 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex,
2832 // Even if we aren't resolving the alias, we need a fake signal so that the
2833 // metaobject remains consistent across the resolve and non-resolve alias runs
2834 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2835 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2836 effectivePropertyIndex++;
2843 // Reserve default property
2844 QFastMetaBuilder::StringRef defPropRef;
2845 if (defaultProperty) {
2846 defPropRef = builder.newString(strlen("DefaultProperty"));
2847 builder.setClassInfo(0, defPropRef, defaultProperty->nameRef);
2850 // Reserve dynamic signals
2851 int signalIndex = 0;
2852 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2854 int paramCount = s->parameterNames.count();
2856 int signatureSize = s->name.utf8length() + 2 /* paren */;
2858 if (paramCount) signatureSize += s->parameterTypesLength() + (paramCount - 1) /* commas */;
2859 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1) /* commas */;
2861 s->signatureRef = builder.newString(signatureSize);
2862 if (namesSize) s->parameterNamesRef = builder.newString(namesSize);
2865 ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++;
2867 builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->signatureRef, s->parameterNamesRef);
2871 // Reserve dynamic slots
2872 if (obj->dynamicSlots.count()) {
2874 // Allocate QVariant string
2875 if (typeRefs[0].isEmpty())
2876 typeRefs[0] = builder.newString(strlen(builtinTypes[0].cppType));
2878 typedef QDeclarativeVMEMetaData VMD;
2880 int methodIndex = 0;
2881 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2882 int paramCount = s->parameterNames.count();
2884 int signatureSize = s->name.utf8length() + 2 /* paren */;
2886 if (paramCount) signatureSize += (paramCount * strlen("QVariant") + (paramCount - 1));
2887 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
2889 s->signatureRef = builder.newString(signatureSize);
2890 if (namesSize) s->parameterNamesRef = builder.newString(namesSize);
2892 builder.setMethod(methodIndex, s->signatureRef, s->parameterNamesRef, typeRefs[0]);
2896 funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ +
2897 namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
2898 funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
2899 for (int jj = 0; jj < paramCount; ++jj) {
2900 if (jj) funcScript.append(QLatin1Char(','));
2901 funcScript.append(QLatin1String(s->parameterNames.at(jj)));
2903 funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
2905 VMD::MethodData methodData = { s->parameterNames.count(), 0,
2906 funcScript.length(),
2907 s->location.start.line };
2909 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2912 VMD::MethodData &md = *(vmd->methodData() + methodIndex);
2914 md.bodyOffset = dynamicData.size();
2916 dynamicData.append((const char *)funcScript.constData(),
2917 (funcScript.length() * sizeof(QChar)));
2924 // Now allocate used builtin types
2925 for (int ii = 0; ii < builtinTypeCount; ++ii) {
2926 if (!typeRefs[ii].isEmpty())
2927 typeRefs[ii].load(builtinTypes[ii].cppType);
2930 // Now allocate properties
2931 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2933 char *d = p->changedSignatureRef.data();
2934 p->name.writeUtf8(d);
2935 strcpy(d + p->name.utf8length(), "Changed()");
2937 if (p->type == Object::DynamicProperty::Alias && !resolveAlias)
2940 p->nameRef.load(p->name);
2942 if (p->type >= builtinTypeCount) {
2943 Q_ASSERT(p->resolvedCustomTypeName);
2944 p->typeRef.load(*p->resolvedCustomTypeName);
2948 // Allocate default property if necessary
2949 if (defaultProperty)
2950 strcpy(defPropRef.data(), "DefaultProperty");
2952 // Now allocate signals
2953 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2955 char *d = s->signatureRef.data();
2956 char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data();
2957 s->name.writeUtf8(d); d += s->name.utf8length();
2960 for (int jj = 0; jj < s->parameterNames.count(); ++jj) {
2961 if (jj != 0) { *d++ = ','; *d2++ = ','; }
2962 strcpy(d, s->parameterTypes.at(jj).constData());
2963 d += s->parameterTypes.at(jj).length();
2964 s->parameterNames.at(jj).writeUtf8(d2);
2965 d2 += s->parameterNames.at(jj).utf8length();
2972 // Now allocate methods
2973 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2974 char *d = s->signatureRef.data();
2975 char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data();
2976 s->name.writeUtf8(d); d += s->name.utf8length();
2978 for (int jj = 0; jj < s->parameterNames.count(); ++jj) {
2979 if (jj != 0) { *d++ = ','; *d2++ = ','; }
2980 strcpy(d, "QVariant");
2981 d += strlen("QVariant");
2982 strcpy(d2, s->parameterNames.at(jj).constData());
2983 d2 += s->parameterNames.at(jj).length();
2990 // Now allocate class name
2991 classNameRef.load(newClassName);
2993 obj->metadata = builder.toData();
2994 builder.fromData(&obj->extObject, obj->metatype, obj->metadata);
2996 if (mode == IgnoreAliases && aliasCount)
2997 compileState->aliasingObjects.append(obj);
2999 obj->synthdata = dynamicData;
3001 if (obj->synthCache) {
3002 obj->synthCache->release();
3003 obj->synthCache = 0;
3006 if (obj->type != -1) {
3007 QDeclarativePropertyCache *cache = output->types[obj->type].createPropertyCache(engine)->copy();
3008 cache->append(engine, &obj->extObject,
3009 QDeclarativePropertyData::NoFlags,
3010 QDeclarativePropertyData::IsVMEFunction,
3011 QDeclarativePropertyData::IsVMESignal);
3013 // now we modify the flags appropriately for var properties.
3014 int propertyOffset = obj->extObject.propertyOffset();
3015 QDeclarativePropertyData *currPropData = 0;
3016 for (int pvi = firstPropertyVarIndex; pvi < totalPropCount; ++pvi) {
3017 currPropData = cache->property(pvi + propertyOffset);
3018 currPropData->setFlags(currPropData->getFlags() | QDeclarativePropertyData::IsVMEProperty);
3021 obj->synthCache = cache;
3027 bool QDeclarativeCompiler::checkValidId(QDeclarativeScript::Value *v, const QString &val)
3030 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
3032 QChar ch = val.at(0);
3033 if (ch.isLetter() && !ch.isLower())
3034 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
3036 QChar u(QLatin1Char('_'));
3037 if (!ch.isLetter() && ch != u)
3038 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
3040 for (int ii = 1; ii < val.count(); ++ii) {
3042 if (!ch.isLetterOrNumber() && ch != u)
3043 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
3046 if (enginePrivate->v8engine()->illegalNames().contains(val))
3047 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
3052 #include <private/qdeclarativejsparser_p.h>
3054 static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node)
3056 if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) {
3058 static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name.toString();
3059 return QStringList() << name;
3060 } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) {
3061 QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node);
3063 QStringList rv = astNodeToStringList(expr->base);
3066 rv.append(expr->name.toString());
3069 return QStringList();
3072 bool QDeclarativeCompiler::compileAlias(QFastMetaBuilder &builder,
3074 QDeclarativeScript::Object *obj,
3075 int propIndex, int aliasIndex,
3076 Object::DynamicProperty &prop)
3078 if (!prop.defaultValue)
3079 COMPILE_EXCEPTION(obj, tr("No property alias location"));
3081 if (!prop.defaultValue->values.isOne() ||
3082 prop.defaultValue->values.first()->object ||
3083 !prop.defaultValue->values.first()->value.isScript())
3084 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3086 QDeclarativeJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST();
3088 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
3090 QStringList alias = astNodeToStringList(node);
3092 if (alias.count() < 1 || alias.count() > 3)
3093 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
3095 QDeclarativeScript::Object *idObject = compileState->ids.value(alias.at(0));
3097 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
3099 QByteArray typeName;
3104 bool writable = false;
3105 bool resettable = false;
3106 if (alias.count() == 2 || alias.count() == 3) {
3107 propIdx = indexOfProperty(idObject, alias.at(1));
3109 if (-1 == propIdx) {
3110 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3111 } else if (propIdx > 0xFFFF) {
3112 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
3115 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
3116 if (!aliasProperty.isScriptable())
3117 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3119 writable = aliasProperty.isWritable() && !prop.isReadOnly;
3120 resettable = aliasProperty.isResettable() && !prop.isReadOnly;
3122 if (aliasProperty.type() < QVariant::UserType ||
3123 aliasProperty.type() == QVariant::LastType /* for QVariant */ )
3124 type = aliasProperty.type();
3126 if (alias.count() == 3) {
3127 QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
3129 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3131 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
3133 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
3134 if (valueTypeIndex == -1)
3135 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3136 Q_ASSERT(valueTypeIndex <= 0xFF);
3138 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
3139 propIdx |= (valueTypeIndex << 16);
3141 // update the property type
3142 type = aliasProperty.type();
3143 if (type >= (int)QVariant::UserType)
3147 if (aliasProperty.isEnumType())
3148 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
3150 typeName = aliasProperty.typeName();
3152 Q_ASSERT(idObject->type != -1); // How else did it get an id?
3154 const QDeclarativeCompiledData::TypeReference &ref = output->types.at(idObject->type);
3156 typeName = ref.type->typeName();
3158 typeName = ref.component->root->className();
3163 if (typeName.endsWith('*'))
3164 flags |= QML_ALIAS_FLAG_PTR;
3166 QDeclarativeVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags };
3168 typedef QDeclarativeVMEMetaData VMD;
3169 VMD *vmd = (QDeclarativeVMEMetaData *)data.data();
3170 *(vmd->aliasData() + aliasIndex) = aliasData;
3172 prop.nameRef = builder.newString(prop.name.utf8length());
3173 prop.resolvedCustomTypeName = pool->NewByteArray(typeName);
3174 prop.typeRef = builder.newString(typeName.length());
3176 int propertyFlags = 0;
3178 propertyFlags |= QFastMetaBuilder::Writable;
3180 propertyFlags |= QFastMetaBuilder::Resettable;
3182 builder.setProperty(propIndex, prop.nameRef, prop.typeRef, (QMetaType::Type)type,
3183 (QFastMetaBuilder::PropertyFlag)propertyFlags,
3189 bool QDeclarativeCompiler::buildBinding(QDeclarativeScript::Value *value,
3190 QDeclarativeScript::Property *prop,
3191 const BindingContext &ctxt)
3193 Q_ASSERT(prop->index != -1);
3194 Q_ASSERT(prop->parent);
3195 Q_ASSERT(prop->parent->metaObject());
3197 if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
3198 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3200 BindingReference *reference = pool->New<BindingReference>();
3201 reference->expression = value->value;
3202 reference->property = prop;
3203 reference->value = value;
3204 reference->bindingContext = ctxt;
3205 addBindingReference(reference);
3210 void QDeclarativeCompiler::genBindingAssignment(QDeclarativeScript::Value *binding,
3211 QDeclarativeScript::Property *prop,
3212 QDeclarativeScript::Object *obj,
3213 QDeclarativeScript::Property *valueTypeProperty)
3216 Q_ASSERT(binding->bindingReference);
3218 const BindingReference &ref = *binding->bindingReference;
3219 if (ref.dataType == BindingReference::V4) {
3220 Instruction::StoreV4Binding store;
3221 store.value = ref.compiledIndex;
3222 store.context = ref.bindingContext.stack;
3223 store.owner = ref.bindingContext.owner;
3224 if (valueTypeProperty) {
3225 store.property = (valueTypeProperty->index & 0xFFFF) |
3226 ((valueTypeProperty->type & 0xFF)) << 16 |
3227 ((prop->index & 0xFF) << 24);
3228 store.isRoot = (compileState->root == valueTypeProperty->parent);
3230 store.property = prop->index;
3231 store.isRoot = (compileState->root == obj);
3233 store.line = binding->location.start.line;
3234 output->addInstruction(store);
3235 } else if (ref.dataType == BindingReference::V8) {
3236 Instruction::StoreV8Binding store;
3237 store.value = ref.compiledIndex;
3238 store.context = ref.bindingContext.stack;
3239 store.owner = ref.bindingContext.owner;
3240 if (valueTypeProperty) {
3241 store.isRoot = (compileState->root == valueTypeProperty->parent);
3243 store.isRoot = (compileState->root == obj);
3245 store.line = binding->location.start.line;
3247 Q_ASSERT(ref.bindingContext.owner == 0 ||
3248 (ref.bindingContext.owner != 0 && valueTypeProperty));
3249 if (ref.bindingContext.owner) {
3250 store.property = genValueTypeData(prop, valueTypeProperty);
3252 store.property = prop->core;
3255 output->addInstruction(store);
3257 QDeclarativeInstruction store;
3258 store.assignBinding.value = output->indexForString(ref.rewrittenExpression);
3259 store.assignBinding.context = ref.bindingContext.stack;
3260 store.assignBinding.owner = ref.bindingContext.owner;
3261 store.assignBinding.line = binding->location.start.line;
3263 if (valueTypeProperty) {
3264 store.assignBinding.isRoot = (compileState->root == valueTypeProperty->parent);
3266 store.assignBinding.isRoot = (compileState->root == obj);
3269 Q_ASSERT(ref.bindingContext.owner == 0 ||
3270 (ref.bindingContext.owner != 0 && valueTypeProperty));
3271 if (ref.bindingContext.owner) {
3272 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
3274 store.assignBinding.property = prop->core;
3276 output->addInstructionHelper(
3277 !prop->isAlias ? QDeclarativeInstruction::StoreBinding
3278 : QDeclarativeInstruction::StoreBindingOnAlias
3283 int QDeclarativeCompiler::genContextCache()
3285 if (compileState->ids.count() == 0)
3288 QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache();
3289 cache->reserve(compileState->ids.count());
3290 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
3291 cache->add(o->id, o->idIndex);
3293 output->contextCaches.append(cache);
3294 return output->contextCaches.count() - 1;
3297 QDeclarativePropertyData
3298 QDeclarativeCompiler::genValueTypeData(QDeclarativeScript::Property *valueTypeProp,
3299 QDeclarativeScript::Property *prop)
3301 typedef QDeclarativePropertyPrivate QDPP;
3302 return QDPP::saveValueType(prop->parent->metaObject(), prop->index,
3303 enginePrivate->valueTypes[prop->type]->metaObject(),
3304 valueTypeProp->index, engine);
3307 bool QDeclarativeCompiler::completeComponentBuild()
3310 componentStats->componentStat.ids = compileState->ids.count();
3312 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
3313 aliasObject = compileState->aliasingObjects.next(aliasObject))
3314 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
3316 QV4Compiler::Expression expr(unit->imports());
3317 expr.component = compileState->root;
3318 expr.ids = &compileState->ids;
3319 expr.importCache = output->importCache;
3321 QV4Compiler bindingCompiler;
3323 QList<BindingReference*> sharedBindings;
3325 for (BindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3327 BindingReference &binding = *b;
3329 // ### We don't currently optimize for bindings on alias's - because
3330 // of the solution to QTBUG-13719
3331 if (!binding.property->isAlias) {
3332 expr.context = binding.bindingContext.object;
3333 expr.property = binding.property;
3334 expr.expression = binding.expression;
3336 int index = bindingCompiler.compile(expr, enginePrivate);
3338 binding.dataType = BindingReference::V4;
3339 binding.compiledIndex = index;
3341 componentStats->componentStat.optimizedBindings.append(b->value->location);
3346 // Pre-rewrite the expression
3347 QString expression = binding.expression.asScript();
3349 QDeclarativeRewrite::RewriteBinding rewriteBinding;
3350 rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3351 bool isSharable = false;
3352 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3354 if (isSharable && !binding.property->isAlias /* See above re alias */ &&
3355 binding.property->type != qMetaTypeId<QDeclarativeBinding*>()) {
3356 binding.dataType = BindingReference::V8;
3357 sharedBindings.append(b);
3359 binding.dataType = BindingReference::QtScript;
3363 componentStats->componentStat.scriptBindings.append(b->value->location);
3366 if (!sharedBindings.isEmpty()) {
3368 static bool lt(const BindingReference *lhs, const BindingReference *rhs)
3370 return lhs->value->location.start.line < rhs->value->location.start.line;
3374 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3376 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3377 int lineNumber = startLineNumber;
3379 QString functionArray(QLatin1String("["));
3380 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3381 BindingReference *reference = sharedBindings.at(ii);
3382 QDeclarativeScript::Value *value = reference->value;
3383 const QString &expression = reference->rewrittenExpression;
3385 if (ii != 0) functionArray += QLatin1String(",");
3387 while (lineNumber < value->location.start.line) {
3389 functionArray += QLatin1String("\n");
3392 functionArray += expression;
3393 reference->compiledIndex = ii;
3395 functionArray += QLatin1String("]");
3397 compileState->v8BindingProgram = functionArray;
3398 compileState->v8BindingProgramLine = startLineNumber;
3399 compileState->v8BindingProgramIndex = output->v8bindings.count();
3400 output->v8bindings.append(v8::Persistent<v8::Array>());
3403 if (bindingCompiler.isValid())
3404 compileState->compiledBindingData = bindingCompiler.program();
3406 // Check pop()'s matched push()'s
3407 Q_ASSERT(compileState->objectDepth.depth() == 0);
3408 Q_ASSERT(compileState->listDepth.depth() == 0);
3410 saveComponentState();
3415 void QDeclarativeCompiler::dumpStats()
3417 Q_ASSERT(componentStats);
3418 qWarning().nospace() << "QML Document: " << output->url.toString();
3419 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3420 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3421 qWarning().nospace() << " Component Line " << stat.lineNumber;
3422 qWarning().nospace() << " Total Objects: " << stat.objects;
3423 qWarning().nospace() << " IDs Used: " << stat.ids;
3424 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3428 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3429 if (0 == (ii % 10)) {
3430 if (ii) output.append("\n");
3435 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3437 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3438 output.append(") ");
3440 if (!output.isEmpty())
3441 qWarning().nospace() << output.constData();
3444 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3447 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3448 if (0 == (ii % 10)) {
3449 if (ii) output.append("\n");
3454 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3456 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3457 output.append(") ");
3459 if (!output.isEmpty())
3460 qWarning().nospace() << output.constData();
3466 Returns true if from can be assigned to a (QObject) property of type
3469 bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeScript::Object *from)
3471 const QMetaObject *toMo = enginePrivate->rawMetaObjectForType(to);
3472 const QMetaObject *fromMo = from->metaObject();
3475 if (QDeclarativePropertyPrivate::equal(fromMo, toMo))
3477 fromMo = fromMo->superClass();
3483 Returns the element name, as written in the QML file, for o.
3485 QString QDeclarativeCompiler::elementName(QDeclarativeScript::Object *o)
3488 if (o->type != -1) {
3489 return output->types.at(o->type).className;
3495 QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeScript::Object *from)
3498 const QMetaObject *mo = from->metatype;
3499 QDeclarativeType *type = 0;
3500 while (!type && mo) {
3501 type = QDeclarativeMetaType::qmlType(mo);
3502 mo = mo->superClass();
3507 QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeScript::Object *obj)
3509 const QMetaObject *mo = obj->metatype;
3511 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3513 return QStringList();
3515 QMetaClassInfo classInfo = mo->classInfo(idx);
3516 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3520 QDeclarativePropertyData *
3521 QDeclarativeCompiler::property(QDeclarativeScript::Object *object, int index)
3523 QDeclarativePropertyCache *cache = 0;
3525 if (object->synthCache)
3526 cache = object->synthCache;
3527 else if (object->type != -1)
3528 cache = output->types[object->type].createPropertyCache(engine);
3530 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3532 return cache->property(index);
3535 QDeclarativePropertyData *
3536 QDeclarativeCompiler::property(QDeclarativeScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3538 if (notInRevision) *notInRevision = false;
3540 QDeclarativePropertyCache *cache = 0;
3542 if (object->synthCache)
3543 cache = object->synthCache;
3544 else if (object->type != -1)
3545 cache = output->types[object->type].createPropertyCache(engine);
3547 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3549 QDeclarativePropertyData *d = cache->property(name);
3551 // Find the first property
3552 while (d && d->isFunction())
3553 d = cache->overrideData(d);
3555 if (d && !cache->isAllowedInRevision(d)) {
3556 if (notInRevision) *notInRevision = true;
3563 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3564 QDeclarativePropertyData *
3565 QDeclarativeCompiler::signal(QDeclarativeScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3567 if (notInRevision) *notInRevision = false;
3569 QDeclarativePropertyCache *cache = 0;
3571 if (object->synthCache)
3572 cache = object->synthCache;
3573 else if (object->type != -1)
3574 cache = output->types[object->type].createPropertyCache(engine);
3576 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3579 QDeclarativePropertyData *d = cache->property(name);
3580 if (notInRevision) *notInRevision = false;
3582 while (d && !(d->isFunction()))
3583 d = cache->overrideData(d);
3585 if (d && !cache->isAllowedInRevision(d)) {
3586 if (notInRevision) *notInRevision = true;
3592 if (name.endsWith(Changed_string)) {
3593 QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3595 d = property(object, propName, notInRevision);
3597 return cache->method(d->notifyIndex);
3603 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3604 int QDeclarativeCompiler::indexOfSignal(QDeclarativeScript::Object *object, const QString &name,
3605 bool *notInRevision)
3607 QDeclarativePropertyData *d = signal(object, QStringRef(&name), notInRevision);
3608 return d?d->coreIndex:-1;
3611 int QDeclarativeCompiler::indexOfProperty(QDeclarativeScript::Object *object, const QString &name,
3612 bool *notInRevision)
3614 return indexOfProperty(object, QStringRef(&name), notInRevision);
3617 int QDeclarativeCompiler::indexOfProperty(QDeclarativeScript::Object *object, const QHashedStringRef &name,
3618 bool *notInRevision)
3620 QDeclarativePropertyData *d = property(object, name, notInRevision);
3621 return d?d->coreIndex:-1;