2012-04-16 19:23:25 +00:00
|
|
|
|
|
|
|
#include "qmljs_objects.h"
|
2012-05-07 14:05:05 +00:00
|
|
|
#include "qv4ir_p.h"
|
2012-05-14 15:12:25 +00:00
|
|
|
#include "qv4ecmaobjects_p.h"
|
2012-05-07 14:05:05 +00:00
|
|
|
#include <QtCore/QDebug>
|
2012-04-16 19:23:25 +00:00
|
|
|
#include <cassert>
|
|
|
|
|
2012-05-04 13:28:04 +00:00
|
|
|
using namespace QQmlJS::VM;
|
|
|
|
|
2012-05-04 13:12:37 +00:00
|
|
|
Object::~Object()
|
|
|
|
{
|
|
|
|
delete members;
|
|
|
|
}
|
|
|
|
|
2012-05-14 14:03:10 +00:00
|
|
|
void Object::setProperty(Context *ctx, const QString &name, const Value &value)
|
|
|
|
{
|
2012-05-14 15:12:25 +00:00
|
|
|
put(ctx->engine->identifier(name), value);
|
2012-05-14 14:03:10 +00:00
|
|
|
}
|
|
|
|
|
2012-05-14 15:38:53 +00:00
|
|
|
void Object::setProperty(Context *ctx, const QString &name, void (*code)(Context *), int count)
|
2012-05-14 14:03:10 +00:00
|
|
|
{
|
2012-05-14 15:38:53 +00:00
|
|
|
Q_UNUSED(count);
|
2012-05-15 08:53:20 +00:00
|
|
|
setProperty(ctx, name, Value::fromObject(ctx->engine->newNativeFunction(ctx, code)));
|
2012-05-14 14:03:10 +00:00
|
|
|
}
|
|
|
|
|
2012-04-16 19:23:25 +00:00
|
|
|
bool Object::get(String *name, Value *result)
|
|
|
|
{
|
2012-05-08 09:13:02 +00:00
|
|
|
if (Value *prop = getProperty(name)) {
|
|
|
|
*result = *prop;
|
2012-04-16 19:23:25 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-05-15 08:53:20 +00:00
|
|
|
__qmljs_init_undefined(result);
|
2012-04-16 19:23:25 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-05-08 09:13:02 +00:00
|
|
|
Value *Object::getOwnProperty(String *name, PropertyAttributes *attributes)
|
2012-04-16 19:23:25 +00:00
|
|
|
{
|
|
|
|
if (members) {
|
|
|
|
if (Property *prop = members->find(name)) {
|
2012-05-08 09:13:02 +00:00
|
|
|
if (attributes)
|
|
|
|
*attributes = prop->attributes;
|
|
|
|
return &prop->value;
|
2012-04-16 19:23:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-05-08 09:13:02 +00:00
|
|
|
Value *Object::getProperty(String *name, PropertyAttributes *attributes)
|
2012-04-16 19:23:25 +00:00
|
|
|
{
|
2012-05-08 09:13:02 +00:00
|
|
|
if (Value *prop = getOwnProperty(name, attributes))
|
2012-04-16 19:23:25 +00:00
|
|
|
return prop;
|
|
|
|
else if (prototype)
|
2012-05-08 09:13:02 +00:00
|
|
|
return prototype->getProperty(name, attributes);
|
2012-04-16 19:23:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Object::put(String *name, const Value &value, bool flag)
|
|
|
|
{
|
2012-05-04 13:12:37 +00:00
|
|
|
Q_UNUSED(flag);
|
|
|
|
|
2012-04-16 19:23:25 +00:00
|
|
|
if (! members)
|
2012-05-04 13:12:37 +00:00
|
|
|
members = new Table();
|
2012-04-16 19:23:25 +00:00
|
|
|
|
|
|
|
members->insert(name, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Object::canPut(String *name)
|
|
|
|
{
|
2012-05-08 09:13:02 +00:00
|
|
|
PropertyAttributes attrs = PropertyAttributes();
|
|
|
|
if (getOwnProperty(name, &attrs)) {
|
|
|
|
return attrs & WritableAttribute;
|
2012-05-04 13:12:37 +00:00
|
|
|
} else if (! prototype) {
|
2012-04-16 19:23:25 +00:00
|
|
|
return extensible;
|
2012-05-08 09:13:02 +00:00
|
|
|
} else if (prototype->getProperty(name, &attrs)) {
|
|
|
|
return attrs & WritableAttribute;
|
2012-04-16 19:23:25 +00:00
|
|
|
} else {
|
|
|
|
return extensible;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Object::hasProperty(String *name) const
|
|
|
|
{
|
|
|
|
if (members)
|
|
|
|
return members->find(name) != 0;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Object::deleteProperty(String *name, bool flag)
|
|
|
|
{
|
2012-05-04 13:12:37 +00:00
|
|
|
Q_UNUSED(flag);
|
|
|
|
|
2012-04-16 19:23:25 +00:00
|
|
|
if (members)
|
|
|
|
return members->remove(name);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-05-14 15:12:25 +00:00
|
|
|
void Object::defaultValue(Context *ctx, Value *result, int typeHint)
|
2012-04-16 19:23:25 +00:00
|
|
|
{
|
|
|
|
if (typeHint == STRING_HINT) {
|
|
|
|
if (asFunctionObject() != 0)
|
2012-05-15 08:53:20 +00:00
|
|
|
__qmljs_init_string(result, ctx->engine->identifier(QLatin1String("function")));
|
2012-04-16 19:23:25 +00:00
|
|
|
else
|
2012-05-15 08:53:20 +00:00
|
|
|
__qmljs_init_string(result, ctx->engine->identifier(QLatin1String("object")));
|
2012-04-16 19:23:25 +00:00
|
|
|
} else {
|
2012-05-15 08:53:20 +00:00
|
|
|
__qmljs_init_undefined(result);
|
2012-04-16 19:23:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool FunctionObject::hasInstance(const Value &value) const
|
|
|
|
{
|
|
|
|
Q_UNUSED(value);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-05-07 14:05:05 +00:00
|
|
|
void FunctionObject::call(Context *ctx)
|
2012-04-16 19:23:25 +00:00
|
|
|
{
|
2012-05-07 14:05:05 +00:00
|
|
|
Q_UNUSED(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FunctionObject::construct(Context *ctx)
|
|
|
|
{
|
2012-05-15 08:53:20 +00:00
|
|
|
__qmljs_init_object(&ctx->thisObject, ctx->engine->newObject());
|
2012-05-09 11:30:22 +00:00
|
|
|
call(ctx);
|
2012-05-07 14:05:05 +00:00
|
|
|
}
|
2012-04-16 19:23:25 +00:00
|
|
|
|
2012-05-13 11:50:55 +00:00
|
|
|
ScriptFunction::ScriptFunction(Context *scope, IR::Function *function)
|
|
|
|
: FunctionObject(scope)
|
2012-05-09 13:47:55 +00:00
|
|
|
, function(function)
|
2012-05-07 14:05:05 +00:00
|
|
|
{
|
2012-05-15 08:02:21 +00:00
|
|
|
needsActivation = function->needsActivation();
|
2012-05-08 09:13:02 +00:00
|
|
|
formalParameterCount = function->formals.size();
|
|
|
|
if (formalParameterCount) {
|
|
|
|
formalParameterList = new String*[formalParameterCount];
|
|
|
|
for (size_t i = 0; i < formalParameterCount; ++i) {
|
2012-05-14 15:12:25 +00:00
|
|
|
formalParameterList[i] = scope->engine->identifier(*function->formals.at(i));
|
2012-05-08 09:13:02 +00:00
|
|
|
}
|
2012-05-07 14:05:05 +00:00
|
|
|
}
|
2012-05-08 09:13:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ScriptFunction::~ScriptFunction()
|
|
|
|
{
|
|
|
|
delete[] formalParameterList;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScriptFunction::call(VM::Context *ctx)
|
|
|
|
{
|
2012-05-07 14:05:05 +00:00
|
|
|
function->code(ctx);
|
2012-04-16 19:23:25 +00:00
|
|
|
}
|
|
|
|
|
2012-05-10 10:14:20 +00:00
|
|
|
void ScriptFunction::construct(VM::Context *ctx)
|
|
|
|
{
|
2012-05-15 08:53:20 +00:00
|
|
|
__qmljs_init_object(&ctx->thisObject, ctx->engine->newObject());
|
2012-05-10 10:14:20 +00:00
|
|
|
function->code(ctx);
|
|
|
|
}
|
|
|
|
|
2012-05-08 09:13:02 +00:00
|
|
|
Value *ArgumentsObject::getProperty(String *name, PropertyAttributes *attributes)
|
2012-04-16 19:23:25 +00:00
|
|
|
{
|
2012-05-08 09:13:02 +00:00
|
|
|
if (context) {
|
|
|
|
for (size_t i = 0; i < context->formalCount; ++i) {
|
|
|
|
String *formal = context->formals[i];
|
|
|
|
if (__qmljs_string_equal(context, formal, name)) {
|
|
|
|
if (attributes)
|
|
|
|
*attributes = PropertyAttributes(*attributes | WritableAttribute);
|
|
|
|
return &context->arguments[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (Value *prop = Object::getProperty(name, attributes))
|
2012-05-07 14:05:05 +00:00
|
|
|
return prop;
|
|
|
|
return 0;
|
2012-04-16 19:23:25 +00:00
|
|
|
}
|
2012-05-14 15:12:25 +00:00
|
|
|
|
|
|
|
ExecutionEngine::ExecutionEngine()
|
|
|
|
{
|
2012-05-15 08:35:19 +00:00
|
|
|
rootContext = newContext();
|
2012-05-14 15:12:25 +00:00
|
|
|
rootContext->init(this);
|
|
|
|
|
|
|
|
//
|
|
|
|
// set up the global object
|
|
|
|
//
|
2012-05-15 08:35:19 +00:00
|
|
|
VM::Object *glo = newArgumentsObject(rootContext);
|
2012-05-15 08:53:20 +00:00
|
|
|
__qmljs_init_object(&globalObject, glo);
|
|
|
|
__qmljs_init_object(&rootContext->activation, glo);
|
2012-05-14 15:12:25 +00:00
|
|
|
|
|
|
|
objectCtor = ObjectCtor::create(this);
|
|
|
|
stringCtor = StringCtor::create(this);
|
|
|
|
numberCtor = NumberCtor::create(this);
|
|
|
|
|
2012-05-15 08:58:22 +00:00
|
|
|
String *prototype = identifier(QLatin1String("prototype"));
|
2012-05-14 15:12:25 +00:00
|
|
|
|
|
|
|
objectCtor.objectValue->get(prototype, &objectPrototype);
|
|
|
|
stringCtor.objectValue->get(prototype, &stringPrototype);
|
|
|
|
numberCtor.objectValue->get(prototype, &numberPrototype);
|
|
|
|
|
2012-05-15 08:53:20 +00:00
|
|
|
glo->put(identifier(QLatin1String("Object")), objectCtor);
|
|
|
|
glo->put(identifier(QLatin1String("String")), stringCtor);
|
|
|
|
glo->put(identifier(QLatin1String("Number")), numberCtor);
|
|
|
|
glo->put(identifier(QLatin1String("Math")), Value::fromObject(newMathObject(rootContext)));
|
2012-05-15 08:35:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Context *ExecutionEngine::newContext()
|
|
|
|
{
|
|
|
|
return new Context();
|
2012-05-14 15:12:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
String *ExecutionEngine::identifier(const QString &s)
|
|
|
|
{
|
|
|
|
String *&id = identifiers[s];
|
|
|
|
if (! id)
|
2012-05-15 08:35:19 +00:00
|
|
|
id = newString(s);
|
2012-05-14 15:12:25 +00:00
|
|
|
return id;
|
|
|
|
}
|
2012-05-15 08:35:19 +00:00
|
|
|
|
|
|
|
FunctionObject *ExecutionEngine::newNativeFunction(Context *scope, void (*code)(Context *))
|
|
|
|
{
|
|
|
|
return new NativeFunction(scope, code);
|
|
|
|
}
|
|
|
|
|
|
|
|
FunctionObject *ExecutionEngine::newScriptFunction(Context *scope, IR::Function *function)
|
|
|
|
{
|
|
|
|
return new ScriptFunction(scope, function);
|
|
|
|
}
|
|
|
|
|
|
|
|
Object *ExecutionEngine::newObject()
|
|
|
|
{
|
|
|
|
return new Object();
|
|
|
|
}
|
|
|
|
|
|
|
|
FunctionObject *ExecutionEngine::newObjectCtor(Context *ctx)
|
|
|
|
{
|
|
|
|
return new ObjectCtor(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
Object *ExecutionEngine::newObjectPrototype(Context *ctx, FunctionObject *proto)
|
|
|
|
{
|
|
|
|
return new ObjectPrototype(ctx, proto);
|
|
|
|
}
|
|
|
|
|
|
|
|
String *ExecutionEngine::newString(const QString &s)
|
|
|
|
{
|
|
|
|
return new String(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
Object *ExecutionEngine::newStringObject(const Value &value)
|
|
|
|
{
|
|
|
|
return new StringObject(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
FunctionObject *ExecutionEngine::newStringCtor(Context *ctx)
|
|
|
|
{
|
|
|
|
return new StringCtor(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
Object *ExecutionEngine::newStringPrototype(Context *ctx, FunctionObject *proto)
|
|
|
|
{
|
2012-05-15 09:19:10 +00:00
|
|
|
Object *stringProto = new StringPrototype(ctx, proto);
|
|
|
|
stringProto->prototype = objectPrototype.objectValue;
|
|
|
|
return stringProto;
|
2012-05-15 08:35:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Object *ExecutionEngine::newNumberObject(const Value &value)
|
|
|
|
{
|
|
|
|
return new NumberObject(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
FunctionObject *ExecutionEngine::newNumberCtor(Context *ctx)
|
|
|
|
{
|
|
|
|
return new NumberCtor(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
Object *ExecutionEngine::newNumberPrototype(Context *ctx, FunctionObject *proto)
|
|
|
|
{
|
2012-05-15 09:19:10 +00:00
|
|
|
Object *numberProto = new NumberPrototype(ctx, proto);
|
|
|
|
numberProto->prototype = objectPrototype.objectValue;
|
|
|
|
return numberProto;
|
2012-05-15 08:35:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Object *ExecutionEngine::newBooleanObject(const Value &value)
|
|
|
|
{
|
|
|
|
return new BooleanObject(value);
|
|
|
|
}
|
|
|
|
|
2012-05-15 09:19:10 +00:00
|
|
|
FunctionObject *ExecutionEngine::newBooleanCtor(Context *ctx)
|
|
|
|
{
|
|
|
|
return new BooleanCtor(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
Object *ExecutionEngine::newBooleanPrototype(Context *ctx, FunctionObject *proto)
|
|
|
|
{
|
|
|
|
Object *booleanProto = new BooleanPrototype(ctx, proto);
|
|
|
|
booleanProto->prototype = objectPrototype.objectValue;
|
|
|
|
return booleanProto;
|
|
|
|
}
|
|
|
|
|
2012-05-15 08:35:19 +00:00
|
|
|
Object *ExecutionEngine::newErrorObject(const Value &value)
|
|
|
|
{
|
|
|
|
return new ErrorObject(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
Object *ExecutionEngine::newMathObject(Context *ctx)
|
|
|
|
{
|
|
|
|
return new MathObject(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
Object *ExecutionEngine::newArgumentsObject(Context *ctx)
|
|
|
|
{
|
|
|
|
return new ArgumentsObject(ctx);
|
|
|
|
}
|