Files
qt-creator/src/libs/qmljs/qmljsinterpreter.cpp

2384 lines
63 KiB
C++
Raw Normal View History

/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#include "qmljsinterpreter.h"
#include "qmljsevaluate.h"
#include "qmljslink.h"
#include "parser/qmljsast_p.h"
2010-01-24 19:31:38 +01:00
#include <QtCore/QMetaObject>
#include <QtCore/QMetaProperty>
#include <QtCore/QDebug>
2010-01-24 13:29:46 +01:00
#ifndef NO_DECLARATIVE_BACKEND
# include <QtDeclarative/private/qdeclarativemetatype_p.h>
# include <QtDeclarative/private/qdeclarativeanchors_p.h> // ### remove me
# include <QtDeclarative/private/qdeclarativerectangle_p.h> // ### remove me
# include <QtDeclarative/private/qdeclarativevaluetype_p.h> // ### remove me
# include <QtDeclarative/private/qdeclarativeanimation_p.h> // ### remove me
2010-01-24 13:29:46 +01:00
#endif
using namespace QmlJS::Interpreter;
using namespace QmlJS::AST;
2010-02-01 13:54:44 +01:00
namespace {
class LookupMember: public MemberProcessor
{
QString _name;
const Value *_value;
bool process(const QString &name, const Value *value)
{
if (_value)
return false;
if (name == _name) {
_value = value;
return false;
}
return true;
}
public:
LookupMember(const QString &name)
: _name(name), _value(0) {}
const Value *value() const { return _value; }
virtual bool processProperty(const QString &name, const Value *value)
{
return process(name, value);
}
virtual bool processEnumerator(const QString &name, const Value *value)
{
return process(name, value);
}
virtual bool processSignal(const QString &name, const Value *value)
{
return process(name, value);
}
virtual bool processSlot(const QString &name, const Value *value)
{
return process(name, value);
}
virtual bool processGeneratedSlot(const QString &name, const Value *value)
{
return process(name, value);
}
};
} // end of anonymous namespace
2010-01-24 13:29:46 +01:00
#ifndef NO_DECLARATIVE_BACKEND
2010-02-01 13:54:44 +01:00
namespace {
class MetaFunction: public FunctionValue
{
QMetaMethod _method;
public:
MetaFunction(const QMetaMethod &method, Engine *engine)
: FunctionValue(engine), _method(method)
{
}
virtual const Value *returnValue() const
{
return engine()->undefinedValue();
}
virtual int argumentCount() const
{
return _method.parameterNames().size();
}
virtual const Value *argument(int) const
{
return engine()->undefinedValue();
}
virtual QString argumentName(int index) const
{
if (index < _method.parameterNames().size())
return _method.parameterNames().at(index);
return FunctionValue::argumentName(index);
}
virtual bool isVariadic() const
{
return false;
}
virtual const Value *invoke(const Activation *) const
{
return engine()->undefinedValue();
}
};
2010-02-01 13:54:44 +01:00
} // end of anonymous namespace
QmlObjectValue::QmlObjectValue(const QMetaObject *metaObject, const QString &qmlTypeName,
int majorVersion, int minorVersion, Engine *engine)
: ObjectValue(engine),
_metaObject(metaObject),
_qmlTypeName(qmlTypeName),
_majorVersion(majorVersion),
_minorVersion(minorVersion)
{
setClassName(qmlTypeName); // ### TODO: we probably need to do more than just this...
}
2010-01-24 13:29:46 +01:00
QmlObjectValue::~QmlObjectValue() {}
2010-01-24 13:29:46 +01:00
const Value *QmlObjectValue::lookupMember(const QString &name, Context *context) const
{
return ObjectValue::lookupMember(name, context);
2010-02-01 13:54:44 +01:00
}
2010-02-01 13:54:44 +01:00
const Value *QmlObjectValue::findOrCreateSignature(int index, const QMetaMethod &method, QString *methodName) const
{
const QString signature = QString::fromUtf8(method.signature());
2010-02-01 13:54:44 +01:00
const int indexOfParen = signature.indexOf(QLatin1Char('('));
if (indexOfParen == -1)
return engine()->undefinedValue(); // skip it, invalid signature.
2010-02-01 13:54:44 +01:00
*methodName = signature.left(indexOfParen);
const Value *value = _metaSignature.value(index);
if (! value) {
value = new MetaFunction(method, engine());
_metaSignature.insert(index, value);
2010-01-24 13:29:46 +01:00
}
2010-02-01 13:54:44 +01:00
return value;
}
2010-01-24 13:29:46 +01:00
void QmlObjectValue::processMembers(MemberProcessor *processor) const
{
2010-02-01 13:54:44 +01:00
// process the meta enums
for (int index = _metaObject->enumeratorOffset(); index < _metaObject->propertyCount(); ++index) {
QMetaEnum e = _metaObject->enumerator(index);
for (int i = 0; i < e.keyCount(); ++i) {
processor->processEnumerator(QString::fromUtf8(e.key(i)), engine()->numberValue());
}
}
2010-02-01 13:54:44 +01:00
// process the meta properties
for (int index = 0; index < _metaObject->propertyCount(); ++index) {
QMetaProperty prop = _metaObject->property(index);
2010-02-01 13:54:44 +01:00
processor->processProperty(prop.name(), propertyValue(prop));
}
2010-02-01 13:54:44 +01:00
// process the meta methods
for (int index = 0; index < _metaObject->methodCount(); ++index) {
QMetaMethod method = _metaObject->method(index);
QString methodName;
const Value *signature = findOrCreateSignature(index, method, &methodName);
if (method.methodType() == QMetaMethod::Slot && method.access() == QMetaMethod::Public) {
2010-02-01 13:54:44 +01:00
processor->processSlot(methodName, signature);
} else if (method.methodType() == QMetaMethod::Signal && method.access() != QMetaMethod::Private) {
// process the signal
2010-02-01 13:54:44 +01:00
processor->processSignal(methodName, signature);
QString slotName;
slotName += QLatin1String("on");
slotName += methodName.at(0).toUpper();
slotName += methodName.midRef(1);
// process the generated slot
2010-02-01 13:54:44 +01:00
processor->processGeneratedSlot(slotName, signature);
}
2010-01-24 13:29:46 +01:00
}
ObjectValue::processMembers(processor);
}
const Value *QmlObjectValue::propertyValue(const QMetaProperty &prop) const
{
if (QDeclarativeMetaType::isQObject(prop.userType())) {
QDeclarativeType *qmlPropertyType = QDeclarativeMetaType::qmlType(prop.userType());
2010-01-24 13:29:46 +01:00
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);
}
if (const ObjectValue *objectValue = engine()->newQmlObject(typeName, package, qmlPropertyType->majorVersion(), qmlPropertyType->minorVersion()))
return objectValue;
} else {
2010-01-24 13:29:46 +01:00
QString typeName = QString::fromUtf8(prop.typeName());
if (typeName.endsWith(QLatin1Char('*')))
typeName.truncate(typeName.length() - 1);
typeName.replace(QLatin1Char('.'), QLatin1Char('/'));
if (const ObjectValue *objectValue = engine()->newQmlObject(typeName, "", -1, -1)) // ### we should extend this to lookup the property types in the QDeclarativeType object, instead of the QMetaProperty.
2010-01-24 13:29:46 +01:00
return objectValue;
}
}
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:
case QMetaType::QVector2D: {
// ### 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;
case QMetaType::QVector3D: {
// ### cache
ObjectValue *object = engine()->newObject(/*prototype =*/ 0);
object->setProperty("x", engine()->numberValue());
object->setProperty("y", engine()->numberValue());
object->setProperty("z", engine()->numberValue());
value = object;
} break;
case QMetaType::QColor: {
value = engine()->colorValue();
} break;
default:
break;
} // end of switch
const QString typeName = prop.typeName();
if (typeName == QLatin1String("QDeclarativeAnchorLine")) {
value = engine()->anchorLineValue();
}
if (value->asStringValue() && prop.name() == QLatin1String("easing")
&& isDerivedFrom(&QDeclarativePropertyAnimation::staticMetaObject)) {
value = engine()->easingCurveNameValue();
}
return value;
}
bool QmlObjectValue::isDerivedFrom(const QMetaObject *base) const
{
for (const QMetaObject *iter = _metaObject; iter; iter = iter->superClass()) {
if (iter == base)
return true;
}
return false;
}
2010-01-24 13:29:46 +01:00
#endif
namespace {
2010-01-24 11:10:01 +01:00
////////////////////////////////////////////////////////////////////////////////
// constructors
////////////////////////////////////////////////////////////////////////////////
class ObjectCtor: public Function
{
public:
ObjectCtor(Engine *engine);
2010-01-24 11:35:11 +01:00
virtual const Value *invoke(const Activation *activation) const;
2010-01-24 11:10:01 +01:00
};
class FunctionCtor: public Function
{
public:
FunctionCtor(Engine *engine);
2010-01-24 11:35:11 +01:00
virtual const Value *invoke(const Activation *activation) const;
2010-01-24 11:10:01 +01:00
};
class ArrayCtor: public Function
{
public:
ArrayCtor(Engine *engine);
2010-01-24 11:35:11 +01:00
virtual const Value *invoke(const Activation *activation) const;
2010-01-24 11:10:01 +01:00
};
class StringCtor: public Function
{
public:
StringCtor(Engine *engine);
2010-01-24 11:35:11 +01:00
virtual const Value *invoke(const Activation *activation) const;
2010-01-24 11:10:01 +01:00
};
class BooleanCtor: public Function
{
public:
BooleanCtor(Engine *engine);
2010-01-24 11:35:11 +01:00
virtual const Value *invoke(const Activation *activation) const;
2010-01-24 11:10:01 +01:00
};
class NumberCtor: public Function
{
public:
NumberCtor(Engine *engine);
2010-01-24 11:35:11 +01:00
virtual const Value *invoke(const Activation *activation) const;
2010-01-24 11:10:01 +01:00
};
class DateCtor: public Function
{
public:
DateCtor(Engine *engine);
2010-01-24 11:35:11 +01:00
virtual const Value *invoke(const Activation *activation) const;
2010-01-24 11:10:01 +01:00
};
class RegExpCtor: public Function
{
public:
RegExpCtor(Engine *engine);
2010-01-24 11:35:11 +01:00
virtual const Value *invoke(const Activation *activation) const;
2010-01-24 11:10:01 +01:00
};
ObjectCtor::ObjectCtor(Engine *engine)
: Function(engine)
{
}
FunctionCtor::FunctionCtor(Engine *engine)
: Function(engine)
{
}
ArrayCtor::ArrayCtor(Engine *engine)
: Function(engine)
{
}
StringCtor::StringCtor(Engine *engine)
: Function(engine)
{
}
BooleanCtor::BooleanCtor(Engine *engine)
: Function(engine)
{
}
NumberCtor::NumberCtor(Engine *engine)
: Function(engine)
{
}
DateCtor::DateCtor(Engine *engine)
: Function(engine)
{
}
RegExpCtor::RegExpCtor(Engine *engine)
: Function(engine)
{
}
2010-01-24 11:35:11 +01:00
const Value *ObjectCtor::invoke(const Activation *activation) const
2010-01-24 11:10:01 +01:00
{
2010-01-24 11:35:11 +01:00
ObjectValue *thisObject = activation->thisObject();
if (activation->calledAsFunction())
thisObject = engine()->newObject();
thisObject->setClassName("Object");
thisObject->setPrototype(engine()->objectPrototype());
thisObject->setProperty("length", engine()->numberValue());
return thisObject;
2010-01-24 11:10:01 +01:00
}
2010-01-24 11:35:11 +01:00
const Value *FunctionCtor::invoke(const Activation *activation) const
2010-01-24 11:10:01 +01:00
{
2010-01-24 11:35:11 +01:00
ObjectValue *thisObject = activation->thisObject();
if (activation->calledAsFunction())
thisObject = engine()->newObject();
thisObject->setClassName("Function");
thisObject->setPrototype(engine()->functionPrototype());
thisObject->setProperty("length", engine()->numberValue());
return thisObject;
2010-01-24 11:10:01 +01:00
}
2010-01-24 11:35:11 +01:00
const Value *ArrayCtor::invoke(const Activation *activation) const
2010-01-24 11:10:01 +01:00
{
2010-01-24 11:35:11 +01:00
ObjectValue *thisObject = activation->thisObject();
if (activation->calledAsFunction())
thisObject = engine()->newObject();
2010-01-24 11:10:01 +01:00
2010-01-24 11:35:11 +01:00
thisObject->setClassName("Array");
thisObject->setPrototype(engine()->arrayPrototype());
thisObject->setProperty("length", engine()->numberValue());
return thisObject;
2010-01-24 11:10:01 +01:00
}
2010-01-24 11:35:11 +01:00
const Value *StringCtor::invoke(const Activation *activation) const
2010-01-24 11:10:01 +01:00
{
2010-01-24 11:35:11 +01:00
if (activation->calledAsFunction())
return engine()->convertToString(activation->thisObject());
2010-01-24 11:10:01 +01:00
2010-01-24 11:35:11 +01:00
ObjectValue *thisObject = activation->thisObject();
thisObject->setClassName("String");
thisObject->setPrototype(engine()->stringPrototype());
thisObject->setProperty("length", engine()->numberValue());
return thisObject;
2010-01-24 11:10:01 +01:00
}
2010-01-24 11:35:11 +01:00
const Value *BooleanCtor::invoke(const Activation *activation) const
2010-01-24 11:10:01 +01:00
{
2010-01-24 11:35:11 +01:00
if (activation->calledAsFunction())
return engine()->convertToBoolean(activation->thisObject());
ObjectValue *thisObject = activation->thisObject();
thisObject->setClassName("Boolean");
thisObject->setPrototype(engine()->booleanPrototype());
return thisObject;
2010-01-24 11:10:01 +01:00
}
2010-01-24 11:35:11 +01:00
const Value *NumberCtor::invoke(const Activation *activation) const
2010-01-24 11:10:01 +01:00
{
2010-01-24 11:35:11 +01:00
if (activation->calledAsFunction())
return engine()->convertToNumber(activation->thisObject());
ObjectValue *thisObject = activation->thisObject();
thisObject->setClassName("Number");
thisObject->setPrototype(engine()->numberPrototype());
return thisObject;
2010-01-24 11:10:01 +01:00
}
2010-01-24 11:35:11 +01:00
const Value *DateCtor::invoke(const Activation *activation) const
2010-01-24 11:10:01 +01:00
{
2010-01-24 11:35:11 +01:00
if (activation->calledAsFunction())
return engine()->stringValue();
ObjectValue *thisObject = activation->thisObject();
thisObject->setClassName("Date");
thisObject->setPrototype(engine()->datePrototype());
return thisObject;
2010-01-24 11:10:01 +01:00
}
2010-01-24 11:35:11 +01:00
const Value *RegExpCtor::invoke(const Activation *activation) const
2010-01-24 11:10:01 +01:00
{
2010-01-24 11:35:11 +01:00
ObjectValue *thisObject = activation->thisObject();
if (activation->calledAsFunction())
thisObject = engine()->newObject();
thisObject->setClassName("RegExp");
thisObject->setPrototype(engine()->regexpPrototype());
thisObject->setProperty("source", engine()->stringValue());
thisObject->setProperty("global", engine()->booleanValue());
thisObject->setProperty("ignoreCase", engine()->booleanValue());
thisObject->setProperty("multiline", engine()->booleanValue());
thisObject->setProperty("lastIndex", engine()->numberValue());
return thisObject;
2010-01-24 11:10:01 +01:00
}
} // end of anonymous namespace
////////////////////////////////////////////////////////////////////////////////
// ValueVisitor
////////////////////////////////////////////////////////////////////////////////
2010-01-24 11:10:01 +01:00
ValueVisitor::ValueVisitor()
{
}
ValueVisitor::~ValueVisitor()
{
}
void ValueVisitor::visit(const NullValue *)
{
}
void ValueVisitor::visit(const UndefinedValue *)
{
}
void ValueVisitor::visit(const NumberValue *)
{
}
void ValueVisitor::visit(const BooleanValue *)
{
}
void ValueVisitor::visit(const StringValue *)
{
}
void ValueVisitor::visit(const ObjectValue *)
{
}
void ValueVisitor::visit(const FunctionValue *)
{
}
void ValueVisitor::visit(const Reference *)
{
}
void ValueVisitor::visit(const EasingCurveNameValue *)
{
}
void ValueVisitor::visit(const ColorValue *)
{
}
void ValueVisitor::visit(const AnchorLineValue *)
{
}
////////////////////////////////////////////////////////////////////////////////
// Value
////////////////////////////////////////////////////////////////////////////////
2010-01-24 11:10:01 +01:00
Value::Value()
{
}
Value::~Value()
{
}
bool Value::getSourceLocation(QString *, int *, int *) const
{
return false;
}
2010-01-24 11:10:01 +01:00
const NullValue *Value::asNullValue() const
{
return 0;
}
const UndefinedValue *Value::asUndefinedValue() const
{
return 0;
}
const NumberValue *Value::asNumberValue() const
{
return 0;
}
const BooleanValue *Value::asBooleanValue() const
{
return 0;
}
const StringValue *Value::asStringValue() const
{
return 0;
}
const ObjectValue *Value::asObjectValue() const
{
return 0;
}
const FunctionValue *Value::asFunctionValue() const
{
return 0;
}
const Reference *Value::asReference() const
{
return 0;
}
const EasingCurveNameValue *Value::asEasingCurveNameValue() const
{
return 0;
}
const ColorValue *Value::asColorValue() const
{
return 0;
}
const AnchorLineValue *Value::asAnchorLineValue() const
{
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// Values
////////////////////////////////////////////////////////////////////////////////
2010-01-24 11:10:01 +01:00
const NullValue *NullValue::asNullValue() const
{
return this;
}
void NullValue::accept(ValueVisitor *visitor) const
{
visitor->visit(this);
}
const UndefinedValue *UndefinedValue::asUndefinedValue() const
{
return this;
}
void UndefinedValue::accept(ValueVisitor *visitor) const
{
visitor->visit(this);
}
2010-01-24 11:10:01 +01:00
const NumberValue *NumberValue::asNumberValue() const
{
return this;
}
void NumberValue::accept(ValueVisitor *visitor) const
{
visitor->visit(this);
}
const BooleanValue *BooleanValue::asBooleanValue() const
{
return this;
}
void BooleanValue::accept(ValueVisitor *visitor) const
{
visitor->visit(this);
}
const StringValue *StringValue::asStringValue() const
{
return this;
}
void StringValue::accept(ValueVisitor *visitor) const
{
visitor->visit(this);
}
ScopeChain::ScopeChain()
: globalScope(0)
, qmlTypes(0)
{
}
ScopeChain::QmlComponentChain::QmlComponentChain()
: rootObject(0), ids(0)
{
}
ScopeChain::QmlComponentChain::~QmlComponentChain()
{
qDeleteAll(instantiatingComponents);
}
void ScopeChain::QmlComponentChain::clear()
{
qDeleteAll(instantiatingComponents);
instantiatingComponents.clear();
rootObject = 0;
functionScopes.clear();
ids = 0;
}
void ScopeChain::QmlComponentChain::add(QList<const ObjectValue *> *list) const
{
foreach (QmlComponentChain *parent, instantiatingComponents)
parent->add(list);
if (rootObject)
list->append(rootObject);
list->append(functionScopes);
if (ids)
list->append(ids);
}
void ScopeChain::update()
{
_all.clear();
_all += globalScope;
foreach (QmlComponentChain *parent, qmlComponentScope.instantiatingComponents)
parent->add(&_all);
if (qmlComponentScope.rootObject && ! qmlScopeObjects.contains(qmlComponentScope.rootObject))
_all += qmlComponentScope.rootObject;
_all += qmlScopeObjects;
_all += qmlComponentScope.functionScopes;
if (qmlComponentScope.ids)
_all += qmlComponentScope.ids;
if (qmlTypes)
_all += qmlTypes;
_all += jsScopes;
}
QList<const ObjectValue *> ScopeChain::all() const
{
return _all;
}
Context::Context(Engine *engine)
: _engine(engine),
_lookupMode(JSLookup),
_qmlScopeObjectIndex(-1),
_qmlScopeObjectSet(false)
{
}
Context::~Context()
{
}
2010-02-22 11:57:32 +01:00
void Context::build(const QList<Node *> &astPath, QmlJS::Document::Ptr doc, const QmlJS::Snapshot &snapshot)
{
Link link(this, doc, snapshot);
link.scopeChainAt(doc, astPath);
}
Engine *Context::engine() const
{
return _engine;
}
const ScopeChain &Context::scopeChain() const
{
return _scopeChain;
}
ScopeChain &Context::scopeChain()
{
return _scopeChain;
}
Context::LookupMode Context::lookupMode() const
{
return _lookupMode;
}
void Context::setLookupMode(LookupMode lookupMode)
{
_lookupMode = lookupMode;
}
const ObjectValue *Context::typeEnvironment(const QmlJS::Document *doc) const
{
return _typeEnvironments.value(doc, 0);
}
void Context::setTypeEnvironment(const QmlJS::Document *doc, const ObjectValue *typeEnvironment)
{
_typeEnvironments[doc] = typeEnvironment;
}
const Value *Context::lookup(const QString &name)
{
QList<const ObjectValue *> scopes = _scopeChain.all();
for (int index = scopes.size() - 1; index != -1; --index) {
const ObjectValue *scope = scopes.at(index);
if (const Value *member = scope->lookupMember(name, this)) {
if (_lookupMode == JSLookup || ! dynamic_cast<const ASTVariableReference *>(member)) {
return member;
}
}
}
return _engine->undefinedValue();
}
const ObjectValue *Context::lookupType(const QmlJS::Document *doc, UiQualifiedId *qmlTypeName)
{
const ObjectValue *objectValue = typeEnvironment(doc);
for (UiQualifiedId *iter = qmlTypeName; objectValue && iter; iter = iter->next) {
if (! iter->name)
return 0;
const Value *value = objectValue->property(iter->name->asString(), this);
if (!value)
return 0;
objectValue = value->asObjectValue();
}
return objectValue;
}
const Value *Context::property(const ObjectValue *object, const QString &name) const
{
const Properties properties = _properties.value(object);
return properties.value(name, engine()->undefinedValue());
}
void Context::setProperty(const ObjectValue *object, const QString &name, const Value *value)
{
_properties[object].insert(name, value);
}
Reference::Reference(Engine *engine)
: _engine(engine)
{
_engine->registerValue(this);
}
Reference::~Reference()
{
}
Engine *Reference::engine() const
{
return _engine;
}
const Reference *Reference::asReference() const
{
return this;
}
void Reference::accept(ValueVisitor *visitor) const
{
visitor->visit(this);
}
const Value *Reference::value(Context *) const
{
return _engine->undefinedValue();
}
void EasingCurveNameValue::accept(ValueVisitor *visitor) const
{
visitor->visit(this);
}
QSet<QString> EasingCurveNameValue::_curveNames;
QSet<QString> EasingCurveNameValue::curveNames()
{
if (_curveNames.isEmpty()) {
_curveNames = QSet<QString>()
<< "easeLinear"
<< "easeInQuad"
<< "easeOutQuad"
<< "easeInOutQuad"
<< "easeOutInQuad"
<< "easeInCubic"
<< "easeOutCubic"
<< "easeInOutCubic"
<< "easeOutInCubic"
<< "easeInQuart"
<< "easeOutQuart"
<< "easeInOutQuart"
<< "easeOutInQuart"
<< "easeInQuint"
<< "easeOutQuint"
<< "easeInOutQuint"
<< "easeOutInQuint"
<< "easeInSine"
<< "easeOutSine"
<< "easeInOutSine"
<< "easeOutInSine"
<< "easeInExpo"
<< "easeOutExpo"
<< "easeInOutExpo"
<< "easeOutInExpo"
<< "easeInCirc"
<< "easeOutCirc"
<< "easeInOutCirc"
<< "easeOutInCirc"
<< "easeInElastic"
<< "easeOutElastic"
<< "easeInOutElastic"
<< "easeOutInElastic"
<< "easeInBack"
<< "easeOutBack"
<< "easeInOutBack"
<< "easeOutInBack"
<< "easeInBounce"
<< "easeOutBounce"
<< "easeInOutBounce"
<< "easeOutInBounce";
}
return _curveNames;
}
const EasingCurveNameValue *EasingCurveNameValue::asEasingCurveNameValue() const
{
return this;
}
void ColorValue::accept(ValueVisitor *visitor) const
{
visitor->visit(this);
}
const ColorValue *ColorValue::asColorValue() const
{
return this;
}
void AnchorLineValue::accept(ValueVisitor *visitor) const
{
visitor->visit(this);
}
const AnchorLineValue *AnchorLineValue::asAnchorLineValue() const
{
return this;
}
MemberProcessor::MemberProcessor()
{
}
MemberProcessor::~MemberProcessor()
{
}
bool MemberProcessor::processProperty(const QString &, const Value *)
{
return true;
}
bool MemberProcessor::processEnumerator(const QString &, const Value *)
{
return true;
}
bool MemberProcessor::processSignal(const QString &, const Value *)
{
return true;
}
bool MemberProcessor::processSlot(const QString &, const Value *)
{
return true;
}
bool MemberProcessor::processGeneratedSlot(const QString &, const Value *)
{
return true;
}
2010-01-24 11:10:01 +01:00
ObjectValue::ObjectValue(Engine *engine)
: _engine(engine),
_prototype(0)
2010-01-24 11:10:01 +01:00
{
engine->registerValue(this);
2010-01-24 11:10:01 +01:00
}
ObjectValue::~ObjectValue()
{
}
Engine *ObjectValue::engine() const
{
return _engine;
}
QString ObjectValue::className() const
{
return _className;
}
void ObjectValue::setClassName(const QString &className)
{
_className = className;
}
const ObjectValue *ObjectValue::prototype(Context *context) const
2010-01-24 11:10:01 +01:00
{
const ObjectValue *prototypeObject = value_cast<const ObjectValue *>(_prototype);
if (! prototypeObject) {
if (const Reference *prototypeReference = value_cast<const Reference *>(_prototype)) {
prototypeObject = value_cast<const ObjectValue *>(prototypeReference->value(context));
}
}
return prototypeObject;
}
void ObjectValue::setPrototype(const Value *prototype)
{
// ### FIXME: Check for cycles.
_prototype = prototype;
2010-01-24 11:10:01 +01:00
}
void ObjectValue::setProperty(const QString &name, const Value *value)
{
_members[name] = value;
}
void ObjectValue::removeProperty(const QString &name)
{
_members.remove(name);
}
const ObjectValue *ObjectValue::asObjectValue() const
{
return this;
}
void ObjectValue::accept(ValueVisitor *visitor) const
{
visitor->visit(this);
}
const Value *ObjectValue::property(const QString &name, Context *context) const
2010-01-24 11:10:01 +01:00
{
return lookupMember(name, context);
}
bool ObjectValue::checkPrototype(const ObjectValue *, QSet<const ObjectValue *> *) const
{
#if 0
const int previousSize = processed->size();
processed->insert(this);
if (previousSize != processed->size()) {
if (this == proto)
return false;
2010-01-24 11:10:01 +01:00
if (prototype() && ! prototype()->checkPrototype(proto, processed))
return false;
return true;
}
#endif
return false;
}
2010-01-24 11:10:01 +01:00
void ObjectValue::processMembers(MemberProcessor *processor) const
{
QHashIterator<QString, const Value *> it(_members);
while (it.hasNext()) {
it.next();
if (! processor->processProperty(it.key(), it.value()))
2010-01-24 11:10:01 +01:00
break;
}
}
const Value *ObjectValue::lookupMember(const QString &name, Context *context) const
2010-01-24 11:10:01 +01:00
{
2010-01-24 13:29:46 +01:00
if (const Value *m = _members.value(name))
2010-01-24 11:10:01 +01:00
return m;
2010-02-01 13:54:44 +01:00
else {
LookupMember slowLookup(name);
processMembers(&slowLookup);
if (slowLookup.value())
return slowLookup.value();
}
2010-01-24 11:10:01 +01:00
const ObjectValue *prototypeObject = prototype(context);
if (prototypeObject) {
if (const Value *m = prototypeObject->lookupMember(name, context))
2010-01-24 11:10:01 +01:00
return m;
}
return 0;
}
Activation::Activation(Context *parentContext)
: _thisObject(0),
_calledAsFunction(true),
_parentContext(parentContext)
2010-01-24 11:35:11 +01:00
{
}
Activation::~Activation()
{
}
Context *Activation::parentContext() const
{
return _parentContext;
}
Context *Activation::context() const
{
// ### FIXME: Real context for activations.
return 0;
}
2010-01-24 11:35:11 +01:00
bool Activation::calledAsConstructor() const
{
return ! _calledAsFunction;
}
void Activation::setCalledAsConstructor(bool calledAsConstructor)
{
_calledAsFunction = ! calledAsConstructor;
}
bool Activation::calledAsFunction() const
{
return _calledAsFunction;
}
void Activation::setCalledAsFunction(bool calledAsFunction)
{
_calledAsFunction = calledAsFunction;
}
ObjectValue *Activation::thisObject() const
{
return _thisObject;
}
void Activation::setThisObject(ObjectValue *thisObject)
{
_thisObject = thisObject;
}
ValueList Activation::arguments() const
{
return _arguments;
}
void Activation::setArguments(const ValueList &arguments)
{
_arguments = arguments;
}
2010-01-24 11:10:01 +01:00
FunctionValue::FunctionValue(Engine *engine)
: ObjectValue(engine)
{
}
FunctionValue::~FunctionValue()
{
}
const Value *FunctionValue::construct(const ValueList &actuals) const
{
Activation activation;
2010-01-24 11:35:11 +01:00
activation.setCalledAsConstructor(true);
activation.setThisObject(engine()->newObject());
activation.setArguments(actuals);
return invoke(&activation);
2010-01-24 11:10:01 +01:00
}
const Value *FunctionValue::call(const ValueList &actuals) const
{
Activation activation;
2010-01-24 11:35:11 +01:00
activation.setCalledAsFunction(true);
activation.setThisObject(engine()->globalObject()); // ### FIXME: it should be `null'
activation.setArguments(actuals);
return invoke(&activation);
2010-01-24 11:10:01 +01:00
}
const Value *FunctionValue::call(const ObjectValue *thisObject, const ValueList &actuals) const
{
Activation activation;
2010-01-24 11:35:11 +01:00
activation.setCalledAsFunction(true);
activation.setThisObject(const_cast<ObjectValue *>(thisObject)); // ### FIXME: remove the const_cast
activation.setArguments(actuals);
return invoke(&activation);
2010-01-24 11:10:01 +01:00
}
const Value *FunctionValue::returnValue() const
{
return engine()->undefinedValue();
}
2010-01-24 11:10:01 +01:00
int FunctionValue::argumentCount() const
{
return 0;
}
const Value *FunctionValue::argument(int) const
{
return engine()->undefinedValue();
}
QString FunctionValue::argumentName(int index) const
{
2010-02-01 12:43:36 +01:00
return QString::fromLatin1("arg%1").arg(index + 1);
}
bool FunctionValue::isVariadic() const
{
return true;
}
const Value *FunctionValue::invoke(const Activation *activation) const
{
return activation->thisObject(); // ### FIXME: it should return undefined
}
2010-01-24 11:10:01 +01:00
const FunctionValue *FunctionValue::asFunctionValue() const
{
return this;
}
void FunctionValue::accept(ValueVisitor *visitor) const
{
visitor->visit(this);
}
Function::Function(Engine *engine)
: FunctionValue(engine), _returnValue(0)
{
2010-01-24 11:10:01 +01:00
setClassName("Function");
}
2010-01-24 11:35:11 +01:00
Function::~Function()
{
}
2010-01-24 11:10:01 +01:00
void Function::addArgument(const Value *argument)
{
2010-01-24 11:10:01 +01:00
_arguments.push_back(argument);
}
2010-01-24 11:10:01 +01:00
const Value *Function::returnValue() const
{
2010-01-24 11:10:01 +01:00
return _returnValue;
}
2010-01-24 11:10:01 +01:00
void Function::setReturnValue(const Value *returnValue)
{
_returnValue = returnValue;
}
2010-01-24 11:10:01 +01:00
int Function::argumentCount() const
{
return _arguments.size();
}
2010-01-24 11:10:01 +01:00
const Value *Function::argument(int index) const
{
return _arguments.at(index);
}
const Value *Function::property(const QString &name, Context *context) const
{
if (name == "length")
return engine()->numberValue();
return FunctionValue::property(name, context);
}
2010-01-24 11:35:11 +01:00
const Value *Function::invoke(const Activation *activation) const
{
2010-01-24 11:35:11 +01:00
return activation->thisObject(); // ### FIXME it should return undefined
}
////////////////////////////////////////////////////////////////////////////////
// typing environment
////////////////////////////////////////////////////////////////////////////////
2010-01-24 11:10:01 +01:00
ConvertToNumber::ConvertToNumber(Engine *engine)
: _engine(engine), _result(0)
{
}
2010-01-24 11:10:01 +01:00
const Value *ConvertToNumber::operator()(const Value *value)
{
const Value *previousValue = switchResult(0);
if (value)
value->accept(this);
return switchResult(previousValue);
}
2010-01-24 11:10:01 +01:00
const Value *ConvertToNumber::switchResult(const Value *value)
{
const Value *previousResult = _result;
_result = value;
return previousResult;
}
void ConvertToNumber::visit(const NullValue *)
{
_result = _engine->numberValue();
}
void ConvertToNumber::visit(const UndefinedValue *)
{
_result = _engine->numberValue();
}
void ConvertToNumber::visit(const NumberValue *value)
{
_result = value;
}
void ConvertToNumber::visit(const BooleanValue *)
{
_result = _engine->numberValue();
}
void ConvertToNumber::visit(const StringValue *)
{
_result = _engine->numberValue();
}
void ConvertToNumber::visit(const ObjectValue *object)
{
if (const FunctionValue *valueOfMember = value_cast<const FunctionValue *>(object->lookupMember("valueOf", 0))) {
_result = value_cast<const NumberValue *>(valueOfMember->call(object)); // ### invoke convert-to-number?
}
}
void ConvertToNumber::visit(const FunctionValue *object)
{
if (const FunctionValue *valueOfMember = value_cast<const FunctionValue *>(object->lookupMember("valueOf", 0))) {
_result = value_cast<const NumberValue *>(valueOfMember->call(object)); // ### invoke convert-to-number?
}
}
2010-01-24 11:10:01 +01:00
ConvertToString::ConvertToString(Engine *engine)
: _engine(engine), _result(0)
{
}
2010-01-24 11:10:01 +01:00
const Value *ConvertToString::operator()(const Value *value)
{
const Value *previousValue = switchResult(0);
if (value)
value->accept(this);
return switchResult(previousValue);
}
2010-01-24 11:10:01 +01:00
const Value *ConvertToString::switchResult(const Value *value)
{
const Value *previousResult = _result;
_result = value;
return previousResult;
}
void ConvertToString::visit(const NullValue *)
{
_result = _engine->stringValue();
}
void ConvertToString::visit(const UndefinedValue *)
{
_result = _engine->stringValue();
}
void ConvertToString::visit(const NumberValue *)
{
_result = _engine->stringValue();
}
void ConvertToString::visit(const BooleanValue *)
{
_result = _engine->stringValue();
}
void ConvertToString::visit(const StringValue *value)
{
_result = value;
}
void ConvertToString::visit(const ObjectValue *object)
{
if (const FunctionValue *toStringMember = value_cast<const FunctionValue *>(object->lookupMember("toString", 0))) {
_result = value_cast<const StringValue *>(toStringMember->call(object)); // ### invoke convert-to-string?
}
}
void ConvertToString::visit(const FunctionValue *object)
{
if (const FunctionValue *toStringMember = value_cast<const FunctionValue *>(object->lookupMember("toString", 0))) {
_result = value_cast<const StringValue *>(toStringMember->call(object)); // ### invoke convert-to-string?
}
}
ConvertToObject::ConvertToObject(Engine *engine)
: _engine(engine), _result(0)
{
}
2010-01-24 11:10:01 +01:00
const Value *ConvertToObject::operator()(const Value *value)
{
const Value *previousValue = switchResult(0);
if (value)
value->accept(this);
return switchResult(previousValue);
}
2010-01-24 11:10:01 +01:00
const Value *ConvertToObject::switchResult(const Value *value)
{
const Value *previousResult = _result;
_result = value;
return previousResult;
}
void ConvertToObject::visit(const NullValue *value)
{
_result = value;
}
void ConvertToObject::visit(const UndefinedValue *)
{
_result = _engine->nullValue();
}
2010-01-24 11:10:01 +01:00
void ConvertToObject::visit(const NumberValue *value)
{
2010-01-24 11:10:01 +01:00
ValueList actuals;
actuals.append(value);
_result = _engine->numberCtor()->construct(actuals);
}
2010-01-24 11:10:01 +01:00
void ConvertToObject::visit(const BooleanValue *value)
{
2010-01-24 11:10:01 +01:00
ValueList actuals;
actuals.append(value);
_result = _engine->booleanCtor()->construct(actuals);
}
2010-01-24 11:10:01 +01:00
void ConvertToObject::visit(const StringValue *value)
{
2010-01-24 11:10:01 +01:00
ValueList actuals;
actuals.append(value);
_result = _engine->stringCtor()->construct(actuals);
}
void ConvertToObject::visit(const ObjectValue *object)
{
_result = object;
}
void ConvertToObject::visit(const FunctionValue *object)
{
_result = object;
}
QString TypeId::operator()(const Value *value)
{
_result = QLatin1String("unknown");
if (value)
value->accept(this);
return _result;
}
2010-01-24 11:10:01 +01:00
void TypeId::visit(const NullValue *)
{
2010-01-24 11:10:01 +01:00
_result = QLatin1String("null");
}
2010-01-24 11:10:01 +01:00
void TypeId::visit(const UndefinedValue *)
{
2010-01-24 11:10:01 +01:00
_result = QLatin1String("undefined");
}
2010-01-24 11:10:01 +01:00
void TypeId::visit(const NumberValue *)
{
2010-01-24 11:10:01 +01:00
_result = QLatin1String("number");
}
2010-01-24 11:10:01 +01:00
void TypeId::visit(const BooleanValue *)
{
2010-01-24 11:10:01 +01:00
_result = QLatin1String("boolean");
}
2010-01-24 11:10:01 +01:00
void TypeId::visit(const StringValue *)
{
2010-01-24 11:10:01 +01:00
_result = QLatin1String("string");
}
2010-01-24 11:10:01 +01:00
void TypeId::visit(const ObjectValue *object)
{
2010-01-24 11:10:01 +01:00
_result = object->className();
2010-01-24 11:10:01 +01:00
if (_result.isEmpty())
_result = QLatin1String("object");
}
2010-01-24 11:10:01 +01:00
void TypeId::visit(const FunctionValue *object)
{
2010-01-24 11:10:01 +01:00
_result = object->className();
2010-01-24 11:10:01 +01:00
if (_result.isEmpty())
_result = QLatin1String("Function");
}
void TypeId::visit(const EasingCurveNameValue *)
{
_result = QLatin1String("string");
}
void TypeId::visit(const ColorValue *)
{
_result = QLatin1String("string");
}
void TypeId::visit(const AnchorLineValue *)
{
_result = QLatin1String("AnchorLine");
}
Engine::Engine()
: _objectPrototype(0),
_functionPrototype(0),
_numberPrototype(0),
_booleanPrototype(0),
_stringPrototype(0),
_arrayPrototype(0),
_datePrototype(0),
_regexpPrototype(0),
_objectCtor(0),
_functionCtor(0),
_arrayCtor(0),
_stringCtor(0),
_booleanCtor(0),
_numberCtor(0),
_dateCtor(0),
_regexpCtor(0),
_globalObject(0),
_mathObject(0),
_qtObject(0),
#ifndef NO_DECLARATIVE_BACKEND
_qmlKeysObject(0),
#endif
_convertToNumber(this),
_convertToString(this),
_convertToObject(this)
{
initializePrototypes();
_metaTypeSystem.reload(this);
}
2010-01-24 11:10:01 +01:00
Engine::~Engine()
{
qDeleteAll(_registeredValues);
}
2010-01-24 11:10:01 +01:00
const NullValue *Engine::nullValue() const
{
return &_nullValue;
}
const UndefinedValue *Engine::undefinedValue() const
{
return &_undefinedValue;
}
const NumberValue *Engine::numberValue() const
{
return &_numberValue;
}
const BooleanValue *Engine::booleanValue() const
{
return &_booleanValue;
}
const StringValue *Engine::stringValue() const
{
return &_stringValue;
}
const EasingCurveNameValue *Engine::easingCurveNameValue() const
{
return &_easingCurveNameValue;
}
const ColorValue *Engine::colorValue() const
{
return &_colorValue;
}
const AnchorLineValue *Engine::anchorLineValue() const
{
return &_anchorLineValue;
}
2010-01-24 11:10:01 +01:00
const Value *Engine::newArray()
{
return arrayCtor()->construct();
}
ObjectValue *Engine::newObject()
{
return newObject(_objectPrototype);
}
ObjectValue *Engine::newObject(const ObjectValue *prototype)
{
ObjectValue *object = new ObjectValue(this);
object->setPrototype(prototype);
return object;
}
Function *Engine::newFunction()
{
Function *function = new Function(this);
function->setPrototype(functionPrototype());
return function;
}
2010-01-24 11:10:01 +01:00
ObjectValue *Engine::globalObject() const
{
return _globalObject;
}
ObjectValue *Engine::objectPrototype() const
{
return _objectPrototype;
}
ObjectValue *Engine::functionPrototype() const
{
return _functionPrototype;
}
ObjectValue *Engine::numberPrototype() const
{
return _numberPrototype;
}
ObjectValue *Engine::booleanPrototype() const
{
return _booleanPrototype;
}
ObjectValue *Engine::stringPrototype() const
{
return _stringPrototype;
}
ObjectValue *Engine::arrayPrototype() const
{
return _arrayPrototype;
}
ObjectValue *Engine::datePrototype() const
{
return _datePrototype;
}
ObjectValue *Engine::regexpPrototype() const
{
return _regexpPrototype;
}
const FunctionValue *Engine::objectCtor() const
{
return _objectCtor;
}
const FunctionValue *Engine::functionCtor() const
{
return _functionCtor;
}
const FunctionValue *Engine::arrayCtor() const
{
return _arrayCtor;
}
const FunctionValue *Engine::stringCtor() const
{
return _stringCtor;
}
const FunctionValue *Engine::booleanCtor() const
{
return _booleanCtor;
}
const FunctionValue *Engine::numberCtor() const
{
return _numberCtor;
}
const FunctionValue *Engine::dateCtor() const
{
return _dateCtor;
}
const FunctionValue *Engine::regexpCtor() const
{
return _regexpCtor;
}
const ObjectValue *Engine::mathObject() const
{
return _mathObject;
}
const ObjectValue *Engine::qtObject() const
{
return _qtObject;
}
void Engine::registerValue(Value *value)
{
_registeredValues.append(value);
}
2010-01-24 11:35:11 +01:00
const Value *Engine::convertToBoolean(const Value *value)
2010-01-24 11:10:01 +01:00
{
return _convertToNumber(value); // ### implement convert to bool
}
const Value *Engine::convertToNumber(const Value *value)
{
return _convertToNumber(value);
}
const Value *Engine::convertToString(const Value *value)
{
return _convertToString(value);
}
2010-01-24 11:10:01 +01:00
const Value *Engine::convertToObject(const Value *value)
{
2010-01-24 11:10:01 +01:00
return _convertToObject(value);
}
2010-01-24 11:10:01 +01:00
QString Engine::typeId(const Value *value)
{
2010-01-24 11:10:01 +01:00
return _typeId(value);
}
void Engine::addFunction(ObjectValue *object, const QString &name, const Value *result, int argumentCount)
{
Function *function = newFunction();
function->setReturnValue(result);
for (int i = 0; i < argumentCount; ++i)
function->addArgument(undefinedValue()); // ### introduce unknownValue
object->setProperty(name, function);
}
void Engine::addFunction(ObjectValue *object, const QString &name, int argumentCount)
{
Function *function = newFunction();
for (int i = 0; i < argumentCount; ++i)
function->addArgument(undefinedValue()); // ### introduce unknownValue
object->setProperty(name, function);
}
void Engine::initializePrototypes()
{
_objectPrototype = newObject(/*prototype = */ 0);
_functionPrototype = newObject(_objectPrototype);
_numberPrototype = newObject(_objectPrototype);
_booleanPrototype = newObject(_objectPrototype);
_stringPrototype = newObject(_objectPrototype);
_arrayPrototype = newObject(_objectPrototype);
_datePrototype = newObject(_objectPrototype);
_regexpPrototype = newObject(_objectPrototype);
// set up the Global object
_globalObject = newObject();
_globalObject->setClassName("Global");
// set up the default Object prototype
_objectCtor = new ObjectCtor(this);
_objectCtor->setPrototype(_functionPrototype);
_objectCtor->setProperty("prototype", _objectPrototype);
_functionCtor = new FunctionCtor(this);
_functionCtor->setPrototype(_functionPrototype);
_functionCtor->setProperty("prototype", _functionPrototype);
_arrayCtor = new ArrayCtor(this);
_arrayCtor->setPrototype(_functionPrototype);
_arrayCtor->setProperty("prototype", _arrayPrototype);
_stringCtor = new StringCtor(this);
_stringCtor->setPrototype(_functionPrototype);
_stringCtor->setProperty("prototype", _stringPrototype);
_booleanCtor = new BooleanCtor(this);
_booleanCtor->setPrototype(_functionPrototype);
_booleanCtor->setProperty("prototype", _booleanPrototype);
_numberCtor = new NumberCtor(this);
_numberCtor->setPrototype(_functionPrototype);
_numberCtor->setProperty("prototype", _numberPrototype);
_dateCtor = new DateCtor(this);
_dateCtor->setPrototype(_functionPrototype);
_dateCtor->setProperty("prototype", _datePrototype);
_regexpCtor = new RegExpCtor(this);
_regexpCtor->setPrototype(_functionPrototype);
_regexpCtor->setProperty("prototype", _regexpPrototype);
addFunction(_objectCtor, "getPrototypeOf", 1);
addFunction(_objectCtor, "getOwnPropertyDescriptor", 2);
2010-01-24 11:10:01 +01:00
addFunction(_objectCtor, "getOwnPropertyNames", newArray(), 1);
addFunction(_objectCtor, "create", 1);
addFunction(_objectCtor, "defineProperty", 3);
addFunction(_objectCtor, "defineProperties", 2);
addFunction(_objectCtor, "seal", 1);
addFunction(_objectCtor, "freeze", 1);
addFunction(_objectCtor, "preventExtensions", 1);
addFunction(_objectCtor, "isSealed", booleanValue(), 1);
addFunction(_objectCtor, "isFrozen", booleanValue(), 1);
addFunction(_objectCtor, "isExtensible", booleanValue(), 1);
2010-01-24 11:10:01 +01:00
addFunction(_objectCtor, "keys", newArray(), 1);
addFunction(_objectPrototype, "toString", stringValue(), 0);
addFunction(_objectPrototype, "toLocaleString", stringValue(), 0);
2010-01-24 11:10:01 +01:00
addFunction(_objectPrototype, "valueOf", 0); // ### FIXME it should return thisObject
addFunction(_objectPrototype, "hasOwnProperty", booleanValue(), 1);
addFunction(_objectPrototype, "isPrototypeOf", booleanValue(), 1);
addFunction(_objectPrototype, "propertyIsEnumerable", booleanValue(), 1);
// set up the default Function prototype
_functionPrototype->setProperty("constructor", _functionCtor);
addFunction(_functionPrototype, "toString", stringValue(), 0);
addFunction(_functionPrototype, "apply", 2);
addFunction(_functionPrototype, "call", 1);
addFunction(_functionPrototype, "bind", 1);
// set up the default Array prototype
addFunction(_arrayCtor, "isArray", booleanValue(), 1);
_arrayPrototype->setProperty("constructor", _arrayCtor);
addFunction(_arrayPrototype, "toString", stringValue(), 0);
addFunction(_arrayPrototype, "toLocalString", stringValue(), 0);
addFunction(_arrayPrototype, "concat", 0);
addFunction(_arrayPrototype, "join", 1);
addFunction(_arrayPrototype, "pop", 0);
addFunction(_arrayPrototype, "push", 0);
addFunction(_arrayPrototype, "reverse", 0);
addFunction(_arrayPrototype, "shift", 0);
addFunction(_arrayPrototype, "slice", 2);
addFunction(_arrayPrototype, "sort", 1);
addFunction(_arrayPrototype, "splice", 2);
addFunction(_arrayPrototype, "unshift", 0);
addFunction(_arrayPrototype, "indexOf", numberValue(), 1);
addFunction(_arrayPrototype, "lastIndexOf", numberValue(), 1);
addFunction(_arrayPrototype, "every", 1);
addFunction(_arrayPrototype, "some", 1);
addFunction(_arrayPrototype, "forEach", 1);
addFunction(_arrayPrototype, "map", 1);
addFunction(_arrayPrototype, "filter", 1);
addFunction(_arrayPrototype, "reduce", 1);
addFunction(_arrayPrototype, "reduceRight", 1);
// set up the default String prototype
addFunction(_stringCtor, "fromCharCode", stringValue(), 0);
_stringPrototype->setProperty("constructor", _stringCtor);
addFunction(_stringPrototype, "toString", stringValue(), 0);
addFunction(_stringPrototype, "valueOf", stringValue(), 0);
addFunction(_stringPrototype, "charAt", stringValue(), 1);
addFunction(_stringPrototype, "charCodeAt", stringValue(), 1);
addFunction(_stringPrototype, "concat", stringValue(), 0);
addFunction(_stringPrototype, "indexOf", numberValue(), 2);
addFunction(_stringPrototype, "lastIndexOf", numberValue(), 2);
addFunction(_stringPrototype, "localeCompare", booleanValue(), 1);
2010-01-24 11:10:01 +01:00
addFunction(_stringPrototype, "match", newArray(), 1);
addFunction(_stringPrototype, "replace", stringValue(), 2);
addFunction(_stringPrototype, "search", numberValue(), 1);
addFunction(_stringPrototype, "slice", stringValue(), 2);
addFunction(_stringPrototype, "split", newArray(), 1);
addFunction(_stringPrototype, "substring", stringValue(), 2);
addFunction(_stringPrototype, "toLowerCase", stringValue(), 0);
addFunction(_stringPrototype, "toLocaleLowerCase", stringValue(), 0);
addFunction(_stringPrototype, "toUpperCase", stringValue(), 0);
addFunction(_stringPrototype, "toLocaleUpperCase", stringValue(), 0);
addFunction(_stringPrototype, "trim", stringValue(), 0);
// set up the default Boolean prototype
addFunction(_booleanCtor, "fromCharCode", 0);
_booleanPrototype->setProperty("constructor", _booleanCtor);
addFunction(_booleanPrototype, "toString", stringValue(), 0);
addFunction(_booleanPrototype, "valueOf", booleanValue(), 0);
// set up the default Number prototype
_numberCtor->setProperty("MAX_VALUE", numberValue());
_numberCtor->setProperty("MIN_VALUE", numberValue());
_numberCtor->setProperty("NaN", numberValue());
_numberCtor->setProperty("NEGATIVE_INFINITY", numberValue());
_numberCtor->setProperty("POSITIVE_INFINITY", numberValue());
addFunction(_numberCtor, "fromCharCode", 0);
_numberPrototype->setProperty("constructor", _numberCtor);
addFunction(_numberPrototype, "toString", stringValue(), 0);
addFunction(_numberPrototype, "toLocaleString", stringValue(), 0);
addFunction(_numberPrototype, "valueOf", numberValue(), 0);
addFunction(_numberPrototype, "toFixed", numberValue(), 1);
addFunction(_numberPrototype, "toExponential", numberValue(), 1);
addFunction(_numberPrototype, "toPrecision", numberValue(), 1);
// set up the Math object
_mathObject = newObject();
_mathObject->setProperty("E", numberValue());
_mathObject->setProperty("LN10", numberValue());
_mathObject->setProperty("LN2", numberValue());
_mathObject->setProperty("LOG2E", numberValue());
_mathObject->setProperty("LOG10E", numberValue());
_mathObject->setProperty("PI", numberValue());
_mathObject->setProperty("SQRT1_2", numberValue());
_mathObject->setProperty("SQRT2", numberValue());
addFunction(_mathObject, "abs", numberValue(), 1);
addFunction(_mathObject, "acos", numberValue(), 1);
addFunction(_mathObject, "asin", numberValue(), 1);
addFunction(_mathObject, "atan", numberValue(), 1);
addFunction(_mathObject, "atan2", numberValue(), 2);
addFunction(_mathObject, "ceil", numberValue(), 1);
addFunction(_mathObject, "cos", numberValue(), 1);
addFunction(_mathObject, "exp", numberValue(), 1);
addFunction(_mathObject, "floor", numberValue(), 1);
addFunction(_mathObject, "log", numberValue(), 1);
addFunction(_mathObject, "max", numberValue(), 0);
addFunction(_mathObject, "min", numberValue(), 0);
addFunction(_mathObject, "pow", numberValue(), 2);
addFunction(_mathObject, "random", numberValue(), 1);
addFunction(_mathObject, "round", numberValue(), 1);
addFunction(_mathObject, "sin", numberValue(), 1);
addFunction(_mathObject, "sqrt", numberValue(), 1);
addFunction(_mathObject, "tan", numberValue(), 1);
// set up the default Boolean prototype
addFunction(_dateCtor, "parse", numberValue(), 1);
addFunction(_dateCtor, "now", numberValue(), 0);
_datePrototype->setProperty("constructor", _dateCtor);
addFunction(_datePrototype, "toString", stringValue(), 0);
addFunction(_datePrototype, "toDateString", stringValue(), 0);
addFunction(_datePrototype, "toTimeString", stringValue(), 0);
addFunction(_datePrototype, "toLocaleString", stringValue(), 0);
addFunction(_datePrototype, "toLocaleDateString", stringValue(), 0);
addFunction(_datePrototype, "toLocaleTimeString", stringValue(), 0);
addFunction(_datePrototype, "valueOf", numberValue(), 0);
addFunction(_datePrototype, "getTime", numberValue(), 0);
addFunction(_datePrototype, "getFullYear", numberValue(), 0);
addFunction(_datePrototype, "getUTCFullYear", numberValue(), 0);
addFunction(_datePrototype, "getMonth", numberValue(), 0);
addFunction(_datePrototype, "getUTCMonth", numberValue(), 0);
addFunction(_datePrototype, "getDate", numberValue(), 0);
addFunction(_datePrototype, "getUTCDate", numberValue(), 0);
addFunction(_datePrototype, "getHours", numberValue(), 0);
addFunction(_datePrototype, "getUTCHours", numberValue(), 0);
addFunction(_datePrototype, "getMinutes", numberValue(), 0);
addFunction(_datePrototype, "getUTCMinutes", numberValue(), 0);
addFunction(_datePrototype, "getSeconds", numberValue(), 0);
addFunction(_datePrototype, "getUTCSeconds", numberValue(), 0);
addFunction(_datePrototype, "getMilliseconds", numberValue(), 0);
addFunction(_datePrototype, "getUTCMilliseconds", numberValue(), 0);
addFunction(_datePrototype, "getTimezoneOffset", numberValue(), 0);
addFunction(_datePrototype, "setTime", 1);
addFunction(_datePrototype, "setMilliseconds", 1);
addFunction(_datePrototype, "setUTCMilliseconds", 1);
addFunction(_datePrototype, "setSeconds", 1);
addFunction(_datePrototype, "setUTCSeconds", 1);
addFunction(_datePrototype, "setMinutes", 1);
addFunction(_datePrototype, "setUTCMinutes", 1);
addFunction(_datePrototype, "setHours", 1);
addFunction(_datePrototype, "setUTCHours", 1);
addFunction(_datePrototype, "setDate", 1);
addFunction(_datePrototype, "setUTCDate", 1);
addFunction(_datePrototype, "setMonth", 1);
addFunction(_datePrototype, "setUTCMonth", 1);
addFunction(_datePrototype, "setFullYear", 1);
addFunction(_datePrototype, "setUTCFullYear", 1);
addFunction(_datePrototype, "toUTCString", stringValue(), 0);
addFunction(_datePrototype, "toISOString", stringValue(), 0);
addFunction(_datePrototype, "toJSON", stringValue(), 1);
// set up the default Boolean prototype
_regexpPrototype->setProperty("constructor", _regexpCtor);
2010-01-24 11:10:01 +01:00
addFunction(_regexpPrototype, "exec", newArray(), 1);
addFunction(_regexpPrototype, "test", booleanValue(), 1);
addFunction(_regexpPrototype, "toString", stringValue(), 0);
// fill the Global object
_globalObject->setProperty("Math", _mathObject);
_globalObject->setProperty("Object", objectCtor());
_globalObject->setProperty("Function", functionCtor());
_globalObject->setProperty("Array", arrayCtor());
_globalObject->setProperty("String", stringCtor());
_globalObject->setProperty("Boolean", booleanCtor());
_globalObject->setProperty("Number", numberCtor());
_globalObject->setProperty("Date", dateCtor());
_globalObject->setProperty("RegExp", regexpCtor());
//types
_qtObject = newObject(/*prototype */ 0);
addFunction(_qtObject, QLatin1String("rgba"), 4);
addFunction(_qtObject, QLatin1String("hsla"), 4);
addFunction(_qtObject, QLatin1String("rect"), 4);
addFunction(_qtObject, QLatin1String("point"), 2);
addFunction(_qtObject, QLatin1String("size"), 2);
addFunction(_qtObject, QLatin1String("vector3d"), 3);
//color helpers
addFunction(_qtObject, QLatin1String("lighter"), 1);
addFunction(_qtObject, QLatin1String("darker"), 1);
addFunction(_qtObject, QLatin1String("tint"), 2);
//misc methods
addFunction(_qtObject, QLatin1String("closestAngle"), 2);
addFunction(_qtObject, QLatin1String("playSound"), 1);
addFunction(_qtObject, QLatin1String("openUrlExternally"), 1);
addFunction(_qtObject, QLatin1String("md5"), 1);
addFunction(_qtObject, QLatin1String("btoa"), 1);
addFunction(_qtObject, QLatin1String("atob"), 1);
addFunction(_qtObject, QLatin1String("quit"), 0);
addFunction(_qtObject, QLatin1String("resolvedUrl"), 1);
//firebug/webkit compat
ObjectValue *consoleObject = newObject(/*prototype */ 0);
addFunction(consoleObject, QLatin1String("log"), 1);
addFunction(consoleObject, QLatin1String("debug"), 1);
_globalObject->setProperty(QLatin1String("console"), consoleObject);
_globalObject->setProperty(QLatin1String("Qt"), _qtObject);
}
const ObjectValue *Engine::qmlKeysObject()
{
#ifndef NO_DECLARATIVE_BACKEND
return _qmlKeysObject;
#else
return 0;
#endif
}
const Value *Engine::defaultValueForBuiltinType(const QString &typeName) const
{
if (typeName == QLatin1String("string") || typeName == QLatin1String("url"))
return stringValue();
else if (typeName == QLatin1String("bool"))
return booleanValue();
else if (typeName == QLatin1String("int") || typeName == QLatin1String("real"))
return numberValue();
// ### more types...
return undefinedValue();
}
2010-01-24 13:29:46 +01:00
#ifndef NO_DECLARATIVE_BACKEND
QmlObjectValue *Engine::newQmlObject(const QString &name, const QString &prefix, int majorVersion, int minorVersion)
{
if (name == QLatin1String("QDeclarativeAnchors")) {
QmlObjectValue *object = new QmlObjectValue(&QDeclarativeAnchors::staticMetaObject, QLatin1String("Anchors"), -1, -1, this);
2010-01-24 13:29:46 +01:00
return object;
} else if (name == QLatin1String("QDeclarativePen")) {
QmlObjectValue *object = new QmlObjectValue(&QDeclarativePen::staticMetaObject, QLatin1String("Pen"), -1, -1, this);
2010-01-24 19:31:38 +01:00
return object;
} else if (name == QLatin1String("QDeclarativeScaleGrid")) {
QmlObjectValue *object = new QmlObjectValue(&QObject::staticMetaObject, QLatin1String("ScaleGrid"), -1, -1, this);
object->setProperty("left", numberValue());
object->setProperty("top", numberValue());
object->setProperty("right", numberValue());
object->setProperty("bottom", numberValue());
return object;
2010-01-24 13:29:46 +01:00
}
// ### TODO: add support for QML packages
const QString componentName = prefix + QLatin1Char('/') + name;
2010-01-24 13:29:46 +01:00
if (QDeclarativeType *qmlType = QDeclarativeMetaType::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);
2010-01-24 13:29:46 +01:00
return object;
}
return 0;
}
#endif
2010-01-24 13:29:46 +01:00
ASTObjectValue::ASTObjectValue(UiQualifiedId *typeName,
UiObjectInitializer *initializer,
const QmlJS::Document *doc,
Engine *engine)
: ObjectValue(engine), _typeName(typeName), _initializer(initializer), _doc(doc)
{
if (_initializer) {
for (UiObjectMemberList *it = _initializer->members; it; it = it->next) {
UiObjectMember *member = it->member;
if (UiPublicMember *def = cast<UiPublicMember *>(member)) {
if (def->type == UiPublicMember::Property && def->name && def->memberType) {
ASTPropertyReference *ref = new ASTPropertyReference(def, _doc, engine);
_properties.append(ref);
} else if (def->type == UiPublicMember::Signal && def->name) {
ASTSignalReference *ref = new ASTSignalReference(def, _doc, engine);
_signals.append(ref);
}
}
}
}
}
ASTObjectValue::~ASTObjectValue()
{
}
bool ASTObjectValue::getSourceLocation(QString *fileName, int *line, int *column) const
{
*fileName = _doc->fileName();
*line = _typeName->identifierToken.startLine;
*column = _typeName->identifierToken.startColumn;
return true;
}
void ASTObjectValue::processMembers(MemberProcessor *processor) const
{
foreach (ASTPropertyReference *ref, _properties) {
processor->processProperty(ref->ast()->name->asString(), ref);
// ### Should get a different value?
processor->processGeneratedSlot(ref->onChangedSlotName(), ref);
}
foreach (ASTSignalReference *ref, _signals) {
processor->processSignal(ref->ast()->name->asString(), ref);
// ### Should get a different value?
processor->processGeneratedSlot(ref->slotName(), ref);
}
ObjectValue::processMembers(processor);
}
ASTVariableReference::ASTVariableReference(VariableDeclaration *ast, Engine *engine)
: Reference(engine), _ast(ast)
{
}
ASTVariableReference::~ASTVariableReference()
{
}
const Value *ASTVariableReference::value(Context *context) const
{
Evaluate check(context);
return check(_ast->expression);
}
ASTFunctionValue::ASTFunctionValue(FunctionDeclaration *ast, Engine *engine)
: FunctionValue(engine), _ast(ast)
{
setPrototype(engine->functionPrototype());
for (FormalParameterList *it = ast->formals; it; it = it->next)
_argumentNames.append(it->name);
}
ASTFunctionValue::~ASTFunctionValue()
{
}
FunctionDeclaration *ASTFunctionValue::ast() const
{
return _ast;
}
const Value *ASTFunctionValue::returnValue() const
{
return engine()->undefinedValue();
}
int ASTFunctionValue::argumentCount() const
{
return _argumentNames.size();
}
const Value *ASTFunctionValue::argument(int) const
{
return engine()->undefinedValue();
}
QString ASTFunctionValue::argumentName(int index) const
{
if (index < _argumentNames.size()) {
if (NameId *nameId = _argumentNames.at(index))
return nameId->asString();
}
return FunctionValue::argumentName(index);
}
bool ASTFunctionValue::isVariadic() const
{
return true;
}
QmlPrototypeReference::QmlPrototypeReference(UiQualifiedId *qmlTypeName, const QmlJS::Document *doc,
Engine *engine)
: Reference(engine),
_qmlTypeName(qmlTypeName),
_doc(doc)
{
}
QmlPrototypeReference::~QmlPrototypeReference()
{
}
UiQualifiedId *QmlPrototypeReference::qmlTypeName() const
{
return _qmlTypeName;
}
const Value *QmlPrototypeReference::value(Context *context) const
{
return context->lookupType(_doc, _qmlTypeName);
}
ASTPropertyReference::ASTPropertyReference(UiPublicMember *ast, const QmlJS::Document *doc, Engine *engine)
: Reference(engine), _ast(ast), _doc(doc)
{
const QString propertyName = ast->name->asString();
_onChangedSlotName = QLatin1String("on");
_onChangedSlotName += propertyName.at(0).toUpper();
_onChangedSlotName += propertyName.midRef(1);
_onChangedSlotName += QLatin1String("Changed");
}
ASTPropertyReference::~ASTPropertyReference()
{
}
bool ASTPropertyReference::getSourceLocation(QString *fileName, int *line, int *column) const
{
*fileName = _doc->fileName();
*line = _ast->identifierToken.startLine;
*column = _ast->identifierToken.startColumn;
return true;
}
const Value *ASTPropertyReference::value(Context *context) const
{
if (_ast->expression) {
Evaluate check(context);
return check(_ast->expression);
}
if (_ast->memberType)
return engine()->defaultValueForBuiltinType(_ast->memberType->asString());
return engine()->undefinedValue();
}
ASTSignalReference::ASTSignalReference(UiPublicMember *ast, const QmlJS::Document *doc, Engine *engine)
: Reference(engine), _ast(ast), _doc(doc)
{
const QString signalName = ast->name->asString();
_slotName = QLatin1String("on");
_slotName += signalName.at(0).toUpper();
_slotName += signalName.midRef(1);
}
ASTSignalReference::~ASTSignalReference()
{
}
bool ASTSignalReference::getSourceLocation(QString *fileName, int *line, int *column) const
{
*fileName = _doc->fileName();
*line = _ast->identifierToken.startLine;
*column = _ast->identifierToken.startColumn;
return true;
}
2010-02-17 08:58:33 +01:00
const Value *ASTSignalReference::value(Context *) const
{
return engine()->undefinedValue();
}