summaryrefslogtreecommitdiffstats
path: root/src/declarative/qml/qmlbasicscript.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative/qml/qmlbasicscript.cpp')
-rw-r--r--src/declarative/qml/qmlbasicscript.cpp760
1 files changed, 0 insertions, 760 deletions
diff --git a/src/declarative/qml/qmlbasicscript.cpp b/src/declarative/qml/qmlbasicscript.cpp
deleted file mode 100644
index 3d566c7..0000000
--- a/src/declarative/qml/qmlbasicscript.cpp
+++ /dev/null
@@ -1,760 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtDeclarative module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qmlbasicscript_p.h"
-
-#include "qmlengine_p.h"
-#include "qmlcontext_p.h"
-#include "qmlrefcount_p.h"
-#include "qmlglobal_p.h"
-
-#include <qfxperf_p_p.h>
-#include <qmljsast_p.h>
-#include <qmljsengine_p.h>
-
-#include <QColor>
-#include <QDebug>
-#include <QStack>
-
-QT_BEGIN_NAMESPACE
-
-DEFINE_BOOL_CONFIG_OPTION(qmlBasicScriptDump, QML_BASICSCRIPT_DUMP);
-
-using namespace QmlJS;
-
-struct ScriptInstruction {
- enum {
- LoadIdObject, // fetch
- FetchConstant, // constant
- FetchContextConstant, // constant
- FetchRootConstant, // constant
-
- Equals, // NA
-
- Int, // integer
- Bool, // boolean
- } type;
-
- union {
- struct {
- int idx;
- } fetch;
- struct {
- int value;
- } integer;
- struct {
- bool value;
- } boolean;
- struct {
- short idx;
- short notify;
- int type;
- } constant;
- };
-};
-
-class QmlBasicScriptPrivate
-{
-public:
- enum Flags { OwnData = 0x00000001 };
-
- int size;
- int stateSize;
- int instructionCount;
- int exprLen;
-
- ScriptInstruction *instructions() const { return (ScriptInstruction *)((char *)this + sizeof(QmlBasicScriptPrivate)); }
-
- const char *expr() const
- {
- return (const char *)(instructions() + instructionCount);
- }
-
- const char *data() const
- {
- return (const char *)(instructions() + instructionCount) + exprLen + 1;
- }
-
- static unsigned int alignRound(int s)
- {
- if (s % 4)
- s += 4 - (s % 4);
- return s;
- }
-};
-
-// anchors.left: (nop convert)(qobject)parent.(anchorline)right
-
-/*
- Property chains: a.b.c.d
- if else value selection statements: if(a) b else if(c) d else e
- trinary selection: a?b:c
- addition: a + b
- negation: a - a
- equality: ==
-*/
-static QVariant fetch_value(QObject *o, int idx, int type)
-{
- if (!o)
- return QVariant();
-
- switch(type) {
- case QVariant::String:
- {
- QString val;
- void *args[] = { &val, 0 };
- QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args);
- return QVariant(val);
- }
- break;
- case QVariant::UInt:
- {
- uint val;
- void *args[] = { &val, 0 };
- QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args);
- return QVariant(val);
- }
- break;
- case QVariant::Int:
- {
- int val;
- void *args[] = { &val, 0 };
- QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args);
- return QVariant(val);
- }
- break;
- case QMetaType::Float:
- {
- float val;
- void *args[] = { &val, 0 };
- QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args);
- return QVariant(val);
- }
- break;
- case QVariant::Double:
- {
- double val;
- void *args[] = { &val, 0 };
- QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args);
- return QVariant(val);
- }
- break;
- case QVariant::Color:
- {
- QColor val;
- void *args[] = { &val, 0 };
- QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args);
- return QVariant(val);
- }
- break;
- case QVariant::Bool:
- {
- bool val;
- void *args[] = { &val, 0 };
- QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args);
- return QVariant(val);
- }
- break;
- default:
- {
- // If the object is null, we extract the predicted type. While this isn't
- // 100% reliable, in many cases it gives us better error messages if we
- // assign this null-object to an incompatible property
- if (QmlMetaType::isObject(type)) {
- // NOTE: This assumes a cast to QObject does not alter the
- // object pointer
- QObject *val = 0;
- void *args[] = { &val, 0 };
- QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args);
- if (!val) return QVariant(type, &val);
- else return QVariant::fromValue(val);
- } else {
- QVariant var = o->metaObject()->property(idx).read(o);
- if (QmlMetaType::isObject(var.userType())) {
- QObject *obj = 0;
- obj = *(QObject **)var.data();
- if (!obj) var = QVariant(var.userType(), &obj);
- else var = QVariant::fromValue(obj);
- }
- return var;
- }
- }
- break;
- };
-}
-
-struct QmlBasicScriptCompiler
-{
- QmlBasicScriptCompiler()
- : script(0), stateSize(0) {}
-
- QmlBasicScript *script;
- int stateSize;
-
- QmlParser::Object *context;
- QmlParser::Object *component;
- QHash<QString, QmlParser::Object *> ids;
-
- bool compile(QmlJS::AST::Node *);
-
- bool compileExpression(QmlJS::AST::Node *);
-
- bool tryConstant(QmlJS::AST::Node *);
- bool parseConstant(QmlJS::AST::Node *);
- bool tryName(QmlJS::AST::Node *);
- bool parseName(QmlJS::AST::Node *);
-
- bool buildName(QStringList &, QmlJS::AST::Node *);
- const QMetaObject *fetch(int type, const QMetaObject *, int idx);
-
- bool tryBinaryExpression(QmlJS::AST::Node *);
- bool compileBinaryExpression(QmlJS::AST::Node *);
-
- QByteArray data;
- QList<ScriptInstruction> bytecode;
-};
-
-/*!
- \internal
- \class QmlBasicScript
- \brief The QmlBasicScript class provides a fast implementation of a limited subset of QmlJS bindings.
-
- QmlBasicScript instances are used to accelerate binding. Instead of using
- the slower, fully fledged QmlJS engine, many simple bindings can be
- evaluated using the QmlBasicScript engine.
-
- To see if the QmlBasicScript engine can handle a binding, call compile()
- and check the return value, or isValid() afterwards.
-
- To accelerate binding, QmlBasicScript can return a precompiled
- version of itself that can be saved for future use. Call compileData() to
- get an opaque pointer to the compiled state, and compileDataSize() for the
- size of this data in bytes. This data can be saved and passed to future
- instances of the QmlBasicScript constructor. The initial copy of compile
- data is owned by the QmlBindScript instance on which compile() was called.
-*/
-
-/*!
- Create a new QmlBasicScript instance.
-*/
-QmlBasicScript::QmlBasicScript()
-: flags(0), d(0), rc(0)
-{
-}
-
-/*!
- Load the QmlBasicScript instance with saved \a data.
-
- \a data \b must be data previously acquired from calling compileData() on a
- previously created QmlBasicScript instance. Any other data will almost
- certainly cause the QmlBasicScript engine to crash.
-
- \a data must continue to be valid throughout the QmlBasicScript instance
- life. It does not assume ownership of the memory.
-
- If \a owner is set, it is referenced on creation and dereferenced on
- destruction of this instance.
-*/
-
-void QmlBasicScript::load(const char *data, QmlRefCount *owner)
-{
- clear();
- d = (QmlBasicScriptPrivate *)data;
- rc = owner;
- if (rc) rc->addref();
-}
-
-/*!
- Return the text of the script expression.
- */
-QByteArray QmlBasicScript::expression() const
-{
- if (!d)
- return QByteArray();
- else
- return QByteArray(d->expr());
-}
-
-/*!
- Destroy the script instance.
-*/
-QmlBasicScript::~QmlBasicScript()
-{
- clear();
-}
-
-/*!
- Clear this script. The object will then be in its initial state, as though
- it were freshly constructed with default constructor.
-*/
-void QmlBasicScript::clear()
-{
- if (flags & QmlBasicScriptPrivate::OwnData)
- free(d);
- if (rc) rc->release();
- d = 0;
- rc = 0;
- flags = 0;
-}
-
-/*!
- Dump the script instructions to stderr for debugging.
- */
-void QmlBasicScript::dump()
-{
- if (!d)
- return;
-
- qWarning() << d->instructionCount << "instructions:";
- for (int ii = 0; ii < d->instructionCount; ++ii) {
- const ScriptInstruction &instr = d->instructions()[ii];
-
- switch(instr.type) {
- case ScriptInstruction::LoadIdObject:
- qWarning().nospace() << "LOAD_ID_OBJECT";
- break;
- case ScriptInstruction::FetchConstant:
- qWarning().nospace() << "FETCH_CONSTANT";
- break;
- case ScriptInstruction::FetchContextConstant:
- qWarning().nospace() << "FETCH_CONTEXT_CONSTANT";
- break;
- case ScriptInstruction::FetchRootConstant:
- qWarning().nospace() << "FETCH_ROOT_CONSTANT";
- break;
- case ScriptInstruction::Equals:
- qWarning().nospace() << "EQUALS";
- break;
- case ScriptInstruction::Int:
- qWarning().nospace() << "INT\t\t" << instr.integer.value;
- break;
- case ScriptInstruction::Bool:
- qWarning().nospace() << "BOOL\t\t" << instr.boolean.value;
- break;
- default:
- qWarning().nospace() << "UNKNOWN";
- break;
- }
- }
-}
-
-/*!
- Return true if this is a valid script binding, otherwise returns false.
- */
-bool QmlBasicScript::isValid() const
-{
- return d != 0;
-}
-
-bool QmlBasicScript::compile(const Expression &expression)
-{
- if (!expression.expression.asAST()) return false;
-
- QByteArray expr = expression.expression.asScript().toUtf8();
- const char *src = expr.constData();
-
- QmlBasicScriptCompiler bsc;
- bsc.script = this;
- bsc.context = expression.context;
- bsc.component = expression.component;
- bsc.ids = expression.ids;
-
- if (d) {
- if (flags & QmlBasicScriptPrivate::OwnData)
- free(d);
- d = 0;
- flags = 0;
- }
-
- if (bsc.compile(expression.expression.asAST())) {
- int len = ::strlen(src);
- flags = QmlBasicScriptPrivate::OwnData;
- int size = sizeof(QmlBasicScriptPrivate) +
- bsc.bytecode.count() * sizeof(ScriptInstruction) +
- QmlBasicScriptPrivate::alignRound(bsc.data.count() + len + 1);
- d = (QmlBasicScriptPrivate *) malloc(size);
- d->size = size;
- d->stateSize = bsc.stateSize;
- d->instructionCount = bsc.bytecode.count();
- d->exprLen = len;
- ::memcpy((char *)d->expr(), src, len + 1);
- for (int ii = 0; ii < d->instructionCount; ++ii)
- d->instructions()[ii] = bsc.bytecode.at(ii);
- ::memcpy((char *)d->data(), bsc.data.constData(), bsc.data.count());
- }
-
- if (d && qmlBasicScriptDump())
- dump();
- return d != 0;
-}
-
-bool QmlBasicScriptCompiler::compile(QmlJS::AST::Node *node)
-{
- return compileExpression(node);
-}
-
-bool QmlBasicScriptCompiler::tryConstant(QmlJS::AST::Node *node)
-{
- if (node->kind == AST::Node::Kind_TrueLiteral ||
- node->kind == AST::Node::Kind_FalseLiteral)
- return true;
-
- if (node->kind == AST::Node::Kind_NumericLiteral) {
- AST::NumericLiteral *lit = static_cast<AST::NumericLiteral *>(node);
-
- return double(int(lit->value)) == lit->value;
- }
-
- return false;
-}
-
-bool QmlBasicScriptCompiler::parseConstant(QmlJS::AST::Node *node)
-{
- ScriptInstruction instr;
-
- if (node->kind == AST::Node::Kind_NumericLiteral) {
- AST::NumericLiteral *lit = static_cast<AST::NumericLiteral *>(node);
- instr.type = ScriptInstruction::Int;
- instr.integer.value = int(lit->value);
- } else {
- instr.type = ScriptInstruction::Bool;
- instr.boolean.value = node->kind == AST::Node::Kind_TrueLiteral;
- }
-
- bytecode.append(instr);
-
- return true;
-}
-
-bool QmlBasicScriptCompiler::tryName(QmlJS::AST::Node *node)
-{
- return node->kind == AST::Node::Kind_IdentifierExpression ||
- node->kind == AST::Node::Kind_FieldMemberExpression;
-}
-
-bool QmlBasicScriptCompiler::buildName(QStringList &name,
- QmlJS::AST::Node *node)
-{
- if (node->kind == AST::Node::Kind_IdentifierExpression) {
- name << static_cast<AST::IdentifierExpression*>(node)->name->asString();
- } else if (node->kind == AST::Node::Kind_FieldMemberExpression) {
- AST::FieldMemberExpression *expr =
- static_cast<AST::FieldMemberExpression *>(node);
-
- if (!buildName(name, expr->base))
- return false;
-
- name << expr->name->asString();
- } else {
- return false;
- }
-
- return true;
-}
-
-const QMetaObject *
-QmlBasicScriptCompiler::fetch(int type, const QMetaObject *mo, int idx)
-{
- ScriptInstruction instr;
- *((int*)&instr.type) = type;
- instr.constant.idx = idx;
- QMetaProperty prop = mo->property(idx);
- if (prop.isConstant())
- instr.constant.notify = 0;
- else
- instr.constant.notify = prop.notifySignalIndex();
- instr.constant.type = prop.userType();
- bytecode << instr;
- return QmlMetaType::metaObjectForType(prop.userType());
-}
-
-bool QmlBasicScriptCompiler::parseName(AST::Node *node)
-{
- QStringList nameParts;
- if (!buildName(nameParts, node))
- return false;
-
- QmlParser::Object *absType = 0;
- const QMetaObject *metaType = 0;
-
- for (int ii = 0; ii < nameParts.count(); ++ii) {
- const QString &name = nameParts.at(ii);
-
- // We don't handle signal properties
- if (name.length() > 2 && name.startsWith(QLatin1String("on")) &&
- name.at(2).isUpper())
- return false;
-
- if (ii == 0) {
-
- if (0) {
- // ### - Must test for an attached type name
- } else if (ids.contains(name)) {
- ScriptInstruction instr;
- instr.type = ScriptInstruction::LoadIdObject;
- instr.fetch.idx = ids.value(name)->idIndex;
- bytecode << instr;
- absType = ids.value(name);
- } else if(name.at(0).isLower()) {
-
- QByteArray utf8Name = name.toUtf8();
- const char *cname = utf8Name.constData();
-
- int d0Idx = context->metaObject()->indexOfProperty(cname);
- int d1Idx = -1;
- if (d0Idx == -1)
- d1Idx = component->metaObject()->indexOfProperty(cname);
-
- if (d0Idx != -1) {
- metaType = fetch(ScriptInstruction::FetchContextConstant,
- context->metaObject(), d0Idx);
- } else if(d1Idx != -1) {
- metaType = fetch(ScriptInstruction::FetchRootConstant,
- component->metaObject(), d1Idx);
- } else {
- return false;
- }
-
- } else {
- return false;
- }
- } else {
-
- if (!name.at(0).isLower())
- return false;
-
- const QMetaObject *mo = 0;
- if (absType)
- mo = absType->metaObject();
- else if(metaType)
- mo = metaType;
- else
- return false;
-
- QByteArray utf8Name = name.toUtf8();
- const char *cname = utf8Name.constData();
- int idx = mo->indexOfProperty(cname);
- if (idx == -1)
- return false;
-
- if (absType || mo->property(idx).isFinal()) {
- absType = 0; metaType = 0;
- metaType = fetch(ScriptInstruction::FetchConstant, mo, idx);
- } else {
- return false;
- }
-
- }
- }
-
- return true;
-}
-
-bool QmlBasicScriptCompiler::compileExpression(QmlJS::AST::Node *node)
-{
- if (tryBinaryExpression(node))
- return compileBinaryExpression(node);
- else if (tryConstant(node))
- return parseConstant(node);
- else if (tryName(node))
- return parseName(node);
- else
- return false;
-}
-
-bool QmlBasicScriptCompiler::tryBinaryExpression(AST::Node *node)
-{
- if (node->kind == AST::Node::Kind_BinaryExpression) {
- AST::BinaryExpression *expr =
- static_cast<AST::BinaryExpression *>(node);
-
- if (expr->op == QSOperator::Equal)
- return true;
- }
- return false;
-}
-
-bool QmlBasicScriptCompiler::compileBinaryExpression(AST::Node *node)
-{
- if (node->kind == AST::Node::Kind_BinaryExpression) {
- AST::BinaryExpression *expr =
- static_cast<AST::BinaryExpression *>(node);
-
- if (!compileExpression(expr->left)) return false;
- if (!compileExpression(expr->right)) return false;
-
- ScriptInstruction instr;
- switch (expr->op) {
- case QSOperator::Equal:
- instr.type = ScriptInstruction::Equals;
- break;
- default:
- return false;
- }
-
- bytecode.append(instr);
- return true;
- }
- return false;
-}
-
-/*!
- Run the script in \a context and return the result.
- */
-QVariant QmlBasicScript::run(QmlContext *context, QObject *me)
-{
- if (!isValid())
- return QVariant();
-
- QmlContextPrivate *contextPrivate = context->d_func();
- QmlEnginePrivate *enginePrivate = QmlEnginePrivate::get(context->engine());
-
- QStack<QVariant> stack;
-
- for (int idx = 0; idx < d->instructionCount; ++idx) {
- const ScriptInstruction &instr = d->instructions()[idx];
-
- switch(instr.type) {
- case ScriptInstruction::LoadIdObject:
- {
- stack.push(QVariant::fromValue(contextPrivate->idValues[instr.fetch.idx].data()));
- enginePrivate->capturedProperties <<
- QmlEnginePrivate::CapturedProperty(context, -1, contextPrivate->notifyIndex + instr.fetch.idx);
- }
- break;
-
- case ScriptInstruction::FetchContextConstant:
- {
- stack.push(fetch_value(me, instr.constant.idx, instr.constant.type));
- if (me && instr.constant.notify != 0)
- enginePrivate->capturedProperties <<
- QmlEnginePrivate::CapturedProperty(me, instr.constant.idx, instr.constant.notify);
- }
- break;
-
- case ScriptInstruction::FetchRootConstant:
- {
- QObject *obj = contextPrivate->defaultObjects.at(0);
-
- stack.push(fetch_value(obj, instr.constant.idx, instr.constant.type));
- if (obj && instr.constant.notify != 0)
- enginePrivate->capturedProperties <<
- QmlEnginePrivate::CapturedProperty(obj, instr.constant.idx, instr.constant.notify);
- }
- break;
-
- case ScriptInstruction::FetchConstant:
- {
- QVariant o = stack.pop();
- QObject *obj = *(QObject **)o.constData();
-
- stack.push(fetch_value(obj, instr.constant.idx, instr.constant.type));
- if (obj && instr.constant.notify != 0)
- enginePrivate->capturedProperties <<
- QmlEnginePrivate::CapturedProperty(obj, instr.constant.idx, instr.constant.notify);
- }
- break;
-
- case ScriptInstruction::Int:
- stack.push(QVariant(instr.integer.value));
- break;
-
- case ScriptInstruction::Bool:
- stack.push(QVariant(instr.boolean.value));
- break;
-
- case ScriptInstruction::Equals:
- {
- QVariant rhs = stack.pop();
- QVariant lhs = stack.pop();
-
- stack.push(rhs == lhs);
- }
- break;
- default:
- break;
- }
- }
-
- if (stack.isEmpty())
- return QVariant();
- else
- return stack.top();
-}
-
-bool QmlBasicScript::isSingleIdFetch() const
-{
- if (!isValid())
- return false;
-
- return d->instructionCount == 1 &&
- d->instructions()[0].type == ScriptInstruction::LoadIdObject;
-}
-
-int QmlBasicScript::singleIdFetchIndex() const
-{
- if (!isSingleIdFetch())
- return -1;
-
- return d->instructions()[0].fetch.idx;
-}
-
-/*!
- Return a pointer to the script's compile data, or null if there is no data.
- */
-const char *QmlBasicScript::compileData() const
-{
- return (const char *)d;
-}
-
-/*!
- Return the size of the script's compile data, or zero if there is no data.
- The size will always be a multiple of 4.
- */
-unsigned int QmlBasicScript::compileDataSize() const
-{
- if (d)
- return d->size;
- else
- return 0;
-}
-
-QT_END_NAMESPACE