2010-01-21 15:54:19 +01:00
|
|
|
/**************************************************************************
|
|
|
|
**
|
|
|
|
** 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"
|
2010-01-24 19:31:38 +01:00
|
|
|
|
|
|
|
#include <QtCore/QMetaObject>
|
|
|
|
#include <QtCore/QMetaProperty>
|
2010-01-21 15:54:19 +01:00
|
|
|
#include <QtCore/QDebug>
|
|
|
|
|
2010-01-24 13:29:46 +01:00
|
|
|
#ifndef NO_DECLARATIVE_BACKEND
|
|
|
|
# include <QtDeclarative/QmlType>
|
|
|
|
# include <QtDeclarative/QmlMetaType>
|
|
|
|
# include <QtDeclarative/private/qmlgraphicsanchors_p.h> // ### remove me
|
2010-01-24 19:31:38 +01:00
|
|
|
# include <QtDeclarative/private/qmlgraphicsrectangle_p.h> // ### remove me
|
|
|
|
# include <QtDeclarative/private/qmlvaluetype_p.h> // ### remove me
|
2010-01-24 13:29:46 +01:00
|
|
|
#endif
|
|
|
|
|
2010-01-21 15:54:19 +01:00
|
|
|
using namespace QmlJS::Interpreter;
|
|
|
|
|
2010-01-24 11:10:01 +01:00
|
|
|
namespace {
|
|
|
|
|
2010-01-24 13:29:46 +01:00
|
|
|
#ifndef NO_DECLARATIVE_BACKEND
|
|
|
|
|
2010-01-26 11:06:28 +01:00
|
|
|
class QmlAttachedKeys: public ObjectValue
|
|
|
|
{
|
|
|
|
static const char **builtinPropertyNames()
|
|
|
|
{
|
|
|
|
static const char *properties[] = {
|
|
|
|
"enabledChanged",
|
|
|
|
"pressed",
|
|
|
|
"released",
|
|
|
|
"digit0Pressed",
|
|
|
|
"digit1Pressed",
|
|
|
|
"digit2Pressed",
|
|
|
|
"digit3Pressed",
|
|
|
|
"digit4Pressed",
|
|
|
|
"digit5Pressed",
|
|
|
|
"digit6Pressed",
|
|
|
|
"digit7Pressed",
|
|
|
|
"digit8Pressed",
|
|
|
|
"digit9Pressed",
|
|
|
|
"leftPressed",
|
|
|
|
"rightPressed",
|
|
|
|
"upPressed",
|
|
|
|
"downPressed",
|
|
|
|
"asteriskPressed",
|
|
|
|
"numberSignPressed",
|
|
|
|
"escapePressed",
|
|
|
|
"returnPressed",
|
|
|
|
"enterPressed",
|
|
|
|
"deletePressed",
|
|
|
|
"spacePressed",
|
|
|
|
"backPressed",
|
|
|
|
"cancelPressed",
|
|
|
|
"selectPressed",
|
|
|
|
"yesPressed",
|
|
|
|
"noPressed",
|
|
|
|
"context1Pressed",
|
|
|
|
"context2Pressed",
|
|
|
|
"context3Pressed",
|
|
|
|
"context4Pressed",
|
|
|
|
"callPressed",
|
|
|
|
"hangupPressed",
|
|
|
|
"flipPressed",
|
|
|
|
"menuPressed",
|
|
|
|
"volumeUpPressed",
|
|
|
|
"volumeDownPressed",
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
return properties;
|
|
|
|
}
|
|
|
|
|
|
|
|
QSet<QString> _generatedSlots;
|
|
|
|
|
|
|
|
public:
|
|
|
|
QmlAttachedKeys(Engine *engine)
|
|
|
|
: ObjectValue(engine)
|
|
|
|
{
|
|
|
|
for (const char **it = builtinPropertyNames(); *it; ++it) {
|
|
|
|
QString signalName = QLatin1String(*it);
|
|
|
|
QString generatedSlot = QLatin1String("on");
|
|
|
|
generatedSlot += signalName.at(0).toUpper();
|
|
|
|
generatedSlot += signalName.midRef(1);
|
|
|
|
_generatedSlots.insert(generatedSlot);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void processMembers(MemberProcessor *processor) const
|
|
|
|
{
|
|
|
|
foreach (const QString &generatedSlot, _generatedSlots)
|
|
|
|
processor->processSlot(generatedSlot, engine()->undefinedValue());
|
|
|
|
|
|
|
|
ObjectValue::processMembers(processor);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2010-01-26 10:50:30 +01:00
|
|
|
class MetaFunction: public FunctionValue
|
|
|
|
{
|
|
|
|
QMetaMethod _method;
|
|
|
|
|
|
|
|
public:
|
|
|
|
MetaFunction(const QMetaMethod &method, Engine *engine)
|
|
|
|
: FunctionValue(engine), _method(method)
|
|
|
|
{
|
|
|
|
engine->registerObject(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
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-01-24 13:29:46 +01:00
|
|
|
class QmlObjectValue: public ObjectValue
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
QmlObjectValue(const QMetaObject *metaObject, Engine *engine)
|
2010-01-26 10:50:30 +01:00
|
|
|
: ObjectValue(engine), _metaObject(metaObject)
|
|
|
|
{
|
|
|
|
}
|
2010-01-24 13:29:46 +01:00
|
|
|
|
|
|
|
virtual ~QmlObjectValue() {}
|
|
|
|
|
|
|
|
virtual const Value *lookupMember(const QString &name) const
|
|
|
|
{
|
|
|
|
for (int index = 0; index < _metaObject->propertyCount(); ++index) {
|
|
|
|
QMetaProperty prop = _metaObject->property(index);
|
|
|
|
|
|
|
|
if (name == QString::fromUtf8(prop.name()))
|
|
|
|
return propertyValue(prop);
|
|
|
|
}
|
|
|
|
|
2010-01-26 10:50:30 +01:00
|
|
|
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 (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());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-24 13:29:46 +01:00
|
|
|
return ObjectValue::lookupMember(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void processMembers(MemberProcessor *processor) const
|
|
|
|
{
|
|
|
|
for (int index = 0; index < _metaObject->propertyCount(); ++index) {
|
|
|
|
QMetaProperty prop = _metaObject->property(index);
|
|
|
|
|
2010-01-26 10:10:11 +01:00
|
|
|
processor->processProperty(prop.name(), propertyValue(prop));
|
2010-01-24 13:29:46 +01:00
|
|
|
}
|
2010-01-25 14:48:44 +01:00
|
|
|
|
|
|
|
for (int index = 0; index < _metaObject->methodCount(); ++index) {
|
2010-01-26 10:50:30 +01:00
|
|
|
QMetaMethod method = _metaObject->method(index);
|
2010-01-26 10:10:11 +01:00
|
|
|
|
2010-01-26 10:50:30 +01:00
|
|
|
const QString signature = QString::fromUtf8(method.signature());
|
2010-01-25 14:48:44 +01:00
|
|
|
|
2010-01-26 10:19:42 +01:00
|
|
|
const int indexOfParen = signature.indexOf(QLatin1Char('('));
|
2010-01-25 14:48:44 +01:00
|
|
|
if (indexOfParen == -1)
|
|
|
|
continue; // skip it, invalid signature.
|
|
|
|
|
2010-01-26 10:19:42 +01:00
|
|
|
const QString methodName = signature.left(indexOfParen);
|
2010-01-26 10:10:11 +01:00
|
|
|
|
2010-01-26 10:50:30 +01:00
|
|
|
if (method.methodType() == QMetaMethod::Slot && method.access() == QMetaMethod::Public) {
|
2010-01-26 10:19:42 +01:00
|
|
|
processor->processSlot(methodName, engine()->undefinedValue());
|
|
|
|
|
2010-01-26 10:50:30 +01:00
|
|
|
} else if (method.methodType() == QMetaMethod::Signal && method.access() != QMetaMethod::Private) {
|
2010-01-26 10:19:42 +01:00
|
|
|
// process the signal
|
2010-01-26 10:50:30 +01:00
|
|
|
processor->processSignal(methodName, engine()->undefinedValue());
|
2010-01-26 10:19:42 +01:00
|
|
|
|
|
|
|
QString slotName;
|
|
|
|
slotName += QLatin1String("on");
|
|
|
|
slotName += methodName.at(0).toUpper();
|
|
|
|
slotName += methodName.midRef(1);
|
|
|
|
|
|
|
|
// process the generated slot
|
2010-01-26 10:50:30 +01:00
|
|
|
processor->processGeneratedSlot(slotName, engine()->undefinedValue());
|
2010-01-26 10:19:42 +01:00
|
|
|
}
|
2010-01-25 14:48:44 +01:00
|
|
|
}
|
|
|
|
|
2010-01-25 15:48:49 +01:00
|
|
|
ObjectValue::processMembers(processor);
|
2010-01-24 13:29:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const Value *propertyValue(const QMetaProperty &prop) const {
|
|
|
|
const Value *value = engine()->undefinedValue();
|
|
|
|
|
|
|
|
if (QmlMetaType::isObject(prop.userType())) {
|
|
|
|
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))
|
|
|
|
return objectValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (prop.type()) {
|
|
|
|
case QMetaType::QByteArray:
|
|
|
|
case QMetaType::QString:
|
2010-01-25 15:05:23 +01:00
|
|
|
case QMetaType::QUrl:
|
2010-01-24 13:29:46 +01:00
|
|
|
value = engine()->stringValue();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QMetaType::Bool:
|
|
|
|
value = engine()->booleanValue();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QMetaType::Int:
|
|
|
|
case QMetaType::Float:
|
|
|
|
case QMetaType::Double:
|
|
|
|
value = engine()->numberValue();
|
|
|
|
break;
|
|
|
|
|
2010-01-25 16:42:31 +01:00
|
|
|
case QMetaType::QFont: {
|
|
|
|
// ### cache
|
|
|
|
ObjectValue *object = engine()->newObject(/*prototype =*/ 0);
|
2010-01-26 12:31:01 +01:00
|
|
|
object->setProperty("family", engine()->stringValue());
|
2010-01-25 16:42:31 +01:00
|
|
|
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;
|
|
|
|
|
2010-01-25 15:05:23 +01:00
|
|
|
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;
|
|
|
|
|
2010-01-24 13:29:46 +01:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
} // end of switch
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
const QMetaObject *_metaObject;
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
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
|
|
|
|
|
2010-01-21 15:54:19 +01:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// 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 *)
|
|
|
|
{
|
|
|
|
}
|
2010-01-21 15:54:19 +01:00
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Value
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
2010-01-24 11:10:01 +01:00
|
|
|
Value::Value()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Value::~Value()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2010-01-21 15:54:19 +01:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Environment
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
2010-01-24 11:10:01 +01:00
|
|
|
Environment::Environment()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Environment::~Environment()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
const Environment *Environment::parent() const
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2010-01-21 15:54:19 +01:00
|
|
|
|
|
|
|
const Value *Environment::lookup(const QString &name) const
|
|
|
|
{
|
|
|
|
if (const Value *member = lookupMember(name))
|
|
|
|
return member;
|
|
|
|
|
|
|
|
else if (const Environment *p = parent())
|
|
|
|
return p->lookup(name);
|
|
|
|
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const Value *Environment::lookupMember(const QString &name) const {
|
|
|
|
Q_UNUSED(name);
|
|
|
|
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-21 15:54:19 +01:00
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2010-01-26 10:10:11 +01:00
|
|
|
MemberProcessor::MemberProcessor()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
MemberProcessor::~MemberProcessor()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MemberProcessor::processProperty(const QString &, const Value *)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MemberProcessor::processSignal(const QString &, const Value *)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MemberProcessor::processSlot(const QString &, const Value *)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-01-26 10:19:42 +01:00
|
|
|
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), _scope(0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
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() const
|
|
|
|
{
|
|
|
|
return _prototype;
|
|
|
|
}
|
|
|
|
|
|
|
|
const ObjectValue *ObjectValue::scope() const
|
|
|
|
{
|
|
|
|
return _scope;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ObjectValue::setScope(const ObjectValue *scope)
|
|
|
|
{
|
|
|
|
_scope = scope;
|
|
|
|
}
|
|
|
|
|
|
|
|
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) const
|
|
|
|
{
|
2010-01-21 15:54:19 +01:00
|
|
|
return lookupMember(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ObjectValue::setPrototype(const ObjectValue *prototype)
|
|
|
|
{
|
|
|
|
QSet<const ObjectValue *> processed;
|
|
|
|
|
2010-01-24 11:10:01 +01:00
|
|
|
if (! prototype || checkPrototype(prototype, &processed))
|
2010-01-21 15:54:19 +01:00
|
|
|
_prototype = prototype;
|
|
|
|
else
|
|
|
|
qWarning() << "**** invalid prototype:";
|
|
|
|
}
|
|
|
|
|
2010-01-24 11:10:01 +01:00
|
|
|
bool ObjectValue::checkPrototype(const ObjectValue *proto, QSet<const ObjectValue *> *processed) const
|
2010-01-21 15:54:19 +01:00
|
|
|
{
|
|
|
|
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))
|
2010-01-21 15:54:19 +01:00
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
2010-01-26 10:10:11 +01:00
|
|
|
if (! processor->processProperty(it.key(), it.value()))
|
2010-01-24 11:10:01 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const Environment *ObjectValue::parent() const
|
|
|
|
{
|
|
|
|
return _scope;
|
|
|
|
}
|
|
|
|
|
|
|
|
const Value *ObjectValue::lookupMember(const QString &name) const
|
|
|
|
{
|
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;
|
|
|
|
|
|
|
|
if (_prototype) {
|
|
|
|
if (const Value *m = _prototype->lookup(name))
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-01-24 11:35:11 +01:00
|
|
|
Activation::Activation(Engine *engine)
|
|
|
|
: ObjectValue(engine),
|
|
|
|
_thisObject(0),
|
|
|
|
_calledAsFunction(true)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Activation::~Activation()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
{
|
2010-01-24 11:35:11 +01:00
|
|
|
Activation activation(engine()); // ### FIXME: create on the heap
|
|
|
|
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
|
|
|
|
{
|
2010-01-24 11:35:11 +01:00
|
|
|
Activation activation(engine()); // ### FIXME: create on the heap
|
|
|
|
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
|
|
|
|
{
|
2010-01-24 11:35:11 +01:00
|
|
|
Activation activation(engine()); // ### FIXME: create on the heap
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2010-01-26 10:50:30 +01:00
|
|
|
const Value *FunctionValue::returnValue() const
|
|
|
|
{
|
|
|
|
return engine()->undefinedValue();
|
|
|
|
}
|
|
|
|
|
2010-01-24 11:10:01 +01:00
|
|
|
int FunctionValue::argumentCount() const
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-01-26 10:50:30 +01:00
|
|
|
const Value *FunctionValue::argument(int) const
|
|
|
|
{
|
|
|
|
return engine()->undefinedValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
QString FunctionValue::argumentName(int index) const
|
|
|
|
{
|
|
|
|
return QString::fromLatin1("arg%1").arg(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
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-21 15:54:19 +01:00
|
|
|
{
|
2010-01-24 11:10:01 +01:00
|
|
|
setClassName("Function");
|
2010-01-21 15:54:19 +01:00
|
|
|
}
|
|
|
|
|
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-21 15:54:19 +01:00
|
|
|
{
|
2010-01-24 11:10:01 +01:00
|
|
|
_arguments.push_back(argument);
|
2010-01-21 15:54:19 +01:00
|
|
|
}
|
|
|
|
|
2010-01-24 11:10:01 +01:00
|
|
|
const Value *Function::returnValue() const
|
2010-01-21 15:54:19 +01:00
|
|
|
{
|
2010-01-24 11:10:01 +01:00
|
|
|
return _returnValue;
|
2010-01-21 15:54:19 +01:00
|
|
|
}
|
|
|
|
|
2010-01-24 11:10:01 +01:00
|
|
|
void Function::setReturnValue(const Value *returnValue)
|
|
|
|
{
|
|
|
|
_returnValue = returnValue;
|
|
|
|
}
|
2010-01-21 15:54:19 +01:00
|
|
|
|
2010-01-24 11:10:01 +01:00
|
|
|
int Function::argumentCount() const
|
|
|
|
{
|
|
|
|
return _arguments.size();
|
|
|
|
}
|
2010-01-21 15:54:19 +01:00
|
|
|
|
2010-01-24 11:10:01 +01:00
|
|
|
const Value *Function::argument(int index) const
|
|
|
|
{
|
|
|
|
return _arguments.at(index);
|
|
|
|
}
|
2010-01-21 15:54:19 +01:00
|
|
|
|
|
|
|
const Value *Function::property(const QString &name) const
|
|
|
|
{
|
|
|
|
if (name == "length")
|
|
|
|
return engine()->numberValue();
|
|
|
|
|
|
|
|
return FunctionValue::property(name);
|
|
|
|
}
|
|
|
|
|
2010-01-24 11:35:11 +01:00
|
|
|
const Value *Function::invoke(const Activation *activation) const
|
2010-01-21 15:54:19 +01:00
|
|
|
{
|
2010-01-24 11:35:11 +01:00
|
|
|
return activation->thisObject(); // ### FIXME it should return undefined
|
2010-01-21 15:54:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// typing environment
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
2010-01-24 11:10:01 +01:00
|
|
|
ConvertToNumber::ConvertToNumber(Engine *engine)
|
|
|
|
: _engine(engine), _result(0)
|
|
|
|
{
|
|
|
|
}
|
2010-01-21 15:54:19 +01:00
|
|
|
|
2010-01-24 11:10:01 +01:00
|
|
|
const Value *ConvertToNumber::operator()(const Value *value)
|
|
|
|
{
|
2010-01-21 15:54:19 +01:00
|
|
|
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)
|
|
|
|
{
|
2010-01-21 15:54:19 +01:00
|
|
|
const Value *previousResult = _result;
|
|
|
|
_result = value;
|
|
|
|
return previousResult;
|
|
|
|
}
|
|
|
|
|
2010-01-24 11:10:01 +01:00
|
|
|
ConvertToString::ConvertToString(Engine *engine)
|
|
|
|
: _engine(engine), _result(0)
|
|
|
|
{
|
|
|
|
}
|
2010-01-21 15:54:19 +01:00
|
|
|
|
2010-01-24 11:10:01 +01:00
|
|
|
const Value *ConvertToString::operator()(const Value *value)
|
|
|
|
{
|
2010-01-21 15:54:19 +01:00
|
|
|
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)
|
|
|
|
{
|
2010-01-21 15:54:19 +01:00
|
|
|
const Value *previousResult = _result;
|
|
|
|
_result = value;
|
|
|
|
return previousResult;
|
|
|
|
}
|
|
|
|
|
2010-01-22 14:42:15 +01:00
|
|
|
ConvertToObject::ConvertToObject(Engine *engine)
|
|
|
|
: _engine(engine), _result(0)
|
|
|
|
{
|
|
|
|
}
|
2010-01-21 15:54:19 +01:00
|
|
|
|
2010-01-24 11:10:01 +01:00
|
|
|
const Value *ConvertToObject::operator()(const Value *value)
|
|
|
|
{
|
2010-01-21 15:54:19 +01:00
|
|
|
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)
|
|
|
|
{
|
2010-01-21 15:54:19 +01:00
|
|
|
const Value *previousResult = _result;
|
|
|
|
_result = value;
|
|
|
|
return previousResult;
|
|
|
|
}
|
|
|
|
|
2010-01-22 14:42:15 +01:00
|
|
|
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-22 14:42:15 +01:00
|
|
|
{
|
2010-01-24 11:10:01 +01:00
|
|
|
ValueList actuals;
|
|
|
|
actuals.append(value);
|
|
|
|
_result = _engine->numberCtor()->construct(actuals);
|
2010-01-22 14:42:15 +01:00
|
|
|
}
|
|
|
|
|
2010-01-24 11:10:01 +01:00
|
|
|
void ConvertToObject::visit(const BooleanValue *value)
|
2010-01-22 14:42:15 +01:00
|
|
|
{
|
2010-01-24 11:10:01 +01:00
|
|
|
ValueList actuals;
|
|
|
|
actuals.append(value);
|
|
|
|
_result = _engine->booleanCtor()->construct(actuals);
|
2010-01-22 14:42:15 +01:00
|
|
|
}
|
|
|
|
|
2010-01-24 11:10:01 +01:00
|
|
|
void ConvertToObject::visit(const StringValue *value)
|
2010-01-22 14:42:15 +01:00
|
|
|
{
|
2010-01-24 11:10:01 +01:00
|
|
|
ValueList actuals;
|
|
|
|
actuals.append(value);
|
|
|
|
_result = _engine->stringCtor()->construct(actuals);
|
2010-01-22 14:42:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void ConvertToObject::visit(const ObjectValue *object)
|
|
|
|
{
|
|
|
|
_result = object;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ConvertToObject::visit(const FunctionValue *object)
|
|
|
|
{
|
|
|
|
_result = object;
|
|
|
|
}
|
2010-01-21 15:54:19 +01:00
|
|
|
|
|
|
|
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-21 15:54:19 +01:00
|
|
|
{
|
2010-01-24 11:10:01 +01:00
|
|
|
_result = QLatin1String("null");
|
|
|
|
}
|
2010-01-21 15:54:19 +01:00
|
|
|
|
2010-01-24 11:10:01 +01:00
|
|
|
void TypeId::visit(const UndefinedValue *)
|
2010-01-21 15:54:19 +01:00
|
|
|
{
|
2010-01-24 11:10:01 +01:00
|
|
|
_result = QLatin1String("undefined");
|
|
|
|
}
|
2010-01-21 15:54:19 +01:00
|
|
|
|
2010-01-24 11:10:01 +01:00
|
|
|
void TypeId::visit(const NumberValue *)
|
2010-01-21 15:54:19 +01:00
|
|
|
{
|
2010-01-24 11:10:01 +01:00
|
|
|
_result = QLatin1String("number");
|
|
|
|
}
|
2010-01-21 15:54:19 +01:00
|
|
|
|
2010-01-24 11:10:01 +01:00
|
|
|
void TypeId::visit(const BooleanValue *)
|
2010-01-21 15:54:19 +01:00
|
|
|
{
|
2010-01-24 11:10:01 +01:00
|
|
|
_result = QLatin1String("boolean");
|
|
|
|
}
|
2010-01-21 15:54:19 +01:00
|
|
|
|
2010-01-24 11:10:01 +01:00
|
|
|
void TypeId::visit(const StringValue *)
|
2010-01-21 15:54:19 +01:00
|
|
|
{
|
2010-01-24 11:10:01 +01:00
|
|
|
_result = QLatin1String("string");
|
|
|
|
}
|
2010-01-21 15:54:19 +01:00
|
|
|
|
2010-01-24 11:10:01 +01:00
|
|
|
void TypeId::visit(const ObjectValue *object)
|
2010-01-21 15:54:19 +01:00
|
|
|
{
|
2010-01-24 11:10:01 +01:00
|
|
|
_result = object->className();
|
2010-01-21 15:54:19 +01:00
|
|
|
|
2010-01-24 11:10:01 +01:00
|
|
|
if (_result.isEmpty())
|
|
|
|
_result = QLatin1String("object");
|
|
|
|
}
|
2010-01-21 15:54:19 +01:00
|
|
|
|
2010-01-24 11:10:01 +01:00
|
|
|
void TypeId::visit(const FunctionValue *object)
|
2010-01-21 15:54:19 +01:00
|
|
|
{
|
2010-01-24 11:10:01 +01:00
|
|
|
_result = object->className();
|
2010-01-21 15:54:19 +01:00
|
|
|
|
2010-01-24 11:10:01 +01:00
|
|
|
if (_result.isEmpty())
|
|
|
|
_result = QLatin1String("Function");
|
|
|
|
}
|
2010-01-21 15:54:19 +01:00
|
|
|
|
|
|
|
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),
|
2010-01-26 12:06:44 +01:00
|
|
|
#ifndef NO_DECLARATIVE_BACKEND
|
2010-01-26 11:06:28 +01:00
|
|
|
_qmlKeysObject(0),
|
2010-01-26 12:06:44 +01:00
|
|
|
#endif
|
2010-01-21 15:54:19 +01:00
|
|
|
_convertToNumber(this),
|
|
|
|
_convertToString(this),
|
|
|
|
_convertToObject(this)
|
|
|
|
{
|
|
|
|
|
|
|
|
initializePrototypes();
|
|
|
|
}
|
|
|
|
|
2010-01-24 11:10:01 +01:00
|
|
|
Engine::~Engine()
|
|
|
|
{
|
2010-01-21 15:54:19 +01:00
|
|
|
QList<ObjectValue *>::iterator it = _objects.begin();
|
|
|
|
|
|
|
|
for (; it != _objects.end(); ++it)
|
|
|
|
delete *it;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
2010-01-21 15:54:19 +01:00
|
|
|
|
2010-01-24 11:10:01 +01:00
|
|
|
const Value *Engine::newArray()
|
|
|
|
{
|
|
|
|
return arrayCtor()->construct();
|
|
|
|
}
|
2010-01-21 15:54:19 +01:00
|
|
|
|
|
|
|
ObjectValue *Engine::newObject()
|
|
|
|
{
|
|
|
|
return newObject(_objectPrototype);
|
|
|
|
}
|
|
|
|
|
|
|
|
ObjectValue *Engine::newObject(const ObjectValue *prototype)
|
|
|
|
{
|
|
|
|
ObjectValue *object = new ObjectValue(this);
|
|
|
|
object->setPrototype(prototype);
|
|
|
|
_objects.push_back(object);
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
|
|
|
Function *Engine::newFunction() {
|
|
|
|
Function *function = new Function(this);
|
|
|
|
function->setPrototype(functionPrototype());
|
|
|
|
_objects.push_back(function);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-01-26 10:50:30 +01:00
|
|
|
void Engine::registerObject(ObjectValue *object)
|
|
|
|
{
|
|
|
|
_objects.append(object);
|
|
|
|
}
|
|
|
|
|
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-21 15:54:19 +01:00
|
|
|
|
2010-01-24 11:10:01 +01:00
|
|
|
const Value *Engine::convertToObject(const Value *value)
|
2010-01-21 15:54:19 +01:00
|
|
|
{
|
2010-01-24 11:10:01 +01:00
|
|
|
return _convertToObject(value);
|
2010-01-21 15:54:19 +01:00
|
|
|
}
|
|
|
|
|
2010-01-24 11:10:01 +01:00
|
|
|
QString Engine::typeId(const Value *value)
|
2010-01-21 15:54:19 +01:00
|
|
|
{
|
2010-01-24 11:10:01 +01:00
|
|
|
return _typeId(value);
|
2010-01-21 15:54:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
_objects.push_back(_objectCtor);
|
|
|
|
_objectCtor->setProperty("prototype", _objectPrototype);
|
|
|
|
|
|
|
|
_functionCtor = new FunctionCtor(this);
|
|
|
|
_functionCtor->setPrototype(_functionPrototype);
|
|
|
|
_objects.push_back(_functionCtor);
|
|
|
|
_functionCtor->setProperty("prototype", _functionPrototype);
|
|
|
|
|
|
|
|
_arrayCtor = new ArrayCtor(this);
|
|
|
|
_arrayCtor->setPrototype(_functionPrototype);
|
|
|
|
_objects.push_back(_arrayCtor);
|
|
|
|
_arrayCtor->setProperty("prototype", _arrayPrototype);
|
|
|
|
|
|
|
|
_stringCtor = new StringCtor(this);
|
|
|
|
_stringCtor->setPrototype(_functionPrototype);
|
|
|
|
_objects.push_back(_stringCtor);
|
|
|
|
_stringCtor->setProperty("prototype", _stringPrototype);
|
|
|
|
|
|
|
|
_booleanCtor = new BooleanCtor(this);
|
|
|
|
_booleanCtor->setPrototype(_functionPrototype);
|
|
|
|
_objects.push_back(_booleanCtor);
|
|
|
|
_booleanCtor->setProperty("prototype", _booleanPrototype);
|
|
|
|
|
|
|
|
_numberCtor = new NumberCtor(this);
|
|
|
|
_numberCtor->setPrototype(_functionPrototype);
|
|
|
|
_objects.push_back(_numberCtor);
|
|
|
|
_numberCtor->setProperty("prototype", _numberPrototype);
|
|
|
|
|
|
|
|
_dateCtor = new DateCtor(this);
|
|
|
|
_dateCtor->setPrototype(_functionPrototype);
|
|
|
|
_objects.push_back(_dateCtor);
|
|
|
|
_dateCtor->setProperty("prototype", _datePrototype);
|
|
|
|
|
|
|
|
_regexpCtor = new RegExpCtor(this);
|
|
|
|
_regexpCtor->setPrototype(_functionPrototype);
|
|
|
|
_objects.push_back(_regexpCtor);
|
|
|
|
_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);
|
2010-01-21 15:54:19 +01:00
|
|
|
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);
|
2010-01-21 15:54:19 +01:00
|
|
|
|
|
|
|
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
|
2010-01-21 15:54:19 +01:00
|
|
|
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);
|
2010-01-21 15:54:19 +01:00
|
|
|
addFunction(_stringPrototype, "replace", stringValue(), 2);
|
|
|
|
addFunction(_stringPrototype, "search", numberValue(), 1);
|
|
|
|
addFunction(_stringPrototype, "slice", stringValue(), 2);
|
2010-01-26 12:38:52 +01:00
|
|
|
addFunction(_stringPrototype, "split", newArray(), 1);
|
2010-01-21 15:54:19 +01:00
|
|
|
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);
|
2010-01-26 10:50:30 +01:00
|
|
|
addFunction(_mathObject, "max", numberValue(), 0);
|
|
|
|
addFunction(_mathObject, "min", numberValue(), 0);
|
2010-01-21 15:54:19 +01:00
|
|
|
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);
|
2010-01-21 15:54:19 +01:00
|
|
|
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());
|
2010-01-26 11:06:28 +01:00
|
|
|
|
2010-01-26 12:06:44 +01:00
|
|
|
#ifndef NO_DECLARATIVE_BACKEND
|
2010-01-26 11:06:28 +01:00
|
|
|
_qmlKeysObject = new QmlAttachedKeys(this);
|
|
|
|
_globalObject->setProperty("Keys", _qmlKeysObject); // ### attach it to the current scope, and not to the global object
|
|
|
|
registerObject(_qmlKeysObject);
|
2010-01-26 12:06:44 +01:00
|
|
|
#endif
|
2010-01-26 11:06:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const ObjectValue *Engine::qmlKeysObject()
|
|
|
|
{
|
2010-01-26 12:06:44 +01:00
|
|
|
#ifndef NO_DECLARATIVE_BACKEND
|
2010-01-26 11:06:28 +01:00
|
|
|
return _qmlKeysObject;
|
2010-01-26 12:06:44 +01:00
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
2010-01-21 15:54:19 +01:00
|
|
|
}
|
|
|
|
|
2010-01-26 11:15:21 +01:00
|
|
|
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 18:11:25 +01:00
|
|
|
ObjectValue *Engine::newQmlObject(const QString &name)
|
2010-01-24 13:29:46 +01:00
|
|
|
{
|
|
|
|
#ifndef NO_DECLARATIVE_BACKEND
|
|
|
|
if (name == QLatin1String("QmlGraphicsAnchors")) {
|
|
|
|
QmlObjectValue *object = new QmlObjectValue(&QmlGraphicsAnchors::staticMetaObject, this);
|
|
|
|
_objects.append(object);
|
|
|
|
return object;
|
2010-01-24 19:31:38 +01:00
|
|
|
} else if (name == QLatin1String("QmlGraphicsPen")) {
|
|
|
|
QmlObjectValue *object = new QmlObjectValue(&QmlGraphicsPen::staticMetaObject, this);
|
|
|
|
_objects.append(object);
|
|
|
|
return object;
|
2010-01-25 15:05:23 +01:00
|
|
|
} else if (name == QLatin1String("QmlGraphicsScaleGrid")) {
|
|
|
|
ObjectValue *object = newObject(/*prototype =*/ 0);
|
|
|
|
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
|
|
|
|
QString componentName;
|
|
|
|
componentName += QLatin1String("Qt/");
|
|
|
|
componentName += name;
|
|
|
|
componentName.replace(QLatin1Char('.'), QLatin1Char('/'));
|
|
|
|
|
|
|
|
if (QmlType *qmlType = QmlMetaType::qmlType(componentName.toUtf8(), 4, 6)) {
|
|
|
|
QmlObjectValue *object = new QmlObjectValue(qmlType->metaObject(), this);
|
|
|
|
_objects.append(object);
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2010-01-25 09:40:00 +01:00
|
|
|
#else
|
|
|
|
return newObject(/*prototype = */ 0);
|
|
|
|
#endif
|
2010-01-24 13:29:46 +01:00
|
|
|
}
|
|
|
|
|
2010-01-21 15:54:19 +01:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// convert to number
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
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->lookup("valueOf"))) {
|
2010-01-24 11:35:11 +01:00
|
|
|
_result = value_cast<const NumberValue *>(valueOfMember->call(object)); // ### invoke convert-to-number?
|
2010-01-21 15:54:19 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ConvertToNumber::visit(const FunctionValue *object)
|
|
|
|
{
|
|
|
|
if (const FunctionValue *valueOfMember = value_cast<const FunctionValue *>(object->lookup("valueOf"))) {
|
2010-01-24 11:35:11 +01:00
|
|
|
_result = value_cast<const NumberValue *>(valueOfMember->call(object)); // ### invoke convert-to-number?
|
2010-01-21 15:54:19 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// convert to string
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
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->lookup("toString"))) {
|
2010-01-24 11:35:11 +01:00
|
|
|
_result = value_cast<const StringValue *>(toStringMember->call(object)); // ### invoke convert-to-string?
|
2010-01-21 15:54:19 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ConvertToString::visit(const FunctionValue *object)
|
|
|
|
{
|
|
|
|
if (const FunctionValue *toStringMember = value_cast<const FunctionValue *>(object->lookup("toString"))) {
|
2010-01-24 11:35:11 +01:00
|
|
|
_result = value_cast<const StringValue *>(toStringMember->call(object)); // ### invoke convert-to-string?
|
2010-01-21 15:54:19 +01:00
|
|
|
}
|
|
|
|
}
|