1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "private/qdeclarativecompiler_p.h"
44 #include "qdeclarativepropertyvaluesource.h"
45 #include "qdeclarativecomponent.h"
46 #include <private/qmetaobjectbuilder_p.h>
47 #include "private/qfastmetabuilder_p.h"
48 #include "private/qdeclarativestringconverters_p.h"
49 #include "private/qdeclarativeengine_p.h"
50 #include "qdeclarativeengine.h"
51 #include "qdeclarativecontext.h"
52 #include "private/qdeclarativemetatype_p.h"
53 #include "private/qdeclarativecustomparser_p_p.h"
54 #include "private/qdeclarativecontext_p.h"
55 #include "private/qdeclarativecomponent_p.h"
56 #include "parser/qdeclarativejsast_p.h"
57 #include "private/qdeclarativevmemetaobject_p.h"
58 #include "private/qdeclarativeexpression_p.h"
59 #include "private/qdeclarativeproperty_p.h"
60 #include "private/qdeclarativerewrite_p.h"
61 #include "qdeclarativescriptstring.h"
62 #include "private/qdeclarativeglobal_p.h"
63 #include "private/qdeclarativebinding_p.h"
64 #include "private/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())
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);
217 if (p.isFlagType()) {
218 enumValue = p.enumerator().keysToValue(value.asString().toUtf8().constData());
220 enumValue = p.enumerator().keyToValue(value.asString().toUtf8().constData());
223 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration"));
225 v->value = QDeclarativeScript::Variant((double)enumValue);
229 int type = prop->type;
232 case QMetaType::QVariant:
234 case QVariant::String:
235 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected"));
237 case QVariant::ByteArray:
238 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: byte array expected"));
241 if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected"));
245 bool ok = v->value.isNumber();
247 double n = v->value.asNumber();
248 if (double(uint(n)) != n)
251 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected"));
256 bool ok = v->value.isNumber();
258 double n = v->value.asNumber();
259 if (double(int(n)) != n)
262 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected"));
265 case QMetaType::Float:
266 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
268 case QVariant::Double:
269 if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected"));
271 case QVariant::Color:
274 QDeclarativeStringConverters::colorFromString(value.asString(), &ok);
275 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected"));
278 #ifndef QT_NO_DATESTRING
282 QDeclarativeStringConverters::dateFromString(value.asString(), &ok);
283 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected"));
289 QDeclarativeStringConverters::timeFromString(value.asString(), &ok);
290 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected"));
293 case QVariant::DateTime:
296 QDeclarativeStringConverters::dateTimeFromString(value.asString(), &ok);
297 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected"));
300 #endif // QT_NO_DATESTRING
301 case QVariant::Point:
302 case QVariant::PointF:
305 QPointF point = QDeclarativeStringConverters::pointFFromString(value.asString(), &ok);
306 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected"));
310 case QVariant::SizeF:
313 QSizeF size = QDeclarativeStringConverters::sizeFFromString(value.asString(), &ok);
314 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected"));
318 case QVariant::RectF:
321 QRectF rect = QDeclarativeStringConverters::rectFFromString(value.asString(), &ok);
322 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected"));
327 if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected"));
330 case QVariant::Vector3D:
333 QDeclarativeStringConverters::vector3DFromString(value.asString(), &ok);
334 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected"));
337 case QVariant::Vector4D:
340 QDeclarativeStringConverters::vector4DFromString(value.asString(), &ok);
341 if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 4D vector expected"));
346 QDeclarativeMetaType::StringConverter converter = QDeclarativeMetaType::customStringConverter(type);
348 COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName((QVariant::Type)type))));
356 Generate a store instruction for assigning literal \a v to property \a prop.
358 Any literal assignment that is approved in testLiteralAssignment() must have
359 a corresponding action in this method.
361 void QDeclarativeCompiler::genLiteralAssignment(QDeclarativeScript::Property *prop,
362 QDeclarativeScript::Value *v)
364 if (prop->core.isEnum()) {
365 Q_ASSERT(v->value.isNumber());
367 int value = (int)v->value.asNumber();
369 Instruction::StoreInteger instr;
370 instr.propertyIndex = prop->index;
372 output->addInstruction(instr);
376 int type = prop->type;
378 case QMetaType::QVariant:
380 if (v->value.isNumber()) {
381 double n = v->value.asNumber();
382 if (double(int(n)) == n) {
383 if (prop->core.isVMEProperty()) {
384 Instruction::StoreVarInteger instr;
385 instr.propertyIndex = prop->index;
386 instr.value = int(n);
387 output->addInstruction(instr);
389 Instruction::StoreVariantInteger instr;
390 instr.propertyIndex = prop->index;
391 instr.value = int(n);
392 output->addInstruction(instr);
395 if (prop->core.isVMEProperty()) {
396 Instruction::StoreVarDouble instr;
397 instr.propertyIndex = prop->index;
399 output->addInstruction(instr);
401 Instruction::StoreVariantDouble instr;
402 instr.propertyIndex = prop->index;
404 output->addInstruction(instr);
407 } else if (v->value.isBoolean()) {
408 if (prop->core.isVMEProperty()) {
409 Instruction::StoreVarBool instr;
410 instr.propertyIndex = prop->index;
411 instr.value = v->value.asBoolean();
412 output->addInstruction(instr);
414 Instruction::StoreVariantBool instr;
415 instr.propertyIndex = prop->index;
416 instr.value = v->value.asBoolean();
417 output->addInstruction(instr);
420 if (prop->core.isVMEProperty()) {
421 Instruction::StoreVar instr;
422 instr.propertyIndex = prop->index;
423 instr.value = output->indexForString(v->value.asString());
424 output->addInstruction(instr);
426 Instruction::StoreVariant instr;
427 instr.propertyIndex = prop->index;
428 instr.value = output->indexForString(v->value.asString());
429 output->addInstruction(instr);
434 case QVariant::String:
436 Instruction::StoreString instr;
437 instr.propertyIndex = prop->index;
438 instr.value = output->indexForString(v->value.asString());
439 output->addInstruction(instr);
442 case QVariant::ByteArray:
444 Instruction::StoreByteArray instr;
445 instr.propertyIndex = prop->index;
446 instr.value = output->indexForByteArray(v->value.asString().toLatin1());
447 output->addInstruction(instr);
452 Instruction::StoreUrl instr;
453 QString string = v->value.asString();
454 QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string));
455 instr.propertyIndex = prop->index;
456 instr.value = output->indexForUrl(u);
457 output->addInstruction(instr);
462 Instruction::StoreInteger instr;
463 instr.propertyIndex = prop->index;
464 instr.value = uint(v->value.asNumber());
465 output->addInstruction(instr);
470 Instruction::StoreInteger instr;
471 instr.propertyIndex = prop->index;
472 instr.value = int(v->value.asNumber());
473 output->addInstruction(instr);
476 case QMetaType::Float:
478 Instruction::StoreFloat instr;
479 instr.propertyIndex = prop->index;
480 instr.value = float(v->value.asNumber());
481 output->addInstruction(instr);
484 case QVariant::Double:
486 Instruction::StoreDouble instr;
487 instr.propertyIndex = prop->index;
488 instr.value = v->value.asNumber();
489 output->addInstruction(instr);
492 case QVariant::Color:
494 Instruction::StoreColor instr;
495 QColor c = QDeclarativeStringConverters::colorFromString(v->value.asString());
496 instr.propertyIndex = prop->index;
497 instr.value = c.rgba();
498 output->addInstruction(instr);
501 #ifndef QT_NO_DATESTRING
504 Instruction::StoreDate instr;
505 QDate d = QDeclarativeStringConverters::dateFromString(v->value.asString());
506 instr.propertyIndex = prop->index;
507 instr.value = d.toJulianDay();
508 output->addInstruction(instr);
513 Instruction::StoreTime instr;
514 QTime time = QDeclarativeStringConverters::timeFromString(v->value.asString());
515 instr.propertyIndex = prop->index;
516 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
517 ::memcpy(&instr.time, &time, sizeof(QTime));
518 output->addInstruction(instr);
521 case QVariant::DateTime:
523 Instruction::StoreDateTime instr;
524 QDateTime dateTime = QDeclarativeStringConverters::dateTimeFromString(v->value.asString());
525 QTime time = dateTime.time();
526 instr.propertyIndex = prop->index;
527 instr.date = dateTime.date().toJulianDay();
528 Q_ASSERT(sizeof(instr.time) == sizeof(QTime));
529 ::memcpy(&instr.time, &time, sizeof(QTime));
530 output->addInstruction(instr);
533 #endif // QT_NO_DATESTRING
534 case QVariant::Point:
536 Instruction::StorePoint instr;
538 QPoint point = QDeclarativeStringConverters::pointFFromString(v->value.asString(), &ok).toPoint();
539 instr.propertyIndex = prop->index;
540 instr.point.xp = point.x();
541 instr.point.yp = point.y();
542 output->addInstruction(instr);
545 case QVariant::PointF:
547 Instruction::StorePointF instr;
549 QPointF point = QDeclarativeStringConverters::pointFFromString(v->value.asString(), &ok);
550 instr.propertyIndex = prop->index;
551 instr.point.xp = point.x();
552 instr.point.yp = point.y();
553 output->addInstruction(instr);
558 Instruction::StoreSize instr;
560 QSize size = QDeclarativeStringConverters::sizeFFromString(v->value.asString(), &ok).toSize();
561 instr.propertyIndex = prop->index;
562 instr.size.wd = size.width();
563 instr.size.ht = size.height();
564 output->addInstruction(instr);
567 case QVariant::SizeF:
569 Instruction::StoreSizeF instr;
571 QSizeF size = QDeclarativeStringConverters::sizeFFromString(v->value.asString(), &ok);
572 instr.propertyIndex = prop->index;
573 instr.size.wd = size.width();
574 instr.size.ht = size.height();
575 output->addInstruction(instr);
580 Instruction::StoreRect instr;
582 QRect rect = QDeclarativeStringConverters::rectFFromString(v->value.asString(), &ok).toRect();
583 instr.propertyIndex = prop->index;
584 instr.rect.x1 = rect.left();
585 instr.rect.y1 = rect.top();
586 instr.rect.x2 = rect.right();
587 instr.rect.y2 = rect.bottom();
588 output->addInstruction(instr);
591 case QVariant::RectF:
593 Instruction::StoreRectF instr;
595 QRectF rect = QDeclarativeStringConverters::rectFFromString(v->value.asString(), &ok);
596 instr.propertyIndex = prop->index;
597 instr.rect.xp = rect.left();
598 instr.rect.yp = rect.top();
599 instr.rect.w = rect.width();
600 instr.rect.h = rect.height();
601 output->addInstruction(instr);
606 Instruction::StoreBool instr;
607 bool b = v->value.asBoolean();
608 instr.propertyIndex = prop->index;
610 output->addInstruction(instr);
613 case QVariant::Vector3D:
615 Instruction::StoreVector3D instr;
617 QVector3D vector = QDeclarativeStringConverters::vector3DFromString(v->value.asString(), &ok);
618 instr.propertyIndex = prop->index;
619 instr.vector.xp = vector.x();
620 instr.vector.yp = vector.y();
621 instr.vector.zp = vector.z();
622 output->addInstruction(instr);
625 case QVariant::Vector4D:
627 Instruction::StoreVector4D instr;
629 QVector4D vector = QDeclarativeStringConverters::vector4DFromString(v->value.asString(), &ok);
630 instr.propertyIndex = prop->index;
631 instr.vector.xp = vector.x();
632 instr.vector.yp = vector.y();
633 instr.vector.zp = vector.z();
634 instr.vector.wp = vector.w();
635 output->addInstruction(instr);
640 Instruction::AssignCustomType instr;
641 instr.propertyIndex = prop->index;
642 instr.primitive = output->indexForString(v->value.asString());
644 output->addInstruction(instr);
651 Resets data by clearing the lists that the QDeclarativeCompiler modifies.
653 void QDeclarativeCompiler::reset(QDeclarativeCompiledData *data)
656 data->primitives.clear();
658 data->bytecode.resize(0);
662 Compile \a unit, and store the output in \a out. \a engine is the QDeclarativeEngine
663 with which the QDeclarativeCompiledData will be associated.
665 Returns true on success, false on failure. On failure, the compile errors
666 are available from errors().
668 If the environment variant QML_COMPILER_DUMP is set
669 (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr
670 on a successful compiler.
672 bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine,
673 QDeclarativeTypeData *unit,
674 QDeclarativeCompiledData *out)
681 QDeclarativeScript::Object *root = unit->parser().tree();
684 this->engine = engine;
685 this->enginePrivate = QDeclarativeEnginePrivate::get(engine);
687 this->unitRoot = root;
691 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
692 QList<QDeclarativeScript::TypeReference *> referencedTypes = unit->parser().referencedTypes();
694 for (int ii = 0; ii < resolvedTypes.count(); ++ii) {
695 QDeclarativeCompiledData::TypeReference ref;
697 const QDeclarativeTypeData::TypeReference &tref = resolvedTypes.at(ii);
698 QDeclarativeScript::TypeReference *parserRef = referencedTypes.at(ii);
701 ref.type = tref.type;
702 if (!ref.type->isCreatable()) {
703 QString err = ref.type->noCreationReason();
705 err = tr( "Element is not creatable.");
706 COMPILE_EXCEPTION(parserRef->refObjects.first(), err);
709 if (ref.type->containsRevisionedAttributes()) {
710 QDeclarativeError cacheError;
711 ref.typePropertyCache = enginePrivate->cache(ref.type, resolvedTypes.at(ii).minorVersion,
713 if (!ref.typePropertyCache)
714 COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description());
715 ref.typePropertyCache->addref();
718 } else if (tref.typeData) {
719 ref.component = tref.typeData->compiledData();
721 ref.className = parserRef->name;
729 out->dumpInstructions();
732 Q_ASSERT(out->rootPropertyCache);
740 this->enginePrivate = 0;
747 void QDeclarativeCompiler::compileTree(QDeclarativeScript::Object *tree)
749 compileState = pool->New<ComponentCompileState>();
751 compileState->root = tree;
753 componentStats->componentStat.lineNumber = tree->location.start.line;
755 // Build global import scripts
756 QStringList importedScriptIndexes;
758 foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
759 importedScriptIndexes.append(script.qualifier);
762 // We generate the importCache before we build the tree so that
763 // it can be used in the binding compiler. Given we "expect" the
764 // QML compilation to succeed, this isn't a waste.
765 output->importCache = new QDeclarativeTypeNameCache();
766 for (int ii = 0; ii < importedScriptIndexes.count(); ++ii)
767 output->importCache->add(importedScriptIndexes.at(ii), ii);
768 unit->imports().populateCache(output->importCache, engine);
770 if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
773 Instruction::Init init;
774 init.bindingsSize = compileState->totalBindingsCount;
775 init.parserStatusSize = compileState->parserStatusCount;
776 init.contextCache = genContextCache();
777 init.objectStackSize = compileState->objectDepth.maxDepth();
778 init.listStackSize = compileState->listDepth.maxDepth();
779 if (compileState->compiledBindingData.isEmpty())
780 init.compiledBinding = -1;
782 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
783 output->addInstruction(init);
785 foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) {
786 Instruction::StoreImportedScript import;
787 import.value = output->scripts.count();
789 QDeclarativeScriptData *scriptData = script.script->scriptData();
790 scriptData->addref();
791 output->scripts << scriptData;
792 output->addInstruction(import);
795 if (!compileState->v8BindingProgram.isEmpty()) {
796 Instruction::InitV8Bindings bindings;
797 bindings.program = output->indexForString(compileState->v8BindingProgram);
798 bindings.programIndex = compileState->v8BindingProgramIndex;
799 bindings.line = compileState->v8BindingProgramLine;
800 output->addInstruction(bindings);
805 Instruction::SetDefault def;
806 output->addInstruction(def);
808 Instruction::Done done;
809 output->addInstruction(done);
811 Q_ASSERT(tree->metatype);
813 if (tree->metadata.isEmpty()) {
814 output->root = tree->metatype;
816 static_cast<QMetaObject &>(output->rootData) = *tree->metaObject();
817 output->root = &output->rootData;
819 if (!tree->metadata.isEmpty())
820 enginePrivate->registerCompositeType(output);
823 static bool QStringList_contains(const QStringList &list, const QHashedStringRef &string)
825 for (int ii = 0; ii < list.count(); ++ii)
826 if (string == list.at(ii))
832 bool QDeclarativeCompiler::buildObject(QDeclarativeScript::Object *obj, const BindingContext &ctxt)
835 componentStats->componentStat.objects++;
837 Q_ASSERT (obj->type != -1);
838 const QDeclarativeCompiledData::TypeReference &tr = output->types.at(obj->type);
839 obj->metatype = tr.metaObject();
842 obj->typeName = tr.type->qmlTypeName();
844 // This object is a "Component" element
845 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
846 COMPILE_CHECK(buildComponent(obj, ctxt));
851 typedef QDeclarativeInstruction I;
852 const I *init = ((const I *)tr.component->bytecode.constData());
853 Q_ASSERT(init && tr.component->instructionType(init) == QDeclarativeInstruction::Init);
855 // Adjust stack depths to include nested components
856 compileState->objectDepth.pushPop(init->init.objectStackSize);
857 compileState->listDepth.pushPop(init->init.listStackSize);
858 compileState->parserStatusCount += init->init.parserStatusSize;
859 compileState->totalBindingsCount += init->init.bindingsSize;
862 compileState->objectDepth.push();
864 // Object instantiations reset the binding context
865 BindingContext objCtxt(obj);
867 // Create the synthesized meta object, ignoring aliases
868 COMPILE_CHECK(checkDynamicMeta(obj));
869 COMPILE_CHECK(mergeDynamicMetaProperties(obj));
870 COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases));
872 // Find the native type and check for the QDeclarativeParserStatus interface
873 QDeclarativeType *type = toQmlType(obj);
875 obj->parserStatusCast = type->parserStatusCast();
876 if (obj->parserStatusCast != -1)
877 compileState->parserStatusCount++;
879 // Check if this is a custom parser type. Custom parser types allow
880 // assignments to non-existent properties. These assignments are then
881 // compiled by the type.
882 bool isCustomParser = output->types.at(obj->type).type &&
883 output->types.at(obj->type).type->customParser() != 0;
884 QList<QDeclarativeCustomParserProperty> customProps;
886 // Fetch the list of deferred properties
887 QStringList deferredList = deferredProperties(obj);
889 // Must do id property first. This is to ensure that the id given to any
890 // id reference created matches the order in which the objects are
892 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
893 if (prop->name() == id_string) {
894 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
900 Property *defaultProperty = 0;
901 Property *skipProperty = 0;
902 if (obj->defaultProperty) {
903 defaultProperty = obj->defaultProperty;
905 Property *explicitProperty = 0;
907 const QMetaObject *mo = obj->metatype;
908 int idx = mo->indexOfClassInfo("DefaultProperty");
910 QMetaClassInfo info = mo->classInfo(idx);
911 const char *p = info.value();
915 while (char c = p[plen++]) { ord |= c; };
919 // Utf8 - unoptimal, but seldom hit
920 QString *s = pool->NewString(QString::fromUtf8(p, plen));
921 QHashedStringRef r(*s);
923 if (obj->propertiesHashField.test(r.hash())) {
924 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
925 if (ep->name() == r) {
926 explicitProperty = ep;
932 if (!explicitProperty)
933 defaultProperty->setName(r);
936 QHashedCStringRef r(p, plen);
938 if (obj->propertiesHashField.test(r.hash())) {
939 for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) {
940 if (ep->name() == r) {
941 explicitProperty = ep;
947 if (!explicitProperty) {
948 // Set the default property name
949 QChar *buffer = pool->NewRawArray<QChar>(r.length());
950 r.writeUtf16(buffer);
951 defaultProperty->setName(QHashedStringRef(buffer, r.length(), r.hash()));
957 if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) {
959 skipProperty = explicitProperty; // We merge the values into defaultProperty
961 // Find the correct insertion point
962 Value *insertPos = 0;
964 for (Value *v = defaultProperty->values.first(); v; v = Property::ValueList::next(v)) {
965 if (!(v->location.start < explicitProperty->values.first()->location.start))
970 defaultProperty->values.insertAfter(insertPos, explicitProperty->values);
974 QDeclarativeCustomParser *cp = 0;
976 cp = output->types.at(obj->type).type->customParser();
978 // Build all explicit properties specified
979 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
981 if (prop == skipProperty)
983 if (prop->name() == id_string)
986 bool canDefer = false;
987 if (isCustomParser) {
988 if (doesPropertyExist(prop, obj) &&
989 (!(cp->flags() & QDeclarativeCustomParser::AcceptsAttachedProperties) ||
990 !isAttachedPropertyName(prop->name()))) {
991 int ids = compileState->ids.count();
992 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
993 canDefer = ids == compileState->ids.count();
994 } else if (isSignalPropertyName(prop->name()) &&
995 (cp->flags() & QDeclarativeCustomParser::AcceptsSignalHandlers)) {
996 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
998 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
1001 if (isSignalPropertyName(prop->name())) {
1002 COMPILE_CHECK(buildSignal(prop,obj,objCtxt));
1004 int ids = compileState->ids.count();
1005 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1006 canDefer = ids == compileState->ids.count();
1010 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1011 prop->isDeferred = true;
1015 // Build the default property
1016 if (defaultProperty) {
1017 Property *prop = defaultProperty;
1019 bool canDefer = false;
1020 if (isCustomParser) {
1021 if (doesPropertyExist(prop, obj)) {
1022 int ids = compileState->ids.count();
1023 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1024 canDefer = ids == compileState->ids.count();
1026 customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop);
1029 int ids = compileState->ids.count();
1030 COMPILE_CHECK(buildProperty(prop, obj, objCtxt));
1031 canDefer = ids == compileState->ids.count();
1034 if (canDefer && !deferredList.isEmpty() && QStringList_contains(deferredList, prop->name()))
1035 prop->isDeferred = true;
1038 // Compile custom parser parts
1039 if (isCustomParser && !customProps.isEmpty()) {
1041 cp->compiler = this;
1043 obj->custom = cp->compile(customProps);
1046 foreach (QDeclarativeError err, cp->errors()) {
1047 err.setUrl(output->url);
1052 compileState->objectDepth.pop();
1057 void QDeclarativeCompiler::genObject(QDeclarativeScript::Object *obj)
1059 QDeclarativeCompiledData::TypeReference &tr = output->types[obj->type];
1060 if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) {
1065 // Create the object
1066 if (obj->custom.isEmpty() && output->types.at(obj->type).type &&
1067 !output->types.at(obj->type).type->isExtendedType() && obj != compileState->root) {
1069 Instruction::CreateSimpleObject create;
1070 create.create = output->types.at(obj->type).type->createFunction();
1071 create.typeSize = output->types.at(obj->type).type->createSize();
1072 create.type = obj->type;
1073 create.line = obj->location.start.line;
1074 create.column = obj->location.start.column;
1075 output->addInstruction(create);
1079 if (output->types.at(obj->type).type) {
1080 Instruction::CreateCppObject create;
1081 create.line = obj->location.start.line;
1082 create.column = obj->location.start.column;
1084 if (!obj->custom.isEmpty())
1085 create.data = output->indexForByteArray(obj->custom);
1086 create.type = obj->type;
1087 create.isRoot = (compileState->root == obj);
1088 output->addInstruction(create);
1090 Instruction::CreateQMLObject create;
1091 create.type = obj->type;
1092 create.isRoot = (compileState->root == obj);
1094 if (!obj->bindingBitmask.isEmpty()) {
1095 Q_ASSERT(obj->bindingBitmask.size() % 4 == 0);
1096 create.bindingBits = output->indexForByteArray(obj->bindingBitmask);
1098 create.bindingBits = -1;
1100 output->addInstruction(create);
1102 Instruction::CompleteQMLObject complete;
1103 complete.line = obj->location.start.line;
1104 complete.column = obj->location.start.column;
1105 complete.isRoot = (compileState->root == obj);
1106 output->addInstruction(complete);
1110 // Setup the synthesized meta object if necessary
1111 if (!obj->metadata.isEmpty()) {
1112 Instruction::StoreMetaObject meta;
1113 meta.data = output->indexForByteArray(obj->metadata);
1114 meta.aliasData = output->indexForByteArray(obj->synthdata);
1115 meta.propertyCache = output->propertyCaches.count();
1117 QDeclarativePropertyCache *propertyCache = obj->synthCache;
1118 Q_ASSERT(propertyCache);
1119 propertyCache->addref();
1121 // Add flag for alias properties
1122 if (!obj->synthdata.isEmpty()) {
1123 const QDeclarativeVMEMetaData *vmeMetaData =
1124 reinterpret_cast<const QDeclarativeVMEMetaData *>(obj->synthdata.constData());
1125 for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) {
1126 int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii;
1127 QDeclarativePropertyCache::Data *data = propertyCache->property(index);
1128 data->setFlags(data->getFlags() | QDeclarativePropertyCache::Data::IsAlias);
1132 if (obj == unitRoot) {
1133 propertyCache->addref();
1134 output->rootPropertyCache = propertyCache;
1137 output->propertyCaches << propertyCache;
1138 output->addInstruction(meta);
1139 } else if (obj == unitRoot) {
1140 output->rootPropertyCache = tr.createPropertyCache(engine);
1141 output->rootPropertyCache->addref();
1144 // Set the object id
1145 if (!obj->id.isEmpty()) {
1146 Instruction::SetId id;
1147 id.value = output->indexForString(obj->id);
1148 id.index = obj->idIndex;
1149 output->addInstruction(id);
1153 if (tr.type && obj->parserStatusCast != -1) {
1154 Instruction::BeginObject begin;
1155 begin.castValue = obj->parserStatusCast;
1156 output->addInstruction(begin);
1162 void QDeclarativeCompiler::genObjectBody(QDeclarativeScript::Object *obj)
1164 for (Property *prop = obj->scriptStringProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1165 Q_ASSERT(prop->scriptStringScope != -1);
1166 const QString &script = prop->values.first()->value.asScript();
1167 Instruction::StoreScriptString ss;
1168 ss.propertyIndex = prop->index;
1169 ss.value = output->indexForString(script);
1170 ss.scope = prop->scriptStringScope;
1171 // ss.bindingId = rewriteBinding(script, prop->name());
1172 ss.bindingId = rewriteBinding(script, QString()); // XXX
1173 ss.line = prop->location.start.line;
1174 output->addInstruction(ss);
1177 bool seenDefer = false;
1178 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1179 if (prop->isDeferred) {
1184 genValueProperty(prop, obj);
1187 Instruction::Defer defer;
1188 defer.deferCount = 0;
1189 int deferIdx = output->addInstruction(defer);
1190 int nextInstructionIndex = output->nextInstructionIndex();
1192 Instruction::DeferInit dinit;
1193 // XXX - these are now massive over allocations
1194 dinit.bindingsSize = compileState->totalBindingsCount;
1195 dinit.parserStatusSize = compileState->parserStatusCount;
1196 dinit.objectStackSize = compileState->objectDepth.maxDepth();
1197 dinit.listStackSize = compileState->listDepth.maxDepth();
1198 output->addInstruction(dinit);
1200 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1201 if (!prop->isDeferred)
1203 genValueProperty(prop, obj);
1206 Instruction::Done done;
1207 output->addInstruction(done);
1209 output->instruction(deferIdx)->defer.deferCount = output->nextInstructionIndex() - nextInstructionIndex;
1212 for (Property *prop = obj->signalProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1214 QDeclarativeScript::Value *v = prop->values.first();
1216 if (v->type == Value::SignalObject) {
1218 genObject(v->object);
1220 Instruction::AssignSignalObject assign;
1221 assign.line = v->location.start.line;
1222 assign.signal = output->indexForString(prop->name().toString());
1223 output->addInstruction(assign);
1225 } else if (v->type == Value::SignalExpression) {
1227 Instruction::StoreSignal store;
1228 store.signalIndex = prop->index;
1230 output->indexForString(v->value.asScript().trimmed());
1231 store.context = v->signalExpressionContextStack;
1232 store.name = output->indexForByteArray(prop->name().toUtf8());
1233 store.line = v->location.start.line;
1234 output->addInstruction(store);
1240 for (Property *prop = obj->attachedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1241 Instruction::FetchAttached fetch;
1242 fetch.id = prop->index;
1243 fetch.line = prop->location.start.line;
1244 output->addInstruction(fetch);
1246 genObjectBody(prop->value);
1248 Instruction::PopFetchedObject pop;
1249 output->addInstruction(pop);
1252 for (Property *prop = obj->groupedProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1253 Instruction::FetchObject fetch;
1254 fetch.property = prop->index;
1255 fetch.line = prop->location.start.line;
1256 output->addInstruction(fetch);
1258 if (!prop->value->metadata.isEmpty()) {
1259 Instruction::StoreMetaObject meta;
1260 meta.data = output->indexForByteArray(prop->value->metadata);
1261 meta.aliasData = output->indexForByteArray(prop->value->synthdata);
1262 meta.propertyCache = -1;
1263 output->addInstruction(meta);
1266 genObjectBody(prop->value);
1268 Instruction::PopFetchedObject pop;
1269 output->addInstruction(pop);
1272 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1274 genValueTypeProperty(obj, prop);
1277 for (Property *prop = obj->valueProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1278 if (prop->isDeferred)
1281 genValueProperty(prop, obj);
1284 for (Property *prop = obj->valueTypeProperties.first(); prop; prop = Object::PropertyList::next(prop)) {
1286 genValueTypeProperty(obj, prop);
1290 void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeScript::Object *obj,QDeclarativeScript::Property *prop)
1292 Instruction::FetchValueType fetch;
1293 fetch.property = prop->index;
1294 fetch.type = prop->type;
1295 fetch.bindingSkipList = 0;
1297 if (obj->type == -1 || output->types.at(obj->type).component) {
1298 // We only have to do this if this is a composite type. If it is a builtin
1299 // type it can't possibly already have bindings that need to be cleared.
1300 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1301 if (!vprop->values.isEmpty()) {
1302 Q_ASSERT(vprop->index >= 0 && vprop->index < 32);
1303 fetch.bindingSkipList |= (1 << vprop->index);
1308 output->addInstruction(fetch);
1310 for (Property *vprop = prop->value->valueProperties.first(); vprop; vprop = Object::PropertyList::next(vprop)) {
1311 genPropertyAssignment(vprop, prop->value, prop);
1314 Instruction::PopValueType pop;
1315 pop.property = prop->index;
1316 pop.type = prop->type;
1317 pop.bindingSkipList = 0;
1318 output->addInstruction(pop);
1321 void QDeclarativeCompiler::genComponent(QDeclarativeScript::Object *obj)
1323 QDeclarativeScript::Object *root = obj->defaultProperty->values.first()->object;
1326 Instruction::CreateComponent create;
1327 create.line = root->location.start.line;
1328 create.column = root->location.start.column;
1329 create.endLine = root->location.end.line;
1330 create.isRoot = (compileState->root == obj);
1331 int createInstruction = output->addInstruction(create);
1332 int nextInstructionIndex = output->nextInstructionIndex();
1334 ComponentCompileState *oldCompileState = compileState;
1335 compileState = componentState(root);
1337 Instruction::Init init;
1338 init.bindingsSize = compileState->totalBindingsCount;
1339 init.parserStatusSize = compileState->parserStatusCount;
1340 init.contextCache = genContextCache();
1341 init.objectStackSize = compileState->objectDepth.maxDepth();
1342 init.listStackSize = compileState->listDepth.maxDepth();
1343 if (compileState->compiledBindingData.isEmpty())
1344 init.compiledBinding = -1;
1346 init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
1347 output->addInstruction(init);
1349 if (!compileState->v8BindingProgram.isEmpty()) {
1350 Instruction::InitV8Bindings bindings;
1351 bindings.program = output->indexForString(compileState->v8BindingProgram);
1352 bindings.programIndex = compileState->v8BindingProgramIndex;
1353 bindings.line = compileState->v8BindingProgramLine;
1354 output->addInstruction(bindings);
1359 Instruction::SetDefault def;
1360 output->addInstruction(def);
1362 Instruction::Done done;
1363 output->addInstruction(done);
1365 output->instruction(createInstruction)->createComponent.count =
1366 output->nextInstructionIndex() - nextInstructionIndex;
1368 compileState = oldCompileState;
1370 if (!obj->id.isEmpty()) {
1371 Instruction::SetId id;
1372 id.value = output->indexForString(obj->id);
1373 id.index = obj->idIndex;
1374 output->addInstruction(id);
1377 if (obj == unitRoot) {
1378 output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
1379 output->rootPropertyCache->addref();
1383 bool QDeclarativeCompiler::buildComponent(QDeclarativeScript::Object *obj,
1384 const BindingContext &ctxt)
1386 // The special "Component" element can only have the id property and a
1387 // default property, that actually defines the component's tree
1389 compileState->objectDepth.push();
1391 // Find, check and set the "id" property (if any)
1392 Property *idProp = 0;
1393 if (obj->properties.isMany() ||
1394 (obj->properties.isOne() && obj->properties.first()->name() != id_string))
1395 COMPILE_EXCEPTION(obj->properties.first(), tr("Component elements may not contain properties other than id"));
1397 if (!obj->properties.isEmpty())
1398 idProp = obj->properties.first();
1401 if (idProp->value || idProp->values.isMany() || idProp->values.first()->object)
1402 COMPILE_EXCEPTION(idProp, tr("Invalid component id specification"));
1403 COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive()))
1405 QString idVal = idProp->values.first()->primitive();
1407 if (compileState->ids.value(idVal))
1408 COMPILE_EXCEPTION(idProp, tr("id is not unique"));
1414 // Check the Component tree is well formed
1415 if (obj->defaultProperty &&
1416 (obj->defaultProperty->value || obj->defaultProperty->values.isMany() ||
1417 (obj->defaultProperty->values.isOne() && !obj->defaultProperty->values.first()->object)))
1418 COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
1420 if (!obj->dynamicProperties.isEmpty())
1421 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
1422 if (!obj->dynamicSignals.isEmpty())
1423 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
1424 if (!obj->dynamicSlots.isEmpty())
1425 COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
1427 QDeclarativeScript::Object *root = 0;
1428 if (obj->defaultProperty && !obj->defaultProperty->values.isEmpty())
1429 root = obj->defaultProperty->values.first()->object;
1432 COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
1434 // Build the component tree
1435 COMPILE_CHECK(buildComponentFromRoot(root, ctxt));
1437 compileState->objectDepth.pop();
1442 bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeScript::Object *obj,
1443 const BindingContext &ctxt)
1445 ComponentCompileState *oldComponentCompileState = compileState;
1446 compileState = pool->New<ComponentCompileState>();
1447 compileState->root = obj;
1448 compileState->nested = true;
1450 if (componentStats) {
1451 ComponentStat oldComponentStat = componentStats->componentStat;
1453 componentStats->componentStat = ComponentStat();
1454 componentStats->componentStat.lineNumber = obj->location.start.line;
1457 COMPILE_CHECK(buildObject(obj, ctxt));
1459 COMPILE_CHECK(completeComponentBuild());
1461 componentStats->componentStat = oldComponentStat;
1464 COMPILE_CHECK(buildObject(obj, ctxt));
1466 COMPILE_CHECK(completeComponentBuild());
1469 compileState = oldComponentCompileState;
1475 // Build a sub-object. A sub-object is one that was not created directly by
1476 // QML - such as a grouped property object, or an attached object. Sub-object's
1477 // can't have an id, involve a custom parser, have attached properties etc.
1478 bool QDeclarativeCompiler::buildSubObject(QDeclarativeScript::Object *obj, const BindingContext &ctxt)
1480 Q_ASSERT(obj->metatype);
1481 Q_ASSERT(!obj->defaultProperty);
1482 Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding
1485 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
1486 if (isSignalPropertyName(prop->name())) {
1487 COMPILE_CHECK(buildSignal(prop, obj, ctxt));
1489 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1496 int QDeclarativeCompiler::componentTypeRef()
1498 QDeclarativeType *t = QDeclarativeMetaType::qmlType(QLatin1String("QtQuick/Component"),2,0);
1499 for (int ii = output->types.count() - 1; ii >= 0; --ii) {
1500 if (output->types.at(ii).type == t)
1503 QDeclarativeCompiledData::TypeReference ref;
1504 ref.className = Component_string;
1506 output->types << ref;
1507 return output->types.count() - 1;
1510 bool QDeclarativeCompiler::buildSignal(QDeclarativeScript::Property *prop, QDeclarativeScript::Object *obj,
1511 const BindingContext &ctxt)
1513 Q_ASSERT(obj->metaObject());
1515 const QHashedStringRef &propName = prop->name();
1517 Q_ASSERT(propName.startsWith(on_string));
1518 QString name = propName.mid(2, -1).toString();
1520 // Note that the property name could start with any alpha or '_' or '$' character,
1521 // so we need to do the lower-casing of the first alpha character.
1522 for (int firstAlphaIndex = 0; firstAlphaIndex < name.size(); ++firstAlphaIndex) {
1523 if (name.at(firstAlphaIndex).isUpper()) {
1524 name[firstAlphaIndex] = name.at(firstAlphaIndex).toLower();
1529 bool notInRevision = false;
1531 QDeclarativePropertyCache::Data *sig = signal(obj, QStringRef(&name), ¬InRevision);
1535 if (notInRevision && 0 == property(obj, propName, 0)) {
1536 Q_ASSERT(obj->type != -1);
1537 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1538 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1540 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));
1542 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1546 // If the "on<Signal>" name doesn't resolve into a signal, try it as a
1548 COMPILE_CHECK(buildProperty(prop, obj, ctxt));
1552 if (prop->value || !prop->values.isOne())
1553 COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment"));
1555 prop->index = sig->coreIndex;
1558 obj->addSignalProperty(prop);
1560 if (prop->values.first()->object) {
1561 COMPILE_CHECK(buildObject(prop->values.first()->object, ctxt));
1562 prop->values.first()->type = Value::SignalObject;
1564 prop->values.first()->type = Value::SignalExpression;
1566 if (!prop->values.first()->value.isScript())
1567 COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)"));
1569 QString script = prop->values.first()->value.asScript().trimmed();
1570 if (script.isEmpty())
1571 COMPILE_EXCEPTION(prop, tr("Empty signal assignment"));
1573 prop->values.first()->signalExpressionContextStack = ctxt.stack;
1582 Returns true if (value) property \a prop exists on obj, false otherwise.
1584 bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeScript::Property *prop,
1585 QDeclarativeScript::Object *obj)
1587 if (prop->name().isEmpty())
1589 if(isAttachedPropertyName(prop->name()) || prop->name() == id_string)
1592 return property(obj, prop->name()) != 0;
1595 bool QDeclarativeCompiler::buildProperty(QDeclarativeScript::Property *prop,
1596 QDeclarativeScript::Object *obj,
1597 const BindingContext &ctxt)
1599 if (prop->isEmpty())
1600 COMPILE_EXCEPTION(prop, tr("Empty property assignment"));
1602 const QMetaObject *metaObject = obj->metaObject();
1603 Q_ASSERT(metaObject);
1605 if (isAttachedPropertyName(prop->name())) {
1606 // Setup attached property data
1608 if (ctxt.isSubContext()) {
1609 // Attached properties cannot be used on sub-objects. Sub-objects
1610 // always exist in a binding sub-context, which is what we test
1612 COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here"));
1615 QDeclarativeType *type = 0;
1616 QDeclarativeImportedNamespace *typeNamespace = 0;
1617 unit->imports().resolveType(prop->name().toString(), &type, 0, 0, 0, &typeNamespace);
1619 if (typeNamespace) {
1620 COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
1623 } else if (!type || !type->attachedPropertiesType()) {
1624 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1628 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1630 Q_ASSERT(type->attachedPropertiesFunction());
1631 prop->index = type->attachedPropertiesId();
1632 prop->value->metatype = type->attachedPropertiesType();
1634 // Setup regular property data
1635 bool notInRevision = false;
1636 QDeclarativePropertyCache::Data *d =
1637 prop->name().isEmpty()?0:property(obj, prop->name(), ¬InRevision);
1639 if (d == 0 && notInRevision) {
1640 const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
1641 const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type);
1643 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));
1645 COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(elementName(obj)).arg(prop->name().toString()));
1648 prop->index = d->coreIndex;
1650 } else if (prop->isDefault) {
1651 QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject);
1652 QDeclarativePropertyCache::Data defaultPropertyData;
1653 defaultPropertyData.load(p, engine);
1655 prop->setName(QLatin1String(p.name()));
1656 prop->core = defaultPropertyData;
1657 prop->index = prop->core.coreIndex;
1660 // We can't error here as the "id" property does not require a
1661 // successful index resolution
1662 if (prop->index != -1)
1663 prop->type = prop->core.propType;
1665 // Check if this is an alias
1666 if (prop->index != -1 &&
1668 prop->parent->type != -1 &&
1669 output->types.at(prop->parent->type).component) {
1671 QDeclarativePropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache;
1672 if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias())
1673 prop->isAlias = true;
1676 if (prop->index != -1 && !prop->values.isEmpty())
1677 prop->parent->setBindingBit(prop->index);
1680 if (!prop->isDefault && prop->name() == id_string && !ctxt.isSubContext()) {
1682 // The magic "id" behavior doesn't apply when "id" is resolved as a
1683 // default property or to sub-objects (which are always in binding
1685 COMPILE_CHECK(buildIdProperty(prop, obj));
1686 if (prop->type == QVariant::String &&
1687 prop->values.first()->value.isString())
1688 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1690 } else if (isAttachedPropertyName(prop->name())) {
1692 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1694 } else if (prop->index == -1) {
1696 if (prop->isDefault) {
1697 COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property"));
1699 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
1702 } else if (prop->value) {
1704 COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt));
1706 } else if (prop->core.isQList()) {
1708 COMPILE_CHECK(buildListProperty(prop, obj, ctxt));
1710 } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) {
1712 COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt));
1716 COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt));
1723 bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns,
1724 QDeclarativeScript::Property *nsProp,
1725 QDeclarativeScript::Object *obj,
1726 const BindingContext &ctxt)
1729 COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace"));
1731 for (Property *prop = nsProp->value->properties.first(); prop; prop = nsProp->value->properties.next(prop)) {
1733 if (!isAttachedPropertyName(prop->name()))
1734 COMPILE_EXCEPTION(prop, tr("Not an attached property name"));
1736 // Setup attached property data
1738 QDeclarativeType *type = 0;
1739 unit->imports().resolveType(ns, prop->name().toString(), &type, 0, 0, 0);
1741 if (!type || !type->attachedPropertiesType())
1742 COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
1745 COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment"));
1747 Q_ASSERT(type->attachedPropertiesFunction());
1748 prop->index = type->index();
1749 prop->value->metatype = type->attachedPropertiesType();
1751 COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt));
1757 void QDeclarativeCompiler::genValueProperty(QDeclarativeScript::Property *prop,
1758 QDeclarativeScript::Object *obj)
1760 if (prop->core.isQList()) {
1761 genListProperty(prop, obj);
1763 genPropertyAssignment(prop, obj);
1767 void QDeclarativeCompiler::genListProperty(QDeclarativeScript::Property *prop,
1768 QDeclarativeScript::Object *obj)
1770 int listType = enginePrivate->listType(prop->type);
1772 Instruction::FetchQList fetch;
1773 fetch.property = prop->index;
1774 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
1775 fetch.type = listType;
1776 output->addInstruction(fetch);
1778 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1780 if (v->type == Value::CreatedObject) {
1782 genObject(v->object);
1783 if (listTypeIsInterface) {
1784 Instruction::AssignObjectList assign;
1785 assign.line = prop->location.start.line;
1786 output->addInstruction(assign);
1788 Instruction::StoreObjectQList store;
1789 output->addInstruction(store);
1792 } else if (v->type == Value::PropertyBinding) {
1794 genBindingAssignment(v, prop, obj);
1800 Instruction::PopQList pop;
1801 output->addInstruction(pop);
1804 void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeScript::Property *prop,
1805 QDeclarativeScript::Object *obj,
1806 QDeclarativeScript::Property *valueTypeProperty)
1808 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
1810 Q_ASSERT(v->type == Value::CreatedObject ||
1811 v->type == Value::PropertyBinding ||
1812 v->type == Value::Literal);
1814 if (v->type == Value::CreatedObject) {
1816 genObject(v->object);
1818 if (QDeclarativeMetaType::isInterface(prop->type)) {
1820 Instruction::StoreInterface store;
1821 store.line = v->object->location.start.line;
1822 store.propertyIndex = prop->index;
1823 output->addInstruction(store);
1825 } else if (prop->type == QMetaType::QVariant) {
1827 if (prop->core.isVMEProperty()) {
1828 Instruction::StoreVarObject store;
1829 store.line = v->object->location.start.line;
1830 store.propertyIndex = prop->index;
1831 output->addInstruction(store);
1833 Instruction::StoreVariantObject store;
1834 store.line = v->object->location.start.line;
1835 store.propertyIndex = prop->index;
1836 output->addInstruction(store);
1842 Instruction::StoreObject store;
1843 store.line = v->object->location.start.line;
1844 store.propertyIndex = prop->index;
1845 output->addInstruction(store);
1848 } else if (v->type == Value::PropertyBinding) {
1850 genBindingAssignment(v, prop, obj, valueTypeProperty);
1852 } else if (v->type == Value::Literal) {
1854 genLiteralAssignment(prop, v);
1860 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
1862 Q_ASSERT(v->type == Value::ValueSource ||
1863 v->type == Value::ValueInterceptor);
1865 if (v->type == Value::ValueSource) {
1866 genObject(v->object);
1868 Instruction::StoreValueSource store;
1869 if (valueTypeProperty) {
1870 store.property = genValueTypeData(prop, valueTypeProperty);
1873 store.property = prop->core;
1876 QDeclarativeType *valueType = toQmlType(v->object);
1877 store.castValue = valueType->propertyValueSourceCast();
1878 output->addInstruction(store);
1880 } else if (v->type == Value::ValueInterceptor) {
1881 genObject(v->object);
1883 Instruction::StoreValueInterceptor store;
1884 if (valueTypeProperty) {
1885 store.property = genValueTypeData(prop, valueTypeProperty);
1888 store.property = prop->core;
1891 QDeclarativeType *valueType = toQmlType(v->object);
1892 store.castValue = valueType->propertyValueInterceptorCast();
1893 output->addInstruction(store);
1899 bool QDeclarativeCompiler::buildIdProperty(QDeclarativeScript::Property *prop,
1900 QDeclarativeScript::Object *obj)
1903 prop->values.isMany() ||
1904 prop->values.first()->object)
1905 COMPILE_EXCEPTION(prop, tr("Invalid use of id property"));
1907 QDeclarativeScript::Value *idValue = prop->values.first();
1908 QString val = idValue->primitive();
1910 COMPILE_CHECK(checkValidId(idValue, val));
1912 if (compileState->ids.value(val))
1913 COMPILE_EXCEPTION(prop, tr("id is not unique"));
1915 prop->values.first()->type = Value::Id;
1923 void QDeclarativeCompiler::addId(const QString &id, QDeclarativeScript::Object *obj)
1926 Q_ASSERT(!compileState->ids.value(id));
1927 Q_ASSERT(obj->id == id);
1928 obj->idIndex = compileState->ids.count();
1929 compileState->ids.append(obj);
1932 void QDeclarativeCompiler::addBindingReference(BindingReference *ref)
1934 Q_ASSERT(ref->value && !ref->value->bindingReference);
1935 ref->value->bindingReference = ref;
1936 compileState->totalBindingsCount++;
1937 compileState->bindings.prepend(ref);
1940 void QDeclarativeCompiler::saveComponentState()
1942 Q_ASSERT(compileState->root);
1943 Q_ASSERT(compileState->root->componentCompileState == 0);
1945 compileState->root->componentCompileState = compileState;
1948 componentStats->savedComponentStats.append(componentStats->componentStat);
1951 QDeclarativeCompilerTypes::ComponentCompileState *
1952 QDeclarativeCompiler::componentState(QDeclarativeScript::Object *obj)
1954 Q_ASSERT(obj->componentCompileState);
1955 return obj->componentCompileState;
1958 // Build attached property object. In this example,
1962 // GridView is an attached property object.
1963 bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeScript::Property *prop,
1964 QDeclarativeScript::Object *obj,
1965 const BindingContext &ctxt)
1967 Q_ASSERT(prop->value);
1968 Q_ASSERT(prop->index != -1); // This is set in buildProperty()
1970 compileState->objectDepth.push();
1972 obj->addAttachedProperty(prop);
1974 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
1976 compileState->objectDepth.pop();
1982 // Build "grouped" properties. In this example:
1984 // font.pointSize: 12
1985 // font.family: "Helvetica"
1987 // font is a nested property. pointSize and family are not.
1988 bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeScript::Property *prop,
1989 QDeclarativeScript::Object *obj,
1990 const BindingContext &ctxt)
1992 Q_ASSERT(prop->type != 0);
1993 Q_ASSERT(prop->index != -1);
1995 if (QDeclarativeValueTypeFactory::isValueType(prop->type)) {
1996 if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
1998 if (!prop->values.isEmpty()) {
1999 if (prop->values.first()->location < prop->value->location) {
2000 COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
2002 COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
2006 if (!obj->metaObject()->property(prop->index).isWritable()) {
2007 COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2011 if (prop->isAlias) {
2012 for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
2013 vtProp->isAlias = true;
2017 COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
2018 prop->value, obj, ctxt.incr()));
2019 obj->addValueTypeProperty(prop);
2021 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2025 // Load the nested property's meta type
2026 prop->value->metatype = enginePrivate->metaObjectForType(prop->type);
2027 if (!prop->value->metatype)
2028 COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
2030 if (!prop->values.isEmpty())
2031 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign a value directly to a grouped property"));
2033 obj->addGroupedProperty(prop);
2035 compileState->objectDepth.push();
2037 COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr()));
2039 compileState->objectDepth.pop();
2045 bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
2046 QDeclarativeScript::Object *obj,
2047 QDeclarativeScript::Object *baseObj,
2048 const BindingContext &ctxt)
2050 compileState->objectDepth.push();
2052 if (obj->defaultProperty)
2053 COMPILE_EXCEPTION(obj, tr("Invalid property use"));
2054 obj->metatype = type->metaObject();
2056 for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) {
2058 QDeclarativePropertyCache::Data *d = property(obj, prop->name());
2060 COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString()));
2062 prop->index = d->coreIndex;
2063 prop->type = d->propType;
2065 prop->isValueTypeSubProperty = true;
2068 COMPILE_EXCEPTION(prop, tr("Property assignment expected"));
2070 if (prop->values.isMany()) {
2071 COMPILE_EXCEPTION(prop, tr("Single property assignment expected"));
2072 } else if (!prop->values.isEmpty()) {
2073 QDeclarativeScript::Value *value = prop->values.first();
2075 if (value->object) {
2076 COMPILE_EXCEPTION(prop, tr("Unexpected object assignment"));
2077 } else if (value->value.isScript()) {
2078 // ### Check for writability
2080 //optimization for <Type>.<EnumValue> enum assignments
2081 bool isEnumAssignment = false;
2083 if (prop->core.isEnum())
2084 COMPILE_CHECK(testQualifiedEnumAssignment(obj->metatype->property(prop->index), obj,
2085 value, &isEnumAssignment));
2087 if (isEnumAssignment) {
2088 value->type = Value::Literal;
2090 BindingReference *reference = pool->New<BindingReference>();
2091 reference->expression = value->value;
2092 reference->property = prop;
2093 reference->value = value;
2094 reference->bindingContext = ctxt;
2095 reference->bindingContext.owner++;
2096 addBindingReference(reference);
2097 value->type = Value::PropertyBinding;
2100 COMPILE_CHECK(testLiteralAssignment(prop, value));
2101 value->type = Value::Literal;
2105 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2106 Q_ASSERT(v->object);
2108 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt));
2111 obj->addValueProperty(prop);
2114 compileState->objectDepth.pop();
2119 // Build assignments to QML lists. QML lists are properties of type
2120 // QDeclarativeListProperty<T>. List properties can accept a list of
2121 // objects, or a single binding.
2122 bool QDeclarativeCompiler::buildListProperty(QDeclarativeScript::Property *prop,
2123 QDeclarativeScript::Object *obj,
2124 const BindingContext &ctxt)
2126 Q_ASSERT(prop->core.isQList());
2128 compileState->listDepth.push();
2132 obj->addValueProperty(prop);
2134 int listType = enginePrivate->listType(t);
2135 bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType);
2137 bool assignedBinding = false;
2138 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2140 v->type = Value::CreatedObject;
2141 COMPILE_CHECK(buildObject(v->object, ctxt));
2143 // We check object coercian here. We check interface assignment
2145 if (!listTypeIsInterface) {
2146 if (!canCoerce(listType, v->object)) {
2147 COMPILE_EXCEPTION(v, tr("Cannot assign object to list"));
2151 } else if (v->value.isScript()) {
2152 if (assignedBinding)
2153 COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists"));
2155 assignedBinding = true;
2156 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2157 v->type = Value::PropertyBinding;
2159 COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
2163 compileState->listDepth.pop();
2168 // Compiles an assignment to a QDeclarativeScriptString property
2169 bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeScript::Property *prop,
2170 QDeclarativeScript::Object *obj,
2171 const BindingContext &ctxt)
2173 if (prop->values.isMany())
2174 COMPILE_EXCEPTION(prop->values.first()->nextValue, tr( "Cannot assign multiple values to a script property"));
2176 if (prop->values.first()->object)
2177 COMPILE_EXCEPTION(prop->values.first(), tr( "Invalid property assignment: script expected"));
2179 prop->scriptStringScope = ctxt.stack;
2180 obj->addScriptStringProperty(prop);
2185 // Compile regular property assignments of the form "property: <value>"
2186 bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeScript::Property *prop,
2187 QDeclarativeScript::Object *obj,
2188 const BindingContext &ctxt)
2190 obj->addValueProperty(prop);
2192 if (prop->values.isMany())
2193 COMPILE_EXCEPTION(prop->values.first(), tr( "Cannot assign multiple values to a singular property") );
2195 for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
2198 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2202 COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
2207 for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
2208 Q_ASSERT(v->object);
2209 COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
2215 // Compile assigning a single object instance to a regular property
2216 bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeScript::Property *prop,
2217 QDeclarativeScript::Object *obj,
2218 QDeclarativeScript::Value *v,
2219 const BindingContext &ctxt)
2221 Q_ASSERT(prop->index != -1);
2222 Q_ASSERT(v->object->type != -1);
2224 if (!obj->metaObject()->property(prop->index).isWritable())
2225 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2227 if (QDeclarativeMetaType::isInterface(prop->type)) {
2229 // Assigning an object to an interface ptr property
2230 COMPILE_CHECK(buildObject(v->object, ctxt));
2232 v->type = Value::CreatedObject;
2234 } else if (prop->type == QMetaType::QVariant) {
2236 // Assigning an object to a QVariant
2237 COMPILE_CHECK(buildObject(v->object, ctxt));
2239 v->type = Value::CreatedObject;
2241 // Normally buildObject() will set this up, but we need the static
2242 // meta object earlier to test for assignability. It doesn't matter
2243 // that there may still be outstanding synthesized meta object changes
2244 // on this type, as they are not relevant for assignability testing
2245 v->object->metatype = output->types.at(v->object->type).metaObject();
2246 Q_ASSERT(v->object->metaObject());
2248 // We want to raw metaObject here as the raw metaobject is the
2249 // actual property type before we applied any extensions that might
2250 // effect the properties on the type, but don't effect assignability
2251 const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type);
2253 // Will be true if the assgned type inherits propertyMetaObject
2254 bool isAssignable = false;
2255 // Determine isAssignable value
2256 if (propertyMetaObject) {
2257 const QMetaObject *c = v->object->metatype;
2259 isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject));
2260 c = c->superClass();
2265 // Simple assignment
2266 COMPILE_CHECK(buildObject(v->object, ctxt));
2268 v->type = Value::CreatedObject;
2269 } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) {
2270 // Automatic "Component" insertion
2271 QDeclarativeScript::Object *root = v->object;
2272 QDeclarativeScript::Object *component = pool->New<Object>();
2273 component->type = componentTypeRef();
2274 component->typeName = QStringLiteral("Qt/Component");
2275 component->metatype = &QDeclarativeComponent::staticMetaObject;
2276 component->location = root->location;
2277 QDeclarativeScript::Value *componentValue = pool->New<Value>();
2278 componentValue->object = root;
2279 component->getDefaultProperty()->addValue(componentValue);
2280 v->object = component;
2281 COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt));
2283 COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property"));
2290 // Compile assigning a single object instance to a regular property using the "on" syntax.
2294 // NumberAnimation on x { }
2296 bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeScript::Property *prop,
2297 QDeclarativeScript::Object *obj,
2298 QDeclarativeScript::Object *baseObj,
2299 QDeclarativeScript::Value *v,
2300 const BindingContext &ctxt)
2302 Q_ASSERT(prop->index != -1);
2303 Q_ASSERT(v->object->type != -1);
2305 if (!obj->metaObject()->property(prop->index).isWritable())
2306 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
2309 // Normally buildObject() will set this up, but we need the static
2310 // meta object earlier to test for assignability. It doesn't matter
2311 // that there may still be outstanding synthesized meta object changes
2312 // on this type, as they are not relevant for assignability testing
2313 v->object->metatype = output->types.at(v->object->type).metaObject();
2314 Q_ASSERT(v->object->metaObject());
2316 // Will be true if the assigned type inherits QDeclarativePropertyValueSource
2317 bool isPropertyValue = false;
2318 // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor
2319 bool isPropertyInterceptor = false;
2320 if (QDeclarativeType *valueType = toQmlType(v->object)) {
2321 isPropertyValue = valueType->propertyValueSourceCast() != -1;
2322 isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1;
2325 if (isPropertyValue || isPropertyInterceptor) {
2326 // Assign as a property value source
2327 COMPILE_CHECK(buildObject(v->object, ctxt));
2329 if (isPropertyInterceptor && prop->parent->synthdata.isEmpty())
2330 buildDynamicMeta(baseObj, ForceCreation);
2331 v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor;
2333 COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(v->object->typeName).arg(prop->name().toString()));
2339 // Compile assigning a literal or binding to a regular property
2340 bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeScript::Property *prop,
2341 QDeclarativeScript::Object *obj,
2342 QDeclarativeScript::Value *v,
2343 const BindingContext &ctxt)
2345 Q_ASSERT(prop->index != -1);
2347 if (v->value.isScript()) {
2349 //optimization for <Type>.<EnumValue> enum assignments
2350 if (prop->core.isEnum()) {
2351 bool isEnumAssignment = false;
2352 COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj,
2353 v, &isEnumAssignment));
2354 if (isEnumAssignment) {
2355 v->type = Value::Literal;
2360 COMPILE_CHECK(buildBinding(v, prop, ctxt));
2362 v->type = Value::PropertyBinding;
2366 COMPILE_CHECK(testLiteralAssignment(prop, v));
2368 v->type = Value::Literal;
2374 bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop,
2375 QDeclarativeScript::Object *obj,
2376 QDeclarativeScript::Value *v,
2379 *isAssignment = false;
2380 if (!prop.isEnumType())
2383 if (!prop.isWritable())
2384 COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
2386 QString string = v->value.asString();
2387 if (!string.at(0).isUpper())
2390 QStringList parts = string.split(QLatin1Char('.'));
2391 if (parts.count() != 2)
2394 QString typeName = parts.at(0);
2395 QDeclarativeType *type = 0;
2396 unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
2398 //handle enums on value types (where obj->typeName is empty)
2399 QString objTypeName = obj->typeName;
2400 if (objTypeName.isEmpty()) {
2401 QDeclarativeType *objType = toQmlType(obj);
2403 objTypeName = objType->qmlTypeName();
2409 QString enumValue = parts.at(1);
2412 if (objTypeName == type->qmlTypeName()) {
2413 // When these two match, we can short cut the search
2414 if (prop.isFlagType()) {
2415 value = prop.enumerator().keysToValue(enumValue.toUtf8().constData());
2417 value = prop.enumerator().keyToValue(enumValue.toUtf8().constData());
2420 // Otherwise we have to search the whole type
2421 // This matches the logic in QV8TypeWrapper
2422 QByteArray enumName = enumValue.toUtf8();
2423 const QMetaObject *metaObject = type->baseMetaObject();
2424 for (int ii = metaObject->enumeratorCount() - 1; value == -1 && ii >= 0; --ii) {
2425 QMetaEnum e = metaObject->enumerator(ii);
2426 value = e.keyToValue(enumName.constData());
2433 v->type = Value::Literal;
2434 v->value = QDeclarativeScript::Variant((double)value);
2435 *isAssignment = true;
2440 struct StaticQtMetaObject : public QObject
2442 static const QMetaObject *get()
2443 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
2446 // Similar logic to above, but not knowing target property.
2447 int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const
2449 int dot = script.indexOf('.');
2451 const QByteArray &scope = script.left(dot);
2452 QDeclarativeType *type = 0;
2453 unit->imports().resolveType(QString::fromUtf8(script.left(dot)), &type, 0, 0, 0, 0);
2454 if (!type && scope != "Qt")
2456 const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
2457 const char *key = script.constData() + dot+1;
2458 int i = mo->enumeratorCount();
2460 int v = mo->enumerator(i).keyToValue(key);
2468 const QMetaObject *QDeclarativeCompiler::resolveType(const QString& name) const
2470 QDeclarativeType *qmltype = 0;
2471 if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
2475 return qmltype->metaObject();
2478 // similar to logic of completeComponentBuild, but also sticks data
2479 // into primitives at the end
2480 int QDeclarativeCompiler::rewriteBinding(const QString& expression, const QString& name)
2482 QDeclarativeRewrite::RewriteBinding rewriteBinding;
2483 rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1));
2485 QString rewrite = rewriteBinding(expression, 0, 0);
2487 return output->indexForString(rewrite);
2490 // Ensures that the dynamic meta specification on obj is valid
2491 bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeScript::Object *obj)
2493 bool seenDefaultProperty = false;
2495 // We use a coarse grain, 31 bit hash to check if there are duplicates.
2496 // Calculating the hash for the names is not a waste as we have to test
2497 // them against the illegalNames set anyway.
2498 QHashField propNames;
2499 QHashField methodNames;
2502 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2503 const QDeclarativeScript::Object::DynamicProperty &prop = *p;
2505 if (prop.isDefaultProperty) {
2506 if (seenDefaultProperty)
2507 COMPILE_EXCEPTION(&prop, tr("Duplicate default property"));
2508 seenDefaultProperty = true;
2511 if (propNames.testAndSet(prop.name.hash())) {
2512 for (Object::DynamicProperty *p2 = obj->dynamicProperties.first(); p2 != p;
2513 p2 = obj->dynamicProperties.next(p2)) {
2514 if (p2->name == prop.name)
2515 COMPILE_EXCEPTION(&prop, tr("Duplicate property name"));
2519 if (prop.name.at(0).isUpper())
2520 COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
2522 if (enginePrivate->v8engine()->illegalNames().contains(prop.name))
2523 COMPILE_EXCEPTION(&prop, tr("Illegal property name"));
2526 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2527 const QDeclarativeScript::Object::DynamicSignal &currSig = *s;
2529 if (methodNames.testAndSet(currSig.name.hash())) {
2530 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2 != s;
2531 s2 = obj->dynamicSignals.next(s2)) {
2532 if (s2->name == currSig.name)
2533 COMPILE_EXCEPTION(&currSig, tr("Duplicate signal name"));
2537 if (currSig.name.at(0).isUpper())
2538 COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
2539 if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
2540 COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
2543 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2544 const QDeclarativeScript::Object::DynamicSlot &currSlot = *s;
2546 if (methodNames.testAndSet(currSlot.name.hash())) {
2547 for (Object::DynamicSignal *s2 = obj->dynamicSignals.first(); s2;
2548 s2 = obj->dynamicSignals.next(s2)) {
2549 if (s2->name == currSlot.name)
2550 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2552 for (Object::DynamicSlot *s2 = obj->dynamicSlots.first(); s2 != s;
2553 s2 = obj->dynamicSlots.next(s2)) {
2554 if (s2->name == currSlot.name)
2555 COMPILE_EXCEPTION(&currSlot, tr("Duplicate method name"));
2559 if (currSlot.name.at(0).isUpper())
2560 COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
2561 if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
2562 COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
2568 bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeScript::Object *obj)
2570 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2572 if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
2575 Property *property = 0;
2576 if (p->isDefaultProperty) {
2577 property = obj->getDefaultProperty();
2579 property = obj->getProperty(p->name);
2580 if (!property->values.isEmpty())
2581 COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
2584 if (property->value)
2585 COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
2587 property->values.append(p->defaultValue->values);
2592 Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter)
2594 bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeScript::Object *obj, DynamicMetaMode mode)
2597 Q_ASSERT(obj->metatype);
2599 if (mode != ForceCreation &&
2600 obj->dynamicProperties.isEmpty() &&
2601 obj->dynamicSignals.isEmpty() &&
2602 obj->dynamicSlots.isEmpty())
2605 bool resolveAlias = (mode == ResolveAliases);
2607 const Object::DynamicProperty *defaultProperty = 0;
2609 int varPropCount = 0;
2610 int totalPropCount = 0;
2611 int firstPropertyVarIndex = 0;
2613 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2615 if (p->type == Object::DynamicProperty::Alias)
2617 if (p->type == Object::DynamicProperty::Var)
2620 if (p->isDefaultProperty &&
2621 (resolveAlias || p->type != Object::DynamicProperty::Alias))
2622 defaultProperty = p;
2624 if (!resolveAlias) {
2625 // No point doing this for both the alias and non alias cases
2626 QDeclarativePropertyCache::Data *d = property(obj, p->name);
2627 if (d && d->isFinal())
2628 COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
2632 bool buildData = resolveAlias || aliasCount == 0;
2634 QByteArray dynamicData;
2636 typedef QDeclarativeVMEMetaData VMD;
2638 dynamicData = QByteArray(sizeof(QDeclarativeVMEMetaData) +
2639 (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) +
2640 obj->dynamicSlots.count() * sizeof(VMD::MethodData) +
2641 aliasCount * sizeof(VMD::AliasData), 0);
2644 int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1);
2646 QByteArray newClassName = obj->metatype->className();
2647 newClassName.append("_QML_");
2648 newClassName.append(QByteArray::number(uniqueClassId));
2650 if (compileState->root == obj && !compileState->nested) {
2651 QString path = output->url.path();
2652 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
2653 if (lastSlash > -1) {
2654 QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
2655 if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
2656 newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId);
2660 QFastMetaBuilder builder;
2661 QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(),
2662 obj->dynamicProperties.count() - (resolveAlias?0:aliasCount),
2663 obj->dynamicSlots.count(),
2664 obj->dynamicSignals.count() + obj->dynamicProperties.count(),
2665 defaultProperty?1:0);
2668 Object::DynamicProperty::Type dtype;
2670 const char *cppType;
2671 } builtinTypes[] = {
2672 { Object::DynamicProperty::Var, 0, "QVariant" },
2673 { Object::DynamicProperty::Variant, 0, "QVariant" },
2674 { Object::DynamicProperty::Int, QMetaType::Int, "int" },
2675 { Object::DynamicProperty::Bool, QMetaType::Bool, "bool" },
2676 { Object::DynamicProperty::Real, QMetaType::Double, "double" },
2677 { Object::DynamicProperty::String, QMetaType::QString, "QString" },
2678 { Object::DynamicProperty::Url, QMetaType::QUrl, "QUrl" },
2679 { Object::DynamicProperty::Color, QMetaType::QColor, "QColor" },
2680 { Object::DynamicProperty::Time, QMetaType::QTime, "QTime" },
2681 { Object::DynamicProperty::Date, QMetaType::QDate, "QDate" },
2682 { Object::DynamicProperty::DateTime, QMetaType::QDateTime, "QDateTime" },
2684 static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
2685 QFastMetaBuilder::StringRef typeRefs[builtinTypeCount];
2687 // Reserve dynamic properties
2688 if (obj->dynamicProperties.count()) {
2689 typedef QDeclarativeVMEMetaData VMD;
2691 int effectivePropertyIndex = 0;
2692 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2694 // Reserve space for name
2695 p->nameRef = builder.newString(p->name.utf8length());
2697 int propertyType = 0;
2698 bool readonly = false;
2699 QFastMetaBuilder::StringRef typeRef;
2701 if (p->type == Object::DynamicProperty::Alias) {
2703 } else if (p->type < builtinTypeCount) {
2704 Q_ASSERT(builtinTypes[p->type].dtype == p->type);
2705 propertyType = builtinTypes[p->type].metaType;
2706 if (typeRefs[p->type].isEmpty())
2707 typeRefs[p->type] = builder.newString(strlen(builtinTypes[p->type].cppType));
2708 typeRef = typeRefs[p->type];
2709 if (p->type == Object::DynamicProperty::Variant)
2713 Q_ASSERT(p->type == Object::DynamicProperty::CustomList ||
2714 p->type == Object::DynamicProperty::Custom);
2716 // XXX don't double resolve this in the case of an alias run
2718 QByteArray customTypeName;
2719 QDeclarativeType *qmltype = 0;
2721 if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
2722 COMPILE_EXCEPTION(p, tr("Invalid property type"));
2725 QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(QUrl(url));
2727 Q_ASSERT(tdata->isComplete());
2729 QDeclarativeCompiledData *data = tdata->compiledData();
2730 customTypeName = data->root->className();
2734 customTypeName = qmltype->typeName();
2737 if (p->type == Object::DynamicProperty::Custom) {
2738 customTypeName += '*';
2739 propertyType = QMetaType::QObjectStar;
2742 customTypeName = QByteArray("QDeclarativeListProperty<") + customTypeName + QByteArray(">");
2743 propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >();
2746 p->resolvedCustomTypeName = pool->NewByteArray(customTypeName);
2747 p->typeRef = builder.newString(customTypeName.length());
2748 typeRef = p->typeRef;
2751 if (p->type == Object::DynamicProperty::Var)
2755 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2756 vmd->propertyCount++;
2757 (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType;
2760 if (p->type < builtinTypeCount)
2761 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef, (QMetaType::Type)propertyType,
2762 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2763 effectivePropertyIndex);
2765 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef,
2766 readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
2767 effectivePropertyIndex);
2769 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2770 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2772 effectivePropertyIndex++;
2776 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2778 vmd->varPropertyCount = varPropCount;
2779 firstPropertyVarIndex = effectivePropertyIndex;
2780 totalPropCount = varPropCount + effectivePropertyIndex;
2781 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2782 if (p->type == Object::DynamicProperty::Var) {
2783 QFastMetaBuilder::StringRef typeRef = typeRefs[p->type];
2785 vmd->propertyCount++;
2786 (vmd->propertyData() + effectivePropertyIndex)->propertyType = -1;
2789 builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef, (QMetaType::Type)-1,
2790 QFastMetaBuilder::Writable, effectivePropertyIndex);
2792 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2793 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2795 effectivePropertyIndex++;
2802 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2803 if (p->type == Object::DynamicProperty::Alias) {
2805 Q_ASSERT(buildData);
2806 ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++;
2807 COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex,
2810 // Even if we aren't resolving the alias, we need a fake signal so that the
2811 // metaobject remains consistent across the resolve and non-resolve alias runs
2812 p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
2813 builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
2814 effectivePropertyIndex++;
2821 // Reserve default property
2822 QFastMetaBuilder::StringRef defPropRef;
2823 if (defaultProperty) {
2824 defPropRef = builder.newString(strlen("DefaultProperty"));
2825 builder.setClassInfo(0, defPropRef, defaultProperty->nameRef);
2828 // Reserve dynamic signals
2829 int signalIndex = 0;
2830 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2832 int paramCount = s->parameterNames.count();
2834 int signatureSize = s->name.utf8length() + 2 /* paren */;
2836 if (paramCount) signatureSize += s->parameterTypesLength() + (paramCount - 1) /* commas */;
2837 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1) /* commas */;
2839 s->signatureRef = builder.newString(signatureSize);
2840 if (namesSize) s->parameterNamesRef = builder.newString(namesSize);
2843 ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++;
2845 builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->signatureRef, s->parameterNamesRef);
2849 // Reserve dynamic slots
2850 if (obj->dynamicSlots.count()) {
2852 // Allocate QVariant string
2853 if (typeRefs[0].isEmpty())
2854 typeRefs[0] = builder.newString(strlen(builtinTypes[0].cppType));
2856 typedef QDeclarativeVMEMetaData VMD;
2858 int methodIndex = 0;
2859 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2860 int paramCount = s->parameterNames.count();
2862 int signatureSize = s->name.utf8length() + 2 /* paren */;
2864 if (paramCount) signatureSize += (paramCount * strlen("QVariant") + (paramCount - 1));
2865 if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
2867 s->signatureRef = builder.newString(signatureSize);
2868 if (namesSize) s->parameterNamesRef = builder.newString(namesSize);
2870 builder.setMethod(methodIndex, s->signatureRef, s->parameterNamesRef, typeRefs[0]);
2874 funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ +
2875 namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
2876 funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
2877 for (int jj = 0; jj < paramCount; ++jj) {
2878 if (jj) funcScript.append(QLatin1Char(','));
2879 funcScript.append(QLatin1String(s->parameterNames.at(jj)));
2881 funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
2883 VMD::MethodData methodData = { s->parameterNames.count(), 0,
2884 funcScript.length(),
2885 s->location.start.line };
2887 VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
2890 VMD::MethodData &md = *(vmd->methodData() + methodIndex);
2892 md.bodyOffset = dynamicData.size();
2894 dynamicData.append((const char *)funcScript.constData(),
2895 (funcScript.length() * sizeof(QChar)));
2902 // Now allocate used builtin types
2903 for (int ii = 0; ii < builtinTypeCount; ++ii) {
2904 if (!typeRefs[ii].isEmpty())
2905 typeRefs[ii].load(builtinTypes[ii].cppType);
2908 // Now allocate properties
2909 for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
2911 char *d = p->changedSignatureRef.data();
2912 p->name.writeUtf8(d);
2913 strcpy(d + p->name.utf8length(), "Changed()");
2915 if (p->type == Object::DynamicProperty::Alias && !resolveAlias)
2918 p->nameRef.load(p->name);
2920 if (p->type >= builtinTypeCount) {
2921 Q_ASSERT(p->resolvedCustomTypeName);
2922 p->typeRef.load(*p->resolvedCustomTypeName);
2926 // Allocate default property if necessary
2927 if (defaultProperty)
2928 strcpy(defPropRef.data(), "DefaultProperty");
2930 // Now allocate signals
2931 for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) {
2933 char *d = s->signatureRef.data();
2934 char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data();
2935 s->name.writeUtf8(d); d += s->name.utf8length();
2938 for (int jj = 0; jj < s->parameterNames.count(); ++jj) {
2939 if (jj != 0) { *d++ = ','; *d2++ = ','; }
2940 strcpy(d, s->parameterTypes.at(jj).constData());
2941 d += s->parameterTypes.at(jj).length();
2942 s->parameterNames.at(jj).writeUtf8(d2);
2943 d2 += s->parameterNames.at(jj).utf8length();
2950 // Now allocate methods
2951 for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
2952 char *d = s->signatureRef.data();
2953 char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data();
2954 s->name.writeUtf8(d); d += s->name.utf8length();
2956 for (int jj = 0; jj < s->parameterNames.count(); ++jj) {
2957 if (jj != 0) { *d++ = ','; *d2++ = ','; }
2958 strcpy(d, "QVariant");
2959 d += strlen("QVariant");
2960 strcpy(d2, s->parameterNames.at(jj).constData());
2961 d2 += s->parameterNames.at(jj).length();
2968 // Now allocate class name
2969 classNameRef.load(newClassName);
2971 obj->metadata = builder.toData();
2972 builder.fromData(&obj->extObject, obj->metatype, obj->metadata);
2974 if (mode == IgnoreAliases && aliasCount)
2975 compileState->aliasingObjects.append(obj);
2977 obj->synthdata = dynamicData;
2979 if (obj->synthCache) {
2980 obj->synthCache->release();
2981 obj->synthCache = 0;
2984 if (obj->type != -1) {
2985 QDeclarativePropertyCache *cache = output->types[obj->type].createPropertyCache(engine)->copy();
2986 cache->append(engine, &obj->extObject,
2987 QDeclarativePropertyCache::Data::NoFlags,
2988 QDeclarativePropertyCache::Data::IsVMEFunction,
2989 QDeclarativePropertyCache::Data::IsVMESignal);
2991 // now we modify the flags appropriately for var properties.
2992 int propertyOffset = obj->extObject.propertyOffset();
2993 QDeclarativePropertyCache::Data *currPropData = 0;
2994 for (int pvi = firstPropertyVarIndex; pvi < totalPropCount; ++pvi) {
2995 currPropData = cache->property(pvi + propertyOffset);
2996 currPropData->setFlags(currPropData->getFlags() | QDeclarativePropertyCache::Data::IsVMEProperty);
2999 obj->synthCache = cache;
3005 bool QDeclarativeCompiler::checkValidId(QDeclarativeScript::Value *v, const QString &val)
3008 COMPILE_EXCEPTION(v, tr( "Invalid empty ID"));
3010 QChar ch = val.at(0);
3011 if (ch.isLetter() && !ch.isLower())
3012 COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter"));
3014 QChar u(QLatin1Char('_'));
3015 if (!ch.isLetter() && ch != u)
3016 COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore"));
3018 for (int ii = 1; ii < val.count(); ++ii) {
3020 if (!ch.isLetterOrNumber() && ch != u)
3021 COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores"));
3024 if (enginePrivate->v8engine()->illegalNames().contains(val))
3025 COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
3030 #include <qdeclarativejsparser_p.h>
3032 static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node)
3034 if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) {
3036 static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name.toString();
3037 return QStringList() << name;
3038 } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) {
3039 QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node);
3041 QStringList rv = astNodeToStringList(expr->base);
3044 rv.append(expr->name.toString());
3047 return QStringList();
3050 bool QDeclarativeCompiler::compileAlias(QFastMetaBuilder &builder,
3052 QDeclarativeScript::Object *obj,
3053 int propIndex, int aliasIndex,
3054 Object::DynamicProperty &prop)
3056 if (!prop.defaultValue)
3057 COMPILE_EXCEPTION(obj, tr("No property alias location"));
3059 if (!prop.defaultValue->values.isOne() ||
3060 prop.defaultValue->values.first()->object ||
3061 !prop.defaultValue->values.first()->value.isScript())
3062 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3064 QDeclarativeJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST();
3066 COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen?
3068 QStringList alias = astNodeToStringList(node);
3070 if (alias.count() < 1 || alias.count() > 3)
3071 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
3073 QDeclarativeScript::Object *idObject = compileState->ids.value(alias.at(0));
3075 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0)));
3077 QByteArray typeName;
3082 bool writable = false;
3083 bool resettable = false;
3084 if (alias.count() == 2 || alias.count() == 3) {
3085 propIdx = indexOfProperty(idObject, alias.at(1));
3087 if (-1 == propIdx) {
3088 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3089 } else if (propIdx > 0xFFFF) {
3090 COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds"));
3093 QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx);
3094 if (!aliasProperty.isScriptable())
3095 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3097 writable = aliasProperty.isWritable();
3098 resettable = aliasProperty.isResettable();
3100 if (aliasProperty.type() < QVariant::UserType)
3101 type = aliasProperty.type();
3103 if (alias.count() == 3) {
3104 QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()];
3106 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3108 propIdx |= ((unsigned int)aliasProperty.type()) << 24;
3110 int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData());
3111 if (valueTypeIndex == -1)
3112 COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
3113 Q_ASSERT(valueTypeIndex <= 0xFF);
3115 aliasProperty = valueType->metaObject()->property(valueTypeIndex);
3116 propIdx |= (valueTypeIndex << 16);
3118 // update the property type
3119 type = aliasProperty.type();
3120 if (type >= (int)QVariant::UserType)
3124 if (aliasProperty.isEnumType())
3125 typeName = "int"; // Avoid introducing a dependency on the aliased metaobject
3127 typeName = aliasProperty.typeName();
3129 Q_ASSERT(idObject->type != -1); // How else did it get an id?
3131 const QDeclarativeCompiledData::TypeReference &ref = output->types.at(idObject->type);
3133 typeName = ref.type->typeName();
3135 typeName = ref.component->root->className();
3140 if (typeName.endsWith('*'))
3141 flags |= QML_ALIAS_FLAG_PTR;
3143 QDeclarativeVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags };
3145 typedef QDeclarativeVMEMetaData VMD;
3146 VMD *vmd = (QDeclarativeVMEMetaData *)data.data();
3147 *(vmd->aliasData() + aliasIndex) = aliasData;
3149 prop.nameRef = builder.newString(prop.name.utf8length());
3150 prop.resolvedCustomTypeName = pool->NewByteArray(typeName);
3151 prop.typeRef = builder.newString(typeName.length());
3153 int propertyFlags = 0;
3155 propertyFlags |= QFastMetaBuilder::Writable;
3157 propertyFlags |= QFastMetaBuilder::Resettable;
3159 builder.setProperty(propIndex, prop.nameRef, prop.typeRef, (QMetaType::Type)type,
3160 (QFastMetaBuilder::PropertyFlag)propertyFlags,
3166 bool QDeclarativeCompiler::buildBinding(QDeclarativeScript::Value *value,
3167 QDeclarativeScript::Property *prop,
3168 const BindingContext &ctxt)
3170 Q_ASSERT(prop->index != -1);
3171 Q_ASSERT(prop->parent);
3172 Q_ASSERT(prop->parent->metaObject());
3174 if (!prop->core.isWritable() && !prop->core.isQList())
3175 COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
3177 BindingReference *reference = pool->New<BindingReference>();
3178 reference->expression = value->value;
3179 reference->property = prop;
3180 reference->value = value;
3181 reference->bindingContext = ctxt;
3182 addBindingReference(reference);
3187 void QDeclarativeCompiler::genBindingAssignment(QDeclarativeScript::Value *binding,
3188 QDeclarativeScript::Property *prop,
3189 QDeclarativeScript::Object *obj,
3190 QDeclarativeScript::Property *valueTypeProperty)
3193 Q_ASSERT(binding->bindingReference);
3195 const BindingReference &ref = *binding->bindingReference;
3196 if (ref.dataType == BindingReference::V4) {
3197 Instruction::StoreV4Binding store;
3198 store.value = ref.compiledIndex;
3199 store.context = ref.bindingContext.stack;
3200 store.owner = ref.bindingContext.owner;
3201 if (valueTypeProperty) {
3202 store.property = (valueTypeProperty->index & 0xFFFF) |
3203 ((valueTypeProperty->type & 0xFF)) << 16 |
3204 ((prop->index & 0xFF) << 24);
3205 store.isRoot = (compileState->root == valueTypeProperty->parent);
3207 store.property = prop->index;
3208 store.isRoot = (compileState->root == obj);
3210 store.line = binding->location.start.line;
3211 output->addInstruction(store);
3212 } else if (ref.dataType == BindingReference::V8) {
3213 Instruction::StoreV8Binding store;
3214 store.value = ref.compiledIndex;
3215 store.context = ref.bindingContext.stack;
3216 store.owner = ref.bindingContext.owner;
3217 if (valueTypeProperty) {
3218 store.isRoot = (compileState->root == valueTypeProperty->parent);
3220 store.isRoot = (compileState->root == obj);
3222 store.line = binding->location.start.line;
3224 Q_ASSERT(ref.bindingContext.owner == 0 ||
3225 (ref.bindingContext.owner != 0 && valueTypeProperty));
3226 if (ref.bindingContext.owner) {
3227 store.property = genValueTypeData(prop, valueTypeProperty);
3229 store.property = prop->core;
3232 output->addInstruction(store);
3234 QDeclarativeInstruction store;
3235 store.assignBinding.value = output->indexForString(ref.rewrittenExpression);
3236 store.assignBinding.context = ref.bindingContext.stack;
3237 store.assignBinding.owner = ref.bindingContext.owner;
3238 store.assignBinding.line = binding->location.start.line;
3240 if (valueTypeProperty) {
3241 store.assignBinding.isRoot = (compileState->root == valueTypeProperty->parent);
3243 store.assignBinding.isRoot = (compileState->root == obj);
3246 Q_ASSERT(ref.bindingContext.owner == 0 ||
3247 (ref.bindingContext.owner != 0 && valueTypeProperty));
3248 if (ref.bindingContext.owner) {
3249 store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
3251 store.assignBinding.property = prop->core;
3253 output->addInstructionHelper(
3254 !prop->isAlias ? QDeclarativeInstruction::StoreBinding
3255 : QDeclarativeInstruction::StoreBindingOnAlias
3260 int QDeclarativeCompiler::genContextCache()
3262 if (compileState->ids.count() == 0)
3265 QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache();
3266 cache->reserve(compileState->ids.count());
3267 for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
3268 cache->add(o->id, o->idIndex);
3270 output->contextCaches.append(cache);
3271 return output->contextCaches.count() - 1;
3274 QDeclarativePropertyCache::Data
3275 QDeclarativeCompiler::genValueTypeData(QDeclarativeScript::Property *valueTypeProp,
3276 QDeclarativeScript::Property *prop)
3278 typedef QDeclarativePropertyPrivate QDPP;
3279 return QDPP::saveValueType(prop->parent->metaObject(), prop->index,
3280 enginePrivate->valueTypes[prop->type]->metaObject(),
3281 valueTypeProp->index, engine);
3284 bool QDeclarativeCompiler::completeComponentBuild()
3287 componentStats->componentStat.ids = compileState->ids.count();
3289 for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject;
3290 aliasObject = compileState->aliasingObjects.next(aliasObject))
3291 COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
3293 QV4Compiler::Expression expr(unit->imports());
3294 expr.component = compileState->root;
3295 expr.ids = &compileState->ids;
3296 expr.importCache = output->importCache;
3298 QV4Compiler bindingCompiler;
3300 QList<BindingReference*> sharedBindings;
3302 for (BindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
3304 BindingReference &binding = *b;
3306 // ### We don't currently optimize for bindings on alias's - because
3307 // of the solution to QTBUG-13719
3308 if (!binding.property->isAlias) {
3309 expr.context = binding.bindingContext.object;
3310 expr.property = binding.property;
3311 expr.expression = binding.expression;
3313 int index = bindingCompiler.compile(expr, enginePrivate);
3315 binding.dataType = BindingReference::V4;
3316 binding.compiledIndex = index;
3318 componentStats->componentStat.optimizedBindings.append(b->value->location);
3323 // Pre-rewrite the expression
3324 QString expression = binding.expression.asScript();
3326 QDeclarativeRewrite::RewriteBinding rewriteBinding;
3327 rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
3328 bool isSharable = false;
3329 binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
3331 if (isSharable && !binding.property->isAlias /* See above re alias */ &&
3332 binding.property->type != qMetaTypeId<QDeclarativeBinding*>()) {
3333 binding.dataType = BindingReference::V8;
3334 sharedBindings.append(b);
3336 binding.dataType = BindingReference::QtScript;
3340 componentStats->componentStat.scriptBindings.append(b->value->location);
3343 if (!sharedBindings.isEmpty()) {
3345 static bool lt(const BindingReference *lhs, const BindingReference *rhs)
3347 return lhs->value->location.start.line < rhs->value->location.start.line;
3351 qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
3353 int startLineNumber = sharedBindings.at(0)->value->location.start.line;
3354 int lineNumber = startLineNumber;
3356 QString functionArray(QLatin1String("["));
3357 for (int ii = 0; ii < sharedBindings.count(); ++ii) {
3358 BindingReference *reference = sharedBindings.at(ii);
3359 QDeclarativeScript::Value *value = reference->value;
3360 const QString &expression = reference->rewrittenExpression;
3362 if (ii != 0) functionArray += QLatin1String(",");
3364 while (lineNumber < value->location.start.line) {
3366 functionArray += QLatin1String("\n");
3369 functionArray += expression;
3370 reference->compiledIndex = ii;
3372 functionArray += QLatin1String("]");
3374 compileState->v8BindingProgram = functionArray;
3375 compileState->v8BindingProgramLine = startLineNumber;
3376 compileState->v8BindingProgramIndex = output->v8bindings.count();
3377 output->v8bindings.append(v8::Persistent<v8::Array>());
3380 if (bindingCompiler.isValid())
3381 compileState->compiledBindingData = bindingCompiler.program();
3383 // Check pop()'s matched push()'s
3384 Q_ASSERT(compileState->objectDepth.depth() == 0);
3385 Q_ASSERT(compileState->listDepth.depth() == 0);
3387 saveComponentState();
3392 void QDeclarativeCompiler::dumpStats()
3394 Q_ASSERT(componentStats);
3395 qWarning().nospace() << "QML Document: " << output->url.toString();
3396 for (int ii = 0; ii < componentStats->savedComponentStats.count(); ++ii) {
3397 const ComponentStat &stat = componentStats->savedComponentStats.at(ii);
3398 qWarning().nospace() << " Component Line " << stat.lineNumber;
3399 qWarning().nospace() << " Total Objects: " << stat.objects;
3400 qWarning().nospace() << " IDs Used: " << stat.ids;
3401 qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
3405 for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
3406 if (0 == (ii % 10)) {
3407 if (ii) output.append("\n");
3412 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
3414 output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
3415 output.append(") ");
3417 if (!output.isEmpty())
3418 qWarning().nospace() << output.constData();
3421 qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
3424 for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) {
3425 if (0 == (ii % 10)) {
3426 if (ii) output.append("\n");
3431 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line));
3433 output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column));
3434 output.append(") ");
3436 if (!output.isEmpty())
3437 qWarning().nospace() << output.constData();
3443 Returns true if from can be assigned to a (QObject) property of type
3446 bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeScript::Object *from)
3448 const QMetaObject *toMo = enginePrivate->rawMetaObjectForType(to);
3449 const QMetaObject *fromMo = from->metaObject();
3452 if (QDeclarativePropertyPrivate::equal(fromMo, toMo))
3454 fromMo = fromMo->superClass();
3460 Returns the element name, as written in the QML file, for o.
3462 QString QDeclarativeCompiler::elementName(QDeclarativeScript::Object *o)
3465 if (o->type != -1) {
3466 return output->types.at(o->type).className;
3472 QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeScript::Object *from)
3475 const QMetaObject *mo = from->metatype;
3476 QDeclarativeType *type = 0;
3477 while (!type && mo) {
3478 type = QDeclarativeMetaType::qmlType(mo);
3479 mo = mo->superClass();
3484 QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeScript::Object *obj)
3486 const QMetaObject *mo = obj->metatype;
3488 int idx = mo->indexOfClassInfo("DeferredPropertyNames");
3490 return QStringList();
3492 QMetaClassInfo classInfo = mo->classInfo(idx);
3493 QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
3497 QDeclarativePropertyCache::Data *
3498 QDeclarativeCompiler::property(QDeclarativeScript::Object *object, int index)
3500 QDeclarativePropertyCache *cache = 0;
3502 if (object->synthCache)
3503 cache = object->synthCache;
3504 else if (object->type != -1)
3505 cache = output->types[object->type].createPropertyCache(engine);
3507 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3509 return cache->property(index);
3512 QDeclarativePropertyCache::Data *
3513 QDeclarativeCompiler::property(QDeclarativeScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3515 if (notInRevision) *notInRevision = false;
3517 QDeclarativePropertyCache *cache = 0;
3519 if (object->synthCache)
3520 cache = object->synthCache;
3521 else if (object->type != -1)
3522 cache = output->types[object->type].createPropertyCache(engine);
3524 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3526 QDeclarativePropertyCache::Data *d = cache->property(name);
3528 // Find the first property
3529 while (d && d->isFunction())
3530 d = cache->overrideData(d);
3532 if (d && !cache->isAllowedInRevision(d)) {
3533 if (notInRevision) *notInRevision = true;
3540 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3541 QDeclarativePropertyCache::Data *
3542 QDeclarativeCompiler::signal(QDeclarativeScript::Object *object, const QHashedStringRef &name, bool *notInRevision)
3544 if (notInRevision) *notInRevision = false;
3546 QDeclarativePropertyCache *cache = 0;
3548 if (object->synthCache)
3549 cache = object->synthCache;
3550 else if (object->type != -1)
3551 cache = output->types[object->type].createPropertyCache(engine);
3553 cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject());
3556 QDeclarativePropertyCache::Data *d = cache->property(name);
3557 if (notInRevision) *notInRevision = false;
3559 while (d && !(d->isFunction()))
3560 d = cache->overrideData(d);
3562 if (d && !cache->isAllowedInRevision(d)) {
3563 if (notInRevision) *notInRevision = true;
3569 if (name.endsWith(Changed_string)) {
3570 QHashedStringRef propName = name.mid(0, name.length() - Changed_string.length());
3572 d = property(object, propName, notInRevision);
3574 return cache->method(d->notifyIndex);
3580 // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName
3581 int QDeclarativeCompiler::indexOfSignal(QDeclarativeScript::Object *object, const QString &name,
3582 bool *notInRevision)
3584 QDeclarativePropertyCache::Data *d = signal(object, QStringRef(&name), notInRevision);
3585 return d?d->coreIndex:-1;
3588 int QDeclarativeCompiler::indexOfProperty(QDeclarativeScript::Object *object, const QString &name,
3589 bool *notInRevision)
3591 return indexOfProperty(object, QStringRef(&name), notInRevision);
3594 int QDeclarativeCompiler::indexOfProperty(QDeclarativeScript::Object *object, const QHashedStringRef &name,
3595 bool *notInRevision)
3597 QDeclarativePropertyCache::Data *d = property(object, name, notInRevision);
3598 return d?d->coreIndex:-1;