Implement Object.create/defineProperty/defineProperties
authorLars Knoll <lars.knoll@digia.com>
Sat, 8 Dec 2012 07:57:35 +0000 (23:57 -0800)
committerSimon Hausmann <simon.hausmann@digia.com>
Sat, 8 Dec 2012 16:25:02 +0000 (17:25 +0100)
Change-Id: I3a71597d012b5fb7d7a2f482f4a16431c71c1c22
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
qmljs_engine.cpp
qmljs_engine.h
qmljs_runtime.cpp
qmljs_runtime.h
qv4ecmaobjects.cpp
qv4ecmaobjects_p.h

index ea6b32a..b0a964f 100644 (file)
@@ -85,6 +85,12 @@ ExecutionEngine::ExecutionEngine(MemoryManager *memoryManager, EvalISelFactory *
     id_constructor = identifier(QStringLiteral("constructor"));
     id_arguments = identifier(QStringLiteral("arguments"));
     id___proto__ = identifier(QStringLiteral("__proto__"));
+    id_enumerable = identifier(QStringLiteral("enumerable"));
+    id_configurable = identifier(QStringLiteral("configurable"));
+    id_writable = identifier(QStringLiteral("writable"));
+    id_value = identifier(QStringLiteral("value"));
+    id_get = identifier(QStringLiteral("get"));
+    id_set = identifier(QStringLiteral("set"));
 
     objectPrototype = new (memoryManager) ObjectPrototype();
     stringPrototype = new (memoryManager) StringPrototype(rootContext);
index 520acab..85a3909 100644 (file)
@@ -136,6 +136,12 @@ struct ExecutionEngine
     String *id_constructor;
     String *id_arguments;
     String *id___proto__;
+    String *id_enumerable;
+    String *id_configurable;
+    String *id_writable;
+    String *id_value;
+    String *id_get;
+    String *id_set;
 
     struct ExceptionHandler {
         ExecutionContext *context;
index aaa5be9..53f313f 100644 (file)
@@ -696,8 +696,9 @@ Value __qmljs_call_activation_property(ExecutionContext *context, String *name,
     return o->call(context, Value::undefinedValue(), args, argc);
 }
 
-Value __qmljs_call_property(ExecutionContext *context, Value thisObject, String *name, Value *args, int argc)
+Value __qmljs_call_property(ExecutionContext *context, Value that, String *name, Value *args, int argc)
 {
+    Value thisObject = that;
     if (!thisObject.isObject())
         thisObject = __qmljs_to_object(thisObject, context);
 
@@ -709,7 +710,7 @@ Value __qmljs_call_property(ExecutionContext *context, Value thisObject, String
     if (!o)
         context->throwTypeError();
 
-    return o->call(context, thisObject, args, argc);
+    return o->call(context, that, args, argc);
 }
 
 Value __qmljs_call_value(ExecutionContext *context, Value thisObject, Value func, Value *args, int argc)
index 6675920..e8049d9 100644 (file)
@@ -91,7 +91,7 @@ extern "C" {
 
 // context
 Value __qmljs_call_activation_property(ExecutionContext *, String *name, Value *args, int argc);
-Value __qmljs_call_property(ExecutionContext *context, Value thisObject, String *name, Value *args, int argc);
+Value __qmljs_call_property(ExecutionContext *context, Value that, String *name, Value *args, int argc);
 Value __qmljs_call_value(ExecutionContext *context, Value thisObject, Value func, Value *args, int argc);
 
 Value __qmljs_construct_activation_property(ExecutionContext *, String *name, Value *args, int argc);
index 5a29c64..88acebf 100644 (file)
@@ -610,18 +610,46 @@ Value ObjectPrototype::method_getOwnPropertyNames(ExecutionContext *ctx)
 
 Value ObjectPrototype::method_create(ExecutionContext *ctx)
 {
-    ctx->throwUnimplemented(QStringLiteral("Object.create"));
-    return Value::undefinedValue();
+    Value O = ctx->argument(0);
+    if (!O.isObject())
+        ctx->throwTypeError();
+
+    Object *newObject = ctx->engine->newObject();
+    newObject->prototype = O.objectValue();
+
+    Value objValue = Value::fromObject(newObject);
+    ctx->arguments[0] = objValue;
+    method_defineProperties(ctx);
+
+    return objValue;
 }
 
 Value ObjectPrototype::method_defineProperty(ExecutionContext *ctx)
 {
-    ctx->throwUnimplemented(QStringLiteral("Object.defineProperty"));
-    return Value::undefinedValue();
+    Value O = ctx->argument(0);
+    if (!O.isObject())
+        ctx->throwTypeError();
+
+    String *name = ctx->argument(1).toString(ctx);
+
+    Value attributes = ctx->argument(2);
+    PropertyDescriptor pd;
+    toPropertyDescriptor(ctx, attributes, &pd);
+
+    bool strict = ctx->strictMode;
+    ctx->strictMode = true;
+    O.objectValue()->__defineOwnProperty__(ctx, name, &pd);
+    ctx->strictMode = strict;
+
+    return O;
 }
 
 Value ObjectPrototype::method_defineProperties(ExecutionContext *ctx)
 {
+    Value O = ctx->argument(0);
+    if (!O.isObject())
+        ctx->throwTypeError();
+
     ctx->throwUnimplemented(QStringLiteral("Object.defineProperties"));
     return Value::undefinedValue();
 }
@@ -828,6 +856,63 @@ Value ObjectPrototype::method_defineSetter(ExecutionContext *ctx)
     return Value::undefinedValue();
 }
 
+void ObjectPrototype::toPropertyDescriptor(ExecutionContext *ctx, Value v, PropertyDescriptor *desc)
+{
+    if (!v.isObject())
+        __qmljs_throw_type_error(ctx);
+
+    Object *o = v.objectValue();
+
+    desc->type = PropertyDescriptor::Generic;
+
+    desc->enumberable = PropertyDescriptor::Undefined;
+    if (o->__hasProperty__(ctx, ctx->engine->id_enumerable))
+        desc->enumberable = __qmljs_to_boolean(o->__get__(ctx, ctx->engine->id_enumerable), ctx) ? PropertyDescriptor::Set : PropertyDescriptor::Unset;
+
+    desc->configurable = PropertyDescriptor::Undefined;
+    if (o->__hasProperty__(ctx, ctx->engine->id_configurable))
+        desc->enumberable = __qmljs_to_boolean(o->__get__(ctx, ctx->engine->id_configurable), ctx) ? PropertyDescriptor::Set : PropertyDescriptor::Unset;
+
+    desc->writable = PropertyDescriptor::Undefined;
+    if (o->__hasProperty__(ctx, ctx->engine->id_writable))
+        desc->enumberable = __qmljs_to_boolean(o->__get__(ctx, ctx->engine->id_writable), ctx) ? PropertyDescriptor::Set : PropertyDescriptor::Unset;
+
+    if (o->__hasProperty__(ctx, ctx->engine->id_value)) {
+        desc->value = o->__get__(ctx, ctx->engine->id_value);
+        desc->type = PropertyDescriptor::Data;
+    }
+
+    if (o->__hasProperty__(ctx, ctx->engine->id_get)) {
+        Value get = o->__get__(ctx, ctx->engine->id_get);
+        FunctionObject *f = get.asFunctionObject();
+        if (f) {
+            if (desc->isWritable() || desc->isData())
+                __qmljs_throw_type_error(ctx);
+            desc->get = f;
+        } else if (!get.isUndefined()) {
+            __qmljs_throw_type_error(ctx);
+        } else {
+            desc->get = 0;
+        }
+        desc->type = PropertyDescriptor::Accessor;
+    }
+
+    if (o->__hasProperty__(ctx, ctx->engine->id_set)) {
+        Value get = o->__get__(ctx, ctx->engine->id_set);
+        FunctionObject *f = get.asFunctionObject();
+        if (f) {
+            if (desc->isWritable() || desc->isData())
+                __qmljs_throw_type_error(ctx);
+            desc->set = f;
+        } else if (!get.isUndefined()) {
+            __qmljs_throw_type_error(ctx);
+        } else {
+            desc->set = 0;
+        }
+        desc->type = PropertyDescriptor::Accessor;
+    }
+}
+
 //
 // String
 //
index 02d7d8c..5803633 100644 (file)
@@ -83,6 +83,8 @@ struct ObjectPrototype: Object
 
     static Value method_defineGetter(ExecutionContext *ctx);
     static Value method_defineSetter(ExecutionContext *ctx);
+
+    static void toPropertyDescriptor(ExecutionContext *ctx, Value v, PropertyDescriptor *desc);
 };
 
 struct StringCtor: FunctionObject