Implemented the binding phase for QML.

Done-with: Christian Kamm
This commit is contained in:
Erik Verbruggen
2010-01-26 14:50:52 +01:00
parent 5d272795cf
commit cf35a0249b
8 changed files with 515 additions and 262 deletions

View File

@@ -22,7 +22,8 @@ HEADERS += \
$$PWD/qmljsscanner.h \
$$PWD/qmljssymbol.h \
$$PWD/qmljstypesystem.h \
$$PWD/qmljsinterpreter.h
$$PWD/qmljsinterpreter.h \
$$PWD/qmljsmetatypesystem.h
SOURCES += \
$$PWD/qmljsbind.cpp \
@@ -34,7 +35,8 @@ SOURCES += \
$$PWD/qmljsscanner.cpp \
$$PWD/qmljssymbol.cpp \
$$PWD/qmljstypesystem.cpp \
$$PWD/qmljsinterpreter.cpp
$$PWD/qmljsinterpreter.cpp \
$$PWD/qmljsmetatypesystem.cpp
contains(QT_CONFIG, declarative) {
QT += declarative

View File

@@ -27,10 +27,13 @@
**
**************************************************************************/
#include "qmljsbind.h"
#include "parser/qmljsast_p.h"
#include "qmljsbind.h"
#include "qmljsmetatypesystem.h"
using namespace QmlJS;
using namespace QmlJS::AST;
using namespace QmlJS::Interpreter;
Bind::Bind()
{
@@ -40,462 +43,629 @@ Bind::~Bind()
{
}
void Bind::operator()(Document::Ptr doc)
Interpreter::ObjectValue *Bind::operator()(Document::Ptr doc, Snapshot &snapshot, UiObjectMember *member, Interpreter::Engine &interp)
{
UiProgram *program = doc->qmlProgram();
if (!program)
return 0;
_doc = doc;
_snapshot = &snapshot;
_interestingMember = member;
_interp = &interp;
_currentObjectValue = 0;
_typeEnvironment = _interp->newObject(0);
_idEnvironment = _interp->newObject(0);
_interestingObjectValue = 0;
_rootObjectValue = 0;
accept(program);
if (_interestingObjectValue) {
_idEnvironment->setScope(_interestingObjectValue);
if (_interestingObjectValue != _rootObjectValue)
_interestingObjectValue->setScope(_rootObjectValue);
} else {
_idEnvironment->setScope(_rootObjectValue);
}
_typeEnvironment->setScope(_idEnvironment);
return _typeEnvironment;
}
void Bind::accept(AST::Node *node)
void Bind::accept(Node *node)
{
AST::Node::accept(node, this);
Node::accept(node, this);
}
bool Bind::visit(AST::UiProgram *)
bool Bind::visit(UiProgram *)
{
return true;
}
bool Bind::visit(AST::UiImportList *)
bool Bind::visit(UiImportList *)
{
return true;
}
bool Bind::visit(AST::UiImport *)
static QString serialize(UiQualifiedId *qualifiedId, QChar delimiter)
{
return true;
QString result;
for (UiQualifiedId *iter = qualifiedId; iter; iter = iter->next) {
if (iter != qualifiedId)
result += delimiter;
if (iter->name)
result += iter->name->asString();
}
return result;
}
bool Bind::visit(AST::UiPublicMember *)
/*
import Qt 4.6
import Qt 4.6 as Xxx
(import com.nokia.qt is the same as the ones above)
import "content"
import "content" as Xxx
import "content" 4.6
import "content" 4.6 as Xxx
import "http://www.ovi.com/" as Ovi
*/
bool Bind::visit(UiImport *ast)
{
return true;
ObjectValue *namespaceObject;
if (ast->asToken.isValid()) { // with namespace we insert an object in the type env. to hold the imported types
namespaceObject = _interp->newObject(0);
if (!ast->importId)
return false; // this should never happen, but better be safe than sorry
_typeEnvironment->setProperty(ast->importId->asString(), namespaceObject);
} else { // without namespace we insert all types directly into the type env.
namespaceObject = _typeEnvironment;
}
// look at files first
// else try the metaobject system
if (!ast->importUri)
return false;
const QString package = serialize(ast->importUri, '/');
int majorVersion = -1; // ### TODO: Check these magic version numbers
int minorVersion = -1; // ### TODO: Check these magic version numbers
if (ast->versionToken.isValid()) {
const QString versionString = _doc->source().mid(ast->versionToken.offset, ast->versionToken.length);
int dotIdx = versionString.indexOf('.');
if (dotIdx == -1) {
// only major (which is probably invalid, but let's handle it anyway)
majorVersion = versionString.toInt();
minorVersion = 0; // ### TODO: Check with magic version numbers above
} else {
majorVersion = versionString.left(dotIdx).toInt();
minorVersion = versionString.mid(dotIdx + 1).toInt();
}
}
#ifndef NO_DECLARATIVE_BACKEND
foreach (QmlObjectValue *object, _interp->metaTypeSystem().staticTypesForImport(package, majorVersion, minorVersion)) {
namespaceObject->setProperty(object->qmlTypeName(), object);
}
#endif // NO_DECLARATIVE_BACKEND
return false;
}
bool Bind::visit(AST::UiSourceElement *)
bool Bind::visit(UiPublicMember *ast)
{
return true;
if (! (ast->name && ast->memberType))
return false;
const QString propName = ast->name->asString();
const QString propType = ast->memberType->asString();
// ### TODO: generalize
if (propType == QLatin1String("string"))
_currentObjectValue->setProperty(propName, _interp->stringValue());
else if (propType == QLatin1String("bool"))
_currentObjectValue->setProperty(propName, _interp->booleanValue());
else if (propType == QLatin1String("int") || propType == QLatin1String("real"))
_currentObjectValue->setProperty(propName, _interp->numberValue());
return false;
}
bool Bind::visit(AST::UiObjectDefinition *)
bool Bind::visit(UiSourceElement *)
{
return true;
}
bool Bind::visit(AST::UiObjectInitializer *)
const ObjectValue *Bind::lookupType(UiQualifiedId *qualifiedTypeNameId)
{
return true;
const ObjectValue *objectValue = _typeEnvironment;
for (UiQualifiedId *iter = qualifiedTypeNameId; iter; iter = iter->next) {
if (! (iter->name))
return 0;
const Value *value = objectValue->property(iter->name->asString());
if (!value)
return 0;
objectValue = value->asObjectValue();
if (!objectValue)
return 0;
}
return objectValue;
}
bool Bind::visit(AST::UiObjectBinding *)
ObjectValue *Bind::bindObject(UiQualifiedId *qualifiedTypeNameId, UiObjectInitializer *initializer)
{
return true;
const ObjectValue *prototype = lookupType(qualifiedTypeNameId);
ObjectValue *objectValue = _interp->newObject(prototype);
ObjectValue *oldObjectValue = switchObjectValue(objectValue);
if (oldObjectValue)
objectValue->setProperty("parent", oldObjectValue);
else
_rootObjectValue = objectValue;
accept(initializer);
return switchObjectValue(oldObjectValue);
}
bool Bind::visit(UiObjectDefinition *ast)
{
ObjectValue *value = bindObject(ast->qualifiedTypeNameId, ast->initializer);
if (_interestingMember == ast)
_interestingObjectValue = value;
return false;
}
bool Bind::visit(UiObjectBinding *ast)
{
// const QString name = serialize(ast->qualifiedId);
ObjectValue *value = bindObject(ast->qualifiedTypeNameId, ast->initializer);
// ### FIXME: we don't handle dot-properties correctly (i.e. font.size)
// _currentObjectValue->setProperty(name, value);
if (_interestingMember == ast)
_interestingObjectValue = value;
return false;
}
bool Bind::visit(AST::UiScriptBinding *)
bool Bind::visit(UiObjectInitializer *)
{
return true;
}
bool Bind::visit(AST::UiArrayBinding *)
bool Bind::visit(UiScriptBinding *ast)
{
if (!(ast->qualifiedId->next) && ast->qualifiedId->name->asString() == "id")
if (ExpressionStatement *e = cast<ExpressionStatement*>(ast->statement))
if (IdentifierExpression *i = cast<IdentifierExpression*>(e->expression))
if (i->name)
_idEnvironment->setProperty(i->name->asString(), _currentObjectValue);
return false;
}
bool Bind::visit(UiArrayBinding *)
{
// ### FIXME: do we need to store the members into the property? Or, maybe the property type is an JS Array?
return true;
}
bool Bind::visit(AST::UiObjectMemberList *)
bool Bind::visit(UiObjectMemberList *)
{
return true;
}
bool Bind::visit(AST::UiArrayMemberList *)
bool Bind::visit(UiArrayMemberList *)
{
return true;
}
bool Bind::visit(AST::UiQualifiedId *)
bool Bind::visit(UiQualifiedId *)
{
return true;
}
bool Bind::visit(AST::UiSignature *)
bool Bind::visit(UiSignature *)
{
return true;
}
bool Bind::visit(AST::UiFormalList *)
bool Bind::visit(UiFormalList *)
{
return true;
}
bool Bind::visit(AST::UiFormal *)
bool Bind::visit(UiFormal *)
{
return true;
}
bool Bind::visit(AST::ThisExpression *)
bool Bind::visit(ThisExpression *)
{
return true;
}
bool Bind::visit(AST::IdentifierExpression *)
bool Bind::visit(IdentifierExpression *)
{
return true;
}
bool Bind::visit(AST::NullExpression *)
bool Bind::visit(NullExpression *)
{
return true;
}
bool Bind::visit(AST::TrueLiteral *)
bool Bind::visit(TrueLiteral *)
{
return true;
}
bool Bind::visit(AST::FalseLiteral *)
bool Bind::visit(FalseLiteral *)
{
return true;
}
bool Bind::visit(AST::StringLiteral *)
bool Bind::visit(StringLiteral *)
{
return true;
}
bool Bind::visit(AST::NumericLiteral *)
bool Bind::visit(NumericLiteral *)
{
return true;
}
bool Bind::visit(AST::RegExpLiteral *)
bool Bind::visit(RegExpLiteral *)
{
return true;
}
bool Bind::visit(AST::ArrayLiteral *)
bool Bind::visit(ArrayLiteral *)
{
return true;
}
bool Bind::visit(AST::ObjectLiteral *)
bool Bind::visit(ObjectLiteral *)
{
return true;
}
bool Bind::visit(AST::ElementList *)
bool Bind::visit(ElementList *)
{
return true;
}
bool Bind::visit(AST::Elision *)
bool Bind::visit(Elision *)
{
return true;
}
bool Bind::visit(AST::PropertyNameAndValueList *)
bool Bind::visit(PropertyNameAndValueList *)
{
return true;
}
bool Bind::visit(AST::NestedExpression *)
bool Bind::visit(NestedExpression *)
{
return true;
}
bool Bind::visit(AST::IdentifierPropertyName *)
bool Bind::visit(IdentifierPropertyName *)
{
return true;
}
bool Bind::visit(AST::StringLiteralPropertyName *)
bool Bind::visit(StringLiteralPropertyName *)
{
return true;
}
bool Bind::visit(AST::NumericLiteralPropertyName *)
bool Bind::visit(NumericLiteralPropertyName *)
{
return true;
}
bool Bind::visit(AST::ArrayMemberExpression *)
bool Bind::visit(ArrayMemberExpression *)
{
return true;
}
bool Bind::visit(AST::FieldMemberExpression *)
bool Bind::visit(FieldMemberExpression *)
{
return true;
}
bool Bind::visit(AST::NewMemberExpression *)
bool Bind::visit(NewMemberExpression *)
{
return true;
}
bool Bind::visit(AST::NewExpression *)
bool Bind::visit(NewExpression *)
{
return true;
}
bool Bind::visit(AST::CallExpression *)
bool Bind::visit(CallExpression *)
{
return true;
}
bool Bind::visit(AST::ArgumentList *)
bool Bind::visit(ArgumentList *)
{
return true;
}
bool Bind::visit(AST::PostIncrementExpression *)
bool Bind::visit(PostIncrementExpression *)
{
return true;
}
bool Bind::visit(AST::PostDecrementExpression *)
bool Bind::visit(PostDecrementExpression *)
{
return true;
}
bool Bind::visit(AST::DeleteExpression *)
bool Bind::visit(DeleteExpression *)
{
return true;
}
bool Bind::visit(AST::VoidExpression *)
bool Bind::visit(VoidExpression *)
{
return true;
}
bool Bind::visit(AST::TypeOfExpression *)
bool Bind::visit(TypeOfExpression *)
{
return true;
}
bool Bind::visit(AST::PreIncrementExpression *)
bool Bind::visit(PreIncrementExpression *)
{
return true;
}
bool Bind::visit(AST::PreDecrementExpression *)
bool Bind::visit(PreDecrementExpression *)
{
return true;
}
bool Bind::visit(AST::UnaryPlusExpression *)
bool Bind::visit(UnaryPlusExpression *)
{
return true;
}
bool Bind::visit(AST::UnaryMinusExpression *)
bool Bind::visit(UnaryMinusExpression *)
{
return true;
}
bool Bind::visit(AST::TildeExpression *)
bool Bind::visit(TildeExpression *)
{
return true;
}
bool Bind::visit(AST::NotExpression *)
bool Bind::visit(NotExpression *)
{
return true;
}
bool Bind::visit(AST::BinaryExpression *)
bool Bind::visit(BinaryExpression *)
{
return true;
}
bool Bind::visit(AST::ConditionalExpression *)
bool Bind::visit(ConditionalExpression *)
{
return true;
}
bool Bind::visit(AST::Expression *)
bool Bind::visit(Expression *)
{
return true;
}
bool Bind::visit(AST::Block *)
bool Bind::visit(Block *)
{
return true;
}
bool Bind::visit(AST::StatementList *)
bool Bind::visit(StatementList *)
{
return true;
}
bool Bind::visit(AST::VariableStatement *)
bool Bind::visit(VariableStatement *)
{
return true;
}
bool Bind::visit(AST::VariableDeclarationList *)
bool Bind::visit(VariableDeclarationList *)
{
return true;
}
bool Bind::visit(AST::VariableDeclaration *)
bool Bind::visit(VariableDeclaration *)
{
return true;
}
bool Bind::visit(AST::EmptyStatement *)
bool Bind::visit(EmptyStatement *)
{
return true;
}
bool Bind::visit(AST::ExpressionStatement *)
bool Bind::visit(ExpressionStatement *)
{
return true;
}
bool Bind::visit(AST::IfStatement *)
bool Bind::visit(IfStatement *)
{
return true;
}
bool Bind::visit(AST::DoWhileStatement *)
bool Bind::visit(DoWhileStatement *)
{
return true;
}
bool Bind::visit(AST::WhileStatement *)
bool Bind::visit(WhileStatement *)
{
return true;
}
bool Bind::visit(AST::ForStatement *)
bool Bind::visit(ForStatement *)
{
return true;
}
bool Bind::visit(AST::LocalForStatement *)
bool Bind::visit(LocalForStatement *)
{
return true;
}
bool Bind::visit(AST::ForEachStatement *)
bool Bind::visit(ForEachStatement *)
{
return true;
}
bool Bind::visit(AST::LocalForEachStatement *)
bool Bind::visit(LocalForEachStatement *)
{
return true;
}
bool Bind::visit(AST::ContinueStatement *)
bool Bind::visit(ContinueStatement *)
{
return true;
}
bool Bind::visit(AST::BreakStatement *)
bool Bind::visit(BreakStatement *)
{
return true;
}
bool Bind::visit(AST::ReturnStatement *)
bool Bind::visit(ReturnStatement *)
{
return true;
}
bool Bind::visit(AST::WithStatement *)
bool Bind::visit(WithStatement *)
{
return true;
}
bool Bind::visit(AST::SwitchStatement *)
bool Bind::visit(SwitchStatement *)
{
return true;
}
bool Bind::visit(AST::CaseBlock *)
bool Bind::visit(CaseBlock *)
{
return true;
}
bool Bind::visit(AST::CaseClauses *)
bool Bind::visit(CaseClauses *)
{
return true;
}
bool Bind::visit(AST::CaseClause *)
bool Bind::visit(CaseClause *)
{
return true;
}
bool Bind::visit(AST::DefaultClause *)
bool Bind::visit(DefaultClause *)
{
return true;
}
bool Bind::visit(AST::LabelledStatement *)
bool Bind::visit(LabelledStatement *)
{
return true;
}
bool Bind::visit(AST::ThrowStatement *)
bool Bind::visit(ThrowStatement *)
{
return true;
}
bool Bind::visit(AST::TryStatement *)
bool Bind::visit(TryStatement *)
{
return true;
}
bool Bind::visit(AST::Catch *)
bool Bind::visit(Catch *)
{
return true;
}
bool Bind::visit(AST::Finally *)
bool Bind::visit(Finally *)
{
return true;
}
bool Bind::visit(AST::FunctionDeclaration *)
bool Bind::visit(FunctionDeclaration *)
{
return true;
}
bool Bind::visit(AST::FunctionExpression *)
bool Bind::visit(FunctionExpression *)
{
return true;
}
bool Bind::visit(AST::FormalParameterList *)
bool Bind::visit(FormalParameterList *)
{
return true;
}
bool Bind::visit(AST::FunctionBody *)
bool Bind::visit(FunctionBody *)
{
return true;
}
bool Bind::visit(AST::Program *)
bool Bind::visit(Program *)
{
return true;
}
bool Bind::visit(AST::SourceElements *)
bool Bind::visit(SourceElements *)
{
return true;
}
bool Bind::visit(AST::FunctionSourceElement *)
bool Bind::visit(FunctionSourceElement *)
{
return true;
}
bool Bind::visit(AST::StatementSourceElement *)
bool Bind::visit(StatementSourceElement *)
{
return true;
}
bool Bind::visit(AST::DebuggerStatement *)
bool Bind::visit(DebuggerStatement *)
{
return true;
}
ObjectValue *Bind::switchObjectValue(ObjectValue *newObjectValue)
{
ObjectValue *oldObjectValue = _currentObjectValue;
_currentObjectValue = newObjectValue;
return oldObjectValue;
}

View File

@@ -30,8 +30,9 @@
#ifndef QMLBIND_H
#define QMLBIND_H
#include "parser/qmljsastvisitor_p.h"
#include "qmljsdocument.h"
#include <qmljs/parser/qmljsastvisitor_p.h>
#include <qmljs/qmljsdocument.h>
#include <qmljs/qmljsinterpreter.h>
namespace QmlJS {
@@ -41,7 +42,7 @@ public:
Bind();
virtual ~Bind();
void operator()(QmlJS::Document::Ptr doc);
Interpreter::ObjectValue* operator()(Document::Ptr doc, Snapshot &snapshot, AST::UiObjectMember *member, Interpreter::Engine &interp);
protected:
void accept(AST::Node *node);
@@ -140,8 +141,23 @@ protected:
virtual bool visit(AST::StatementSourceElement *ast);
virtual bool visit(AST::DebuggerStatement *ast);
protected:
Interpreter::ObjectValue *switchObjectValue(Interpreter::ObjectValue *newObjectValue);
const Interpreter::ObjectValue *lookupType(AST::UiQualifiedId *qualifiedTypeNameId);
Interpreter::ObjectValue *bindObject(AST::UiQualifiedId *qualifiedTypeNameId, AST::UiObjectInitializer *initializer);
private:
QmlJS::Document::Ptr _doc;
Document::Ptr _doc;
Snapshot *_snapshot;
AST::UiObjectMember *_interestingMember;
Interpreter::Engine *_interp;
Interpreter::ObjectValue *_currentObjectValue;
Interpreter::ObjectValue *_typeEnvironment;
Interpreter::ObjectValue *_idEnvironment;
Interpreter::ObjectValue *_interestingObjectValue;
Interpreter::ObjectValue *_rootObjectValue;
};
} // end of namespace Qml

View File

@@ -225,6 +225,8 @@ void Snapshot::insert(const Document::Ptr &document)
Document::PtrList Snapshot::importedDocuments(const Document::Ptr &doc, const QString &importPath) const
{
// ### TODO: maybe we should add all imported documents in the parse Document::parse() method, regardless of whether they're in the path or not.
Document::PtrList result;
const QString docPath = doc->path() + '/' + importPath;

View File

@@ -43,8 +43,6 @@
using namespace QmlJS::Interpreter;
namespace {
#ifndef NO_DECLARATIVE_BACKEND
class QmlAttachedKeys: public ObjectValue
@@ -166,93 +164,102 @@ public:
}
};
class QmlObjectValue: public ObjectValue
QmlObjectValue::QmlObjectValue(const QMetaObject *metaObject, const QString &qmlTypeName, int majorVersion, int minorVersion, Engine *engine)
: ObjectValue(engine), _metaObject(metaObject), _qmlTypeName(qmlTypeName), _majorVersion(majorVersion), _minorVersion(minorVersion)
{}
QmlObjectValue::~QmlObjectValue() {}
const Value *QmlObjectValue::lookupMember(const QString &name) const
{
public:
QmlObjectValue(const QMetaObject *metaObject, Engine *engine)
: ObjectValue(engine), _metaObject(metaObject)
{
for (int index = 0; index < _metaObject->propertyCount(); ++index) {
QMetaProperty prop = _metaObject->property(index);
if (name == QString::fromUtf8(prop.name()))
return propertyValue(prop);
}
virtual ~QmlObjectValue() {}
for (int index = 0; index < _metaObject->methodCount(); ++index) {
QMetaMethod method = _metaObject->method(index);
virtual const Value *lookupMember(const QString &name) const
{
for (int index = 0; index < _metaObject->propertyCount(); ++index) {
QMetaProperty prop = _metaObject->property(index);
const QString signature = QString::fromUtf8(method.signature());
if (name == QString::fromUtf8(prop.name()))
return propertyValue(prop);
const int indexOfParen = signature.indexOf(QLatin1Char('('));
if (indexOfParen == -1)
continue; // skip it, invalid signature.
const QString methodName = signature.left(indexOfParen);
if (methodName != name) {
continue;
} else if (method.methodType() == QMetaMethod::Slot && method.access() == QMetaMethod::Public) {
return new MetaFunction(method, engine());
} else if (method.methodType() == QMetaMethod::Signal && method.access() != QMetaMethod::Private) {
return new MetaFunction(method, engine());
}
}
for (int index = 0; index < _metaObject->methodCount(); ++index) {
QMetaMethod method = _metaObject->method(index);
return ObjectValue::lookupMember(name);
}
const QString signature = QString::fromUtf8(method.signature());
void QmlObjectValue::processMembers(MemberProcessor *processor) const
{
for (int index = 0; index < _metaObject->propertyCount(); ++index) {
QMetaProperty prop = _metaObject->property(index);
const int indexOfParen = signature.indexOf(QLatin1Char('('));
if (indexOfParen == -1)
continue; // skip it, invalid signature.
processor->processProperty(prop.name(), propertyValue(prop));
}
const QString methodName = signature.left(indexOfParen);
for (int index = 0; index < _metaObject->methodCount(); ++index) {
QMetaMethod method = _metaObject->method(index);
if (methodName != name) {
continue;
const QString signature = QString::fromUtf8(method.signature());
} else if (method.methodType() == QMetaMethod::Slot && method.access() == QMetaMethod::Public) {
return new MetaFunction(method, engine());
const int indexOfParen = signature.indexOf(QLatin1Char('('));
if (indexOfParen == -1)
continue; // skip it, invalid signature.
} else if (method.methodType() == QMetaMethod::Signal && method.access() != QMetaMethod::Private) {
return new MetaFunction(method, engine());
const QString methodName = signature.left(indexOfParen);
if (method.methodType() == QMetaMethod::Slot && method.access() == QMetaMethod::Public) {
processor->processSlot(methodName, engine()->undefinedValue());
} else if (method.methodType() == QMetaMethod::Signal && method.access() != QMetaMethod::Private) {
// process the signal
processor->processSignal(methodName, engine()->undefinedValue());
QString slotName;
slotName += QLatin1String("on");
slotName += methodName.at(0).toUpper();
slotName += methodName.midRef(1);
// process the generated slot
processor->processGeneratedSlot(slotName, engine()->undefinedValue());
}
}
ObjectValue::processMembers(processor);
}
const Value *QmlObjectValue::propertyValue(const QMetaProperty &prop) const
{
if (QmlMetaType::isObject(prop.userType())) {
QmlType *qmlPropertyType = QmlMetaType::qmlType(QmlMetaType::metaObjectForType(prop.userType()));
if (qmlPropertyType && !qmlPropertyType->qmlTypeName().isEmpty()) {
QString typeName = qmlPropertyType->qmlTypeName();
int slashIdx = typeName.lastIndexOf(QLatin1Char('/'));
QString package;
if (slashIdx != -1) {
package = typeName.left(slashIdx);
typeName = typeName.mid(slashIdx + 1);
}
}
return ObjectValue::lookupMember(name);
}
virtual void processMembers(MemberProcessor *processor) const
{
for (int index = 0; index < _metaObject->propertyCount(); ++index) {
QMetaProperty prop = _metaObject->property(index);
processor->processProperty(prop.name(), propertyValue(prop));
}
for (int index = 0; index < _metaObject->methodCount(); ++index) {
QMetaMethod method = _metaObject->method(index);
const QString signature = QString::fromUtf8(method.signature());
const int indexOfParen = signature.indexOf(QLatin1Char('('));
if (indexOfParen == -1)
continue; // skip it, invalid signature.
const QString methodName = signature.left(indexOfParen);
if (method.methodType() == QMetaMethod::Slot && method.access() == QMetaMethod::Public) {
processor->processSlot(methodName, engine()->undefinedValue());
} else if (method.methodType() == QMetaMethod::Signal && method.access() != QMetaMethod::Private) {
// process the signal
processor->processSignal(methodName, engine()->undefinedValue());
QString slotName;
slotName += QLatin1String("on");
slotName += methodName.at(0).toUpper();
slotName += methodName.midRef(1);
// process the generated slot
processor->processGeneratedSlot(slotName, engine()->undefinedValue());
}
}
ObjectValue::processMembers(processor);
}
const Value *propertyValue(const QMetaProperty &prop) const {
const Value *value = engine()->undefinedValue();
if (QmlMetaType::isObject(prop.userType())) {
if (const ObjectValue *objectValue = engine()->newQmlObject(typeName, package, qmlPropertyType->majorVersion(), qmlPropertyType->minorVersion()))
return objectValue;
} else {
QString typeName = QString::fromUtf8(prop.typeName());
if (typeName.endsWith(QLatin1Char('*')))
@@ -260,78 +267,78 @@ public:
typeName.replace(QLatin1Char('.'), QLatin1Char('/'));
if (const ObjectValue *objectValue = engine()->newQmlObject(typeName))
if (const ObjectValue *objectValue = engine()->newQmlObject(typeName, "", -1, -1)) // ### we should extend this to lookup the property types in the QmlType object, instead of the QMetaProperty.
return objectValue;
}
switch (prop.type()) {
case QMetaType::QByteArray:
case QMetaType::QString:
case QMetaType::QUrl:
value = engine()->stringValue();
break;
case QMetaType::Bool:
value = engine()->booleanValue();
break;
case QMetaType::Int:
case QMetaType::Float:
case QMetaType::Double:
value = engine()->numberValue();
break;
case QMetaType::QFont: {
// ### cache
ObjectValue *object = engine()->newObject(/*prototype =*/ 0);
object->setProperty("family", engine()->stringValue());
object->setProperty("weight", engine()->undefinedValue()); // ### make me an object
object->setProperty("copitalization", engine()->undefinedValue()); // ### make me an object
object->setProperty("bold", engine()->booleanValue());
object->setProperty("italic", engine()->booleanValue());
object->setProperty("underline", engine()->booleanValue());
object->setProperty("overline", engine()->booleanValue());
object->setProperty("strikeout", engine()->booleanValue());
object->setProperty("pointSize", engine()->numberValue());
object->setProperty("pixelSize", engine()->numberValue());
object->setProperty("letterSpacing", engine()->numberValue());
object->setProperty("wordSpacing", engine()->numberValue());
value = object;
} break;
case QMetaType::QPoint:
case QMetaType::QPointF: {
// ### cache
ObjectValue *object = engine()->newObject(/*prototype =*/ 0);
object->setProperty("x", engine()->numberValue());
object->setProperty("y", engine()->numberValue());
value = object;
} break;
case QMetaType::QRect:
case QMetaType::QRectF: {
// ### cache
ObjectValue *object = engine()->newObject(/*prototype =*/ 0);
object->setProperty("x", engine()->numberValue());
object->setProperty("y", engine()->numberValue());
object->setProperty("width", engine()->numberValue());
object->setProperty("height", engine()->numberValue());
value = object;
} break;
default:
break;
} // end of switch
return value;
}
private:
const QMetaObject *_metaObject;
};
const Value *value = engine()->undefinedValue();
switch (prop.type()) {
case QMetaType::QByteArray:
case QMetaType::QString:
case QMetaType::QUrl:
value = engine()->stringValue();
break;
case QMetaType::Bool:
value = engine()->booleanValue();
break;
case QMetaType::Int:
case QMetaType::Float:
case QMetaType::Double:
value = engine()->numberValue();
break;
case QMetaType::QFont: {
// ### cache
ObjectValue *object = engine()->newObject(/*prototype =*/ 0);
object->setProperty("family", engine()->stringValue());
object->setProperty("weight", engine()->undefinedValue()); // ### make me an object
object->setProperty("copitalization", engine()->undefinedValue()); // ### make me an object
object->setProperty("bold", engine()->booleanValue());
object->setProperty("italic", engine()->booleanValue());
object->setProperty("underline", engine()->booleanValue());
object->setProperty("overline", engine()->booleanValue());
object->setProperty("strikeout", engine()->booleanValue());
object->setProperty("pointSize", engine()->numberValue());
object->setProperty("pixelSize", engine()->numberValue());
object->setProperty("letterSpacing", engine()->numberValue());
object->setProperty("wordSpacing", engine()->numberValue());
value = object;
} break;
case QMetaType::QPoint:
case QMetaType::QPointF: {
// ### cache
ObjectValue *object = engine()->newObject(/*prototype =*/ 0);
object->setProperty("x", engine()->numberValue());
object->setProperty("y", engine()->numberValue());
value = object;
} break;
case QMetaType::QRect:
case QMetaType::QRectF: {
// ### cache
ObjectValue *object = engine()->newObject(/*prototype =*/ 0);
object->setProperty("x", engine()->numberValue());
object->setProperty("y", engine()->numberValue());
object->setProperty("width", engine()->numberValue());
object->setProperty("height", engine()->numberValue());
value = object;
} break;
default:
break;
} // end of switch
return value;
}
#endif
namespace {
////////////////////////////////////////////////////////////////////////////////
// constructors
////////////////////////////////////////////////////////////////////////////////
@@ -1300,8 +1307,9 @@ Engine::Engine()
_convertToString(this),
_convertToObject(this)
{
initializePrototypes();
_metaTypeSystem.reload(this);
}
Engine::~Engine()
@@ -1780,19 +1788,19 @@ const Value *Engine::defaultValueForBuiltinType(const QString &typeName) const
return undefinedValue();
}
ObjectValue *Engine::newQmlObject(const QString &name)
{
#ifndef NO_DECLARATIVE_BACKEND
QmlObjectValue *Engine::newQmlObject(const QString &name, const QString &prefix, int majorVersion, int minorVersion)
{
if (name == QLatin1String("QmlGraphicsAnchors")) {
QmlObjectValue *object = new QmlObjectValue(&QmlGraphicsAnchors::staticMetaObject, this);
QmlObjectValue *object = new QmlObjectValue(&QmlGraphicsAnchors::staticMetaObject, QLatin1String("Anchors"), -1, -1, this);
_objects.append(object);
return object;
} else if (name == QLatin1String("QmlGraphicsPen")) {
QmlObjectValue *object = new QmlObjectValue(&QmlGraphicsPen::staticMetaObject, this);
QmlObjectValue *object = new QmlObjectValue(&QmlGraphicsPen::staticMetaObject, QLatin1String("Pen"), -1, -1, this);
_objects.append(object);
return object;
} else if (name == QLatin1String("QmlGraphicsScaleGrid")) {
ObjectValue *object = newObject(/*prototype =*/ 0);
QmlObjectValue *object = new QmlObjectValue(&QObject::staticMetaObject, QLatin1String("ScaleGrid"), -1, -1, this);
object->setProperty("left", numberValue());
object->setProperty("top", numberValue());
object->setProperty("right", numberValue());
@@ -1801,20 +1809,17 @@ ObjectValue *Engine::newQmlObject(const QString &name)
}
// ### TODO: add support for QML packages
QString componentName;
componentName += QLatin1String("Qt/");
componentName += name;
componentName.replace(QLatin1Char('.'), QLatin1Char('/'));
const QString componentName = prefix + QLatin1Char('/') + name;
if (QmlType *qmlType = QmlMetaType::qmlType(componentName.toUtf8(), 4, 6)) {
QmlObjectValue *object = new QmlObjectValue(qmlType->metaObject(), this);
if (QmlType *qmlType = QmlMetaType::qmlType(componentName.toUtf8(), majorVersion, minorVersion)) {
const QString typeName = qmlType->qmlTypeName();
const QString strippedTypeName = typeName.mid(typeName.lastIndexOf('/') + 1);
QmlObjectValue *object = new QmlObjectValue(qmlType->metaObject(), strippedTypeName, majorVersion, minorVersion, this);
_objects.append(object);
return object;
}
return 0;
#else
return newObject(/*prototype = */ 0);
#endif
}
#endif

View File

@@ -30,7 +30,8 @@
#ifndef QMLJS_INTERPRETER_H
#define QMLJS_INTERPRETER_H
#include "qmljs_global.h"
#include <qmljs/qmljs_global.h>
#include <qmljs/qmljsmetatypesystem.h>
#include <QtCore/QList>
#include <QtCore/QString>
@@ -250,6 +251,36 @@ private:
QString _className;
};
#ifndef NO_DECLARATIVE_BACKEND
class QmlObjectValue: public ObjectValue
{
public:
QmlObjectValue(const QMetaObject *metaObject, const QString &qmlTypeName, int majorVersion, int minorVersion, Engine *engine);
virtual ~QmlObjectValue();
virtual const Value *lookupMember(const QString &name) const;
virtual void processMembers(MemberProcessor *processor) const;
const Value *propertyValue(const QMetaProperty &prop) const;
QString qmlTypeName() const
{ return _qmlTypeName; }
int majorVersion() const
{ return _majorVersion; }
int minorVersion() const
{ return _minorVersion; }
private:
const QMetaObject *_metaObject;
QString _qmlTypeName;
int _majorVersion;
int _minorVersion;
};
#endif // !NO_DECLARATIVE_BACKEND
class QMLJS_EXPORT Activation: public ObjectValue
{
public:
@@ -440,9 +471,11 @@ public:
const Value *newArray(); // ### remove me
// QML objects
ObjectValue *newQmlObject(const QString &name);
const ObjectValue *qmlKeysObject();
const Value *defaultValueForBuiltinType(const QString &typeName) const;
#ifndef NO_DECLARATIVE_BACKEND
QmlObjectValue *newQmlObject(const QString &name, const QString &prefix, int majorVersion, int minorVersion);
#endif
// global object
ObjectValue *globalObject() const;
@@ -477,6 +510,11 @@ public:
const Value *convertToObject(const Value *value);
QString typeId(const Value *value);
// typing:
const MetaTypeSystem &metaTypeSystem() const
{ return _metaTypeSystem; }
private:
void initializePrototypes();
@@ -519,6 +557,8 @@ private:
ConvertToString _convertToString;
ConvertToObject _convertToObject;
TypeId _typeId;
MetaTypeSystem _metaTypeSystem;
};
} } // end of namespace QmlJS::Interpreter