DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP);
DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS);
+using namespace QDeclarativeJS;
using namespace QDeclarativeScript;
using namespace QDeclarativeCompilerTypes;
static QString Changed_string(QLatin1String("Changed"));
static QString Component_string(QLatin1String("Component"));
static QString Component_import_string(QLatin1String("QML/Component"));
+static QString qsTr_string(QLatin1String("qsTr"));
+static QString qsTrId_string(QLatin1String("qsTrId"));
/*!
Instantiate a new QDeclarativeCompiler.
*/
QDeclarativeCompiler::QDeclarativeCompiler(QDeclarativePool *pool)
: pool(pool), output(0), engine(0), unitRoot(0), unit(0), cachedComponentTypeRef(-1),
- componentStats(0)
+ cachedTranslationContextIndex(-1), componentStats(0)
{
if (compilerStatDump())
componentStats = pool->New<ComponentStats>();
this->enginePrivate = 0;
this->unit = 0;
this->cachedComponentTypeRef = -1;
+ this->cachedTranslationContextIndex = -1;
this->unitRoot = 0;
return !isError();
return cachedComponentTypeRef;
}
+int QDeclarativeCompiler::translationContextIndex()
+{
+ if (cachedTranslationContextIndex == -1) {
+ // This code must match that in the qsTr() implementation
+ QString path = output->url.toString();
+ int lastSlash = path.lastIndexOf(QLatin1Char('/'));
+ QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) :
+ QString();
+ QByteArray contextUtf8 = context.toUtf8();
+ cachedTranslationContextIndex = output->indexForByteArray(contextUtf8);
+ }
+ return cachedTranslationContextIndex;
+}
+
bool QDeclarativeCompiler::buildSignal(QDeclarativeScript::Property *prop, QDeclarativeScript::Object *obj,
const BindingContext &ctxt)
{
compileState->ids.append(obj);
}
-void QDeclarativeCompiler::addBindingReference(BindingReference *ref)
+void QDeclarativeCompiler::addBindingReference(JSBindingReference *ref)
{
Q_ASSERT(ref->value && !ref->value->bindingReference);
ref->value->bindingReference = ref;
if (isEnumAssignment) {
value->type = Value::Literal;
} else {
- BindingReference *reference = pool->New<BindingReference>();
+ JSBindingReference *reference = pool->New<JSBindingReference>();
reference->expression = value->value;
reference->property = prop;
reference->value = value;
}
}
- COMPILE_CHECK(buildBinding(v, prop, ctxt));
+ // Test for other binding optimizations
+ if (!buildLiteralBinding(v, prop, ctxt))
+ COMPILE_CHECK(buildBinding(v, prop, ctxt));
v->type = Value::PropertyBinding;
if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
- BindingReference *reference = pool->New<BindingReference>();
+ JSBindingReference *reference = pool->New<JSBindingReference>();
reference->expression = value->value;
reference->property = prop;
reference->value = value;
return true;
}
+bool QDeclarativeCompiler::buildLiteralBinding(QDeclarativeScript::Value *v,
+ QDeclarativeScript::Property *prop,
+ const QDeclarativeCompilerTypes::BindingContext &)
+{
+ Q_ASSERT(v->value.isScript());
+
+ if (!prop->core.isWritable())
+ return false;
+
+ AST::Node *binding = v->value.asAST();
+
+ if (prop->type == QVariant::String) {
+ if (AST::CallExpression *e = AST::cast<AST::CallExpression *>(binding)) {
+ if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(e->base)) {
+ if (i->name == qsTrId_string) {
+ AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
+ AST::ArgumentList *arg2 = arg1?arg1->next:0;
+
+ if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
+ (!arg2 || arg2->expression->kind == AST::Node::Kind_NumericLiteral) &&
+ (!arg2 || !arg2->next)) {
+
+ QStringRef text;
+ int n = -1;
+
+ text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
+ if (arg2) n = (int)AST::cast<AST::NumericLiteral *>(arg2->expression)->value;
+
+ TrBindingReference *reference = pool->New<TrBindingReference>();
+ reference->dataType = BindingReference::TrId;
+ reference->text = text;
+ reference->n = n;
+ v->bindingReference = reference;
+ return true;
+ }
+
+ } else if (i->name == qsTr_string) {
+
+ AST::ArgumentList *arg1 = e->arguments?e->arguments:0;
+ AST::ArgumentList *arg2 = arg1?arg1->next:0;
+ AST::ArgumentList *arg3 = arg2?arg2->next:0;
+
+ if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral &&
+ (!arg2 || arg2->expression->kind == AST::Node::Kind_StringLiteral) &&
+ (!arg3 || arg3->expression->kind == AST::Node::Kind_NumericLiteral) &&
+ (!arg3 || !arg3->next)) {
+
+ QStringRef text;
+ QStringRef comment;
+ int n = -1;
+
+ text = AST::cast<AST::StringLiteral *>(arg1->expression)->value;
+ if (arg2) comment = AST::cast<AST::StringLiteral *>(arg2->expression)->value;
+ if (arg3) n = (int)AST::cast<AST::NumericLiteral *>(arg3->expression)->value;
+
+ TrBindingReference *reference = pool->New<TrBindingReference>();
+ reference->dataType = BindingReference::Tr;
+ reference->text = text;
+ reference->comment = comment;
+ reference->n = n;
+ v->bindingReference = reference;
+ return true;
+ }
+
+ }
+ }
+ }
+
+ }
+
+ return false;
+}
+
void QDeclarativeCompiler::genBindingAssignment(QDeclarativeScript::Value *binding,
QDeclarativeScript::Property *prop,
QDeclarativeScript::Object *obj,
Q_ASSERT(binding->bindingReference);
const BindingReference &ref = *binding->bindingReference;
- if (ref.dataType == BindingReference::V4) {
+ if (ref.dataType == BindingReference::TrId) {
+ const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
+
+ Instruction::StoreTrIdString store;
+ store.propertyIndex = prop->core.coreIndex;
+ store.text = output->indexForByteArray(tr.text.toUtf8());
+ store.n = tr.n;
+ output->addInstruction(store);
+ } else if (ref.dataType == BindingReference::Tr) {
+ const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref);
+
+ Instruction::StoreTrString store;
+ store.propertyIndex = prop->core.coreIndex;
+ store.context = translationContextIndex();
+ store.text = output->indexForByteArray(tr.text.toUtf8());
+ store.comment = output->indexForByteArray(tr.comment.toUtf8());
+ store.n = tr.n;
+ output->addInstruction(store);
+ } else if (ref.dataType == BindingReference::V4) {
+ const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
+
Instruction::StoreV4Binding store;
- store.value = ref.compiledIndex;
- store.context = ref.bindingContext.stack;
- store.owner = ref.bindingContext.owner;
+ store.value = js.compiledIndex;
+ store.context = js.bindingContext.stack;
+ store.owner = js.bindingContext.owner;
if (valueTypeProperty) {
store.property = (valueTypeProperty->index & 0xFFFF) |
((valueTypeProperty->type & 0xFF)) << 16 |
store.column = binding->location.start.column;
output->addInstruction(store);
} else if (ref.dataType == BindingReference::V8) {
+ const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
+
Instruction::StoreV8Binding store;
- store.value = ref.compiledIndex;
- store.context = ref.bindingContext.stack;
- store.owner = ref.bindingContext.owner;
+ store.value = js.compiledIndex;
+ store.context = js.bindingContext.stack;
+ store.owner = js.bindingContext.owner;
if (valueTypeProperty) {
store.isRoot = (compileState->root == valueTypeProperty->parent);
} else {
store.line = binding->location.start.line;
store.column = binding->location.start.column;
- Q_ASSERT(ref.bindingContext.owner == 0 ||
- (ref.bindingContext.owner != 0 && valueTypeProperty));
- if (ref.bindingContext.owner) {
+ Q_ASSERT(js.bindingContext.owner == 0 ||
+ (js.bindingContext.owner != 0 && valueTypeProperty));
+ if (js.bindingContext.owner) {
store.property = genValueTypeData(prop, valueTypeProperty);
} else {
store.property = prop->core;
}
output->addInstruction(store);
- } else {
+ } else if (ref.dataType == BindingReference::QtScript) {
+ const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
+
QDeclarativeInstruction store;
- store.assignBinding.value = output->indexForString(ref.rewrittenExpression);
- store.assignBinding.context = ref.bindingContext.stack;
- store.assignBinding.owner = ref.bindingContext.owner;
+ store.assignBinding.value = output->indexForString(js.rewrittenExpression);
+ store.assignBinding.context = js.bindingContext.stack;
+ store.assignBinding.owner = js.bindingContext.owner;
store.assignBinding.line = binding->location.start.line;
store.assignBinding.column = binding->location.start.column;
store.assignBinding.isRoot = (compileState->root == obj);
}
- Q_ASSERT(ref.bindingContext.owner == 0 ||
- (ref.bindingContext.owner != 0 && valueTypeProperty));
- if (ref.bindingContext.owner) {
+ Q_ASSERT(js.bindingContext.owner == 0 ||
+ (js.bindingContext.owner != 0 && valueTypeProperty));
+ if (js.bindingContext.owner) {
store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
} else {
store.assignBinding.property = prop->core;
!prop->isAlias ? QDeclarativeInstruction::StoreBinding
: QDeclarativeInstruction::StoreBindingOnAlias
, store);
+ } else {
+ Q_ASSERT(!"Unhandled BindingReference::DataType type");
}
}
QV4Compiler bindingCompiler;
- QList<BindingReference*> sharedBindings;
+ QList<JSBindingReference*> sharedBindings;
- for (BindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
+ for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
- BindingReference &binding = *b;
+ JSBindingReference &binding = *b;
// ### We don't currently optimize for bindings on alias's - because
// of the solution to QTBUG-13719
if (!sharedBindings.isEmpty()) {
struct Sort {
- static bool lt(const BindingReference *lhs, const BindingReference *rhs)
+ static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs)
{
return lhs->value->location.start.line < rhs->value->location.start.line;
}
QString functionArray(QLatin1String("["));
for (int ii = 0; ii < sharedBindings.count(); ++ii) {
- BindingReference *reference = sharedBindings.at(ii);
+ JSBindingReference *reference = sharedBindings.at(ii);
QDeclarativeScript::Value *value = reference->value;
const QString &expression = reference->rewrittenExpression;
QDeclarativeScript::Object *object;
};
- struct BindingReference : public QDeclarativePool::Class
+ struct BindingReference
{
- BindingReference() : nextReference(0) {}
+ enum DataType { QtScript, V4, V8,
+ Tr, TrId };
+ DataType dataType;
+ };
+
+ struct JSBindingReference : public QDeclarativePool::Class,
+ public BindingReference
+ {
+ JSBindingReference() : nextReference(0) {}
QDeclarativeScript::Variant expression;
QDeclarativeScript::Property *property;
QDeclarativeScript::Value *value;
- enum DataType { QtScript, V4, V8 };
- DataType dataType;
-
int compiledIndex;
QString rewrittenExpression;
BindingContext bindingContext;
- BindingReference *nextReference;
+ JSBindingReference *nextReference;
+ };
+
+ struct TrBindingReference : public QDeclarativePool::POD,
+ public BindingReference
+ {
+ QStringRef text;
+ QStringRef comment;
+ int n;
};
struct IdList : public QFieldList<QDeclarativeScript::Object,
DepthStack objectDepth;
DepthStack listDepth;
- typedef QDeclarativeCompilerTypes::BindingReference B;
- typedef QFieldList<B, &B::nextReference> BindingReferenceList;
- BindingReferenceList bindings;
+ typedef QDeclarativeCompilerTypes::JSBindingReference B;
+ typedef QFieldList<B, &B::nextReference> JSBindingReferenceList;
+ JSBindingReferenceList bindings;
typedef QDeclarativeScript::Object O;
typedef QFieldList<O, &O::nextAliasingObject> AliasingObjectsList;
AliasingObjectsList aliasingObjects;
bool checkDynamicMeta(QDeclarativeScript::Object *obj);
bool buildBinding(QDeclarativeScript::Value *, QDeclarativeScript::Property *prop,
const QDeclarativeCompilerTypes::BindingContext &ctxt);
+ bool buildLiteralBinding(QDeclarativeScript::Value *, QDeclarativeScript::Property *prop,
+ const QDeclarativeCompilerTypes::BindingContext &ctxt);
bool buildComponentFromRoot(QDeclarativeScript::Object *obj, const QDeclarativeCompilerTypes::BindingContext &);
bool compileAlias(QFastMetaBuilder &,
QByteArray &data,
QDeclarativeScript::Property *valueTypeProp);
int componentTypeRef();
+ int translationContextIndex();
static QDeclarativeType *toQmlType(QDeclarativeScript::Object *from);
bool canCoerce(int to, QDeclarativeScript::Object *from);
void dumpStats();
- void addBindingReference(QDeclarativeCompilerTypes::BindingReference *);
+ void addBindingReference(QDeclarativeCompilerTypes::JSBindingReference *);
QDeclarativeCompilerTypes::ComponentCompileState *compileState;
QDeclarativeScript::Object *unitRoot;
QDeclarativeTypeData *unit;
int cachedComponentTypeRef;
+ int cachedTranslationContextIndex;
// Compiler component statistics. Only collected if QML_COMPILER_STATS=1
struct ComponentStat
QCOMPARE(object->property("basic").toString(), QLatin1String("bonjour"));
QCOMPARE(object->property("basic2").toString(), QLatin1String("au revoir"));
+ QCOMPARE(object->property("basic3").toString(), QLatin1String("bonjour"));
QCOMPARE(object->property("disambiguation").toString(), QLatin1String("salut"));
QCOMPARE(object->property("disambiguation2").toString(), QString::fromUtf8("\xc3\xa0 plus tard"));
+ QCOMPARE(object->property("disambiguation3").toString(), QLatin1String("salut"));
QCOMPARE(object->property("noop").toString(), QLatin1String("bonjour"));
QCOMPARE(object->property("noop2").toString(), QLatin1String("au revoir"));
QCOMPARE(object->property("singular").toString(), QLatin1String("1 canard"));
+ QCOMPARE(object->property("singular2").toString(), QLatin1String("1 canard"));
QCOMPARE(object->property("plural").toString(), QLatin1String("2 canards"));
+ QCOMPARE(object->property("plural2").toString(), QLatin1String("2 canards"));
QCoreApplication::removeTranslator(&translator);
delete object;
QCOMPARE(object->property("idTranslation").toString(), QLatin1String("bonjour tout le monde"));
QCOMPARE(object->property("idTranslation2").toString(), QLatin1String("bonjour tout le monde"));
+ QCOMPARE(object->property("idTranslation3").toString(), QLatin1String("bonjour tout le monde"));
QCoreApplication::removeTranslator(&translator);
delete object;
QCOMPARE(object->property("basic").toString(), QLatin1String("bonjour"));
QCOMPARE(object->property("basic2").toString(), QLatin1String("au revoir"));
+ QCOMPARE(object->property("basic3").toString(), QLatin1String("bonjour"));
QCOMPARE(object->property("disambiguation").toString(), QLatin1String("salut"));
QCOMPARE(object->property("disambiguation2").toString(), QString::fromUtf8("\xc3\xa0 plus tard"));
+ QCOMPARE(object->property("disambiguation3").toString(), QLatin1String("salut"));
QCOMPARE(object->property("noop").toString(), QLatin1String("bonjour"));
QCOMPARE(object->property("noop2").toString(), QLatin1String("au revoir"));
QCOMPARE(object->property("singular").toString(), QLatin1String("1 canard"));
+ QCOMPARE(object->property("singular2").toString(), QLatin1String("1 canard"));
QCOMPARE(object->property("plural").toString(), QLatin1String("2 canards"));
+ QCOMPARE(object->property("plural2").toString(), QLatin1String("2 canards"));
QCoreApplication::removeTranslator(&translator);
delete object;