jscript: Added Object.getOwnPropertyDescriptor implementation.

Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
oldstable
Jacek Caban 2018-05-10 19:19:56 +02:00 committed by Alexandre Julliard
parent 54bcff15ef
commit 551e5a77e2
5 changed files with 163 additions and 6 deletions

View File

@ -1614,3 +1614,35 @@ HRESULT jsdisp_is_enumerable(jsdisp_t *obj, const WCHAR *name, BOOL *ret)
*ret = prop && (prop->flags & PROPF_ENUMERABLE) && prop->type != PROP_PROTREF;
return S_OK;
}
HRESULT jsdisp_get_own_property(jsdisp_t *obj, const WCHAR *name, BOOL flags_only,
property_desc_t *desc)
{
dispex_prop_t *prop;
HRESULT hres;
hres = find_prop_name(obj, string_hash(name), name, &prop);
if(FAILED(hres))
return hres;
if(!prop)
return DISP_E_UNKNOWNNAME;
memset(desc, 0, sizeof(*desc));
switch(prop->type) {
case PROP_BUILTIN:
case PROP_JSVAL:
if(!flags_only) {
hres = prop_get(obj, prop, &desc->value);
if(FAILED(hres))
return hres;
}
break;
default:
return DISP_E_UNKNOWNNAME;
}
desc->flags = prop->flags & (PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE);
return S_OK;
}

View File

@ -50,6 +50,7 @@ typedef struct _jsval_t jsval_t;
typedef struct _jsstr_t jsstr_t;
typedef struct _script_ctx_t script_ctx_t;
typedef struct _dispex_prop_t dispex_prop_t;
typedef struct _property_desc_t property_desc_t;
typedef struct {
void **blocks;
@ -292,6 +293,7 @@ HRESULT jsdisp_get_id(jsdisp_t*,const WCHAR*,DWORD,DISPID*) DECLSPEC_HIDDEN;
HRESULT disp_delete(IDispatch*,DISPID,BOOL*) DECLSPEC_HIDDEN;
HRESULT disp_delete_name(script_ctx_t*,IDispatch*,jsstr_t*,BOOL*) DECLSPEC_HIDDEN;
HRESULT jsdisp_delete_idx(jsdisp_t*,DWORD) DECLSPEC_HIDDEN;
HRESULT jsdisp_get_own_property(jsdisp_t*,const WCHAR*,BOOL,property_desc_t*) DECLSPEC_HIDDEN;
HRESULT jsdisp_is_own_prop(jsdisp_t*,const WCHAR*,BOOL*) DECLSPEC_HIDDEN;
HRESULT jsdisp_is_enumerable(jsdisp_t*,const WCHAR*,BOOL*) DECLSPEC_HIDDEN;
@ -376,6 +378,11 @@ typedef struct {
#include "jsval.h"
struct _property_desc_t {
unsigned flags;
jsval_t value;
};
typedef struct {
EXCEPINFO ei;
jsval_t val;

View File

@ -32,8 +32,16 @@ static const WCHAR propertyIsEnumerableW[] =
{'p','r','o','p','e','r','t','y','I','s','E','n','u','m','e','r','a','b','l','e',0};
static const WCHAR isPrototypeOfW[] = {'i','s','P','r','o','t','o','t','y','p','e','O','f',0};
static const WCHAR getOwnPropertyDescriptorW[] =
{'g','e','t','O','w','n','P','r','o','p','e','r','t','y','D','e','s','c','r','i','p','t','o','r',0};
static const WCHAR default_valueW[] = {'[','o','b','j','e','c','t',' ','O','b','j','e','c','t',']',0};
static const WCHAR configurableW[] = {'c','o','n','f','i','g','u','r','a','b','l','e',0};
static const WCHAR enumerableW[] = {'e','n','u','m','e','r','a','b','l','e',0};
static const WCHAR valueW[] = {'v','a','l','u','e',0};
static const WCHAR writableW[] = {'w','r','i','t','a','b','l','e',0};
static HRESULT Object_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
jsval_t *r)
{
@ -252,6 +260,79 @@ static const builtin_info_t ObjectInst_info = {
NULL
};
static void release_property_descriptor(property_desc_t *desc)
{
jsval_release(desc->value);
}
static HRESULT Object_getOwnPropertyDescriptor(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags,
unsigned argc, jsval_t *argv, jsval_t *r)
{
property_desc_t prop_desc;
jsdisp_t *obj, *desc_obj;
const WCHAR *name;
jsstr_t *name_str;
HRESULT hres;
TRACE("\n");
if(argc < 1 || !is_object_instance(argv[0]))
return throw_type_error(ctx, JS_E_OBJECT_EXPECTED, NULL);
obj = to_jsdisp(get_object(argv[0]));
if(!obj) {
FIXME("not implemented non-JS object\n");
return E_NOTIMPL;
}
hres = to_flat_string(ctx, argc >= 2 ? argv[1] : jsval_undefined(), &name_str, &name);
if(FAILED(hres))
return hres;
hres = jsdisp_get_own_property(obj, name, FALSE, &prop_desc);
jsstr_release(name_str);
if(hres == DISP_E_UNKNOWNNAME) {
if(r) *r = jsval_undefined();
return S_OK;
}
if(FAILED(hres))
return hres;
hres = create_object(ctx, NULL, &desc_obj);
if(FAILED(hres))
return hres;
hres = jsdisp_propput_name(desc_obj, valueW, prop_desc.value);
if(SUCCEEDED(hres))
hres = jsdisp_propput_name(desc_obj, writableW,
jsval_bool(!!(prop_desc.flags & PROPF_WRITABLE)));
if(SUCCEEDED(hres))
hres = jsdisp_propput_name(desc_obj, enumerableW,
jsval_bool(!!(prop_desc.flags & PROPF_ENUMERABLE)));
if(SUCCEEDED(hres))
hres = jsdisp_propput_name(desc_obj, configurableW,
jsval_bool(!!(prop_desc.flags & PROPF_CONFIGURABLE)));
release_property_descriptor(&prop_desc);
if(SUCCEEDED(hres) && r)
*r = jsval_obj(desc_obj);
else
jsdisp_release(desc_obj);
return hres;
}
static const builtin_prop_t ObjectConstr_props[] = {
{getOwnPropertyDescriptorW, Object_getOwnPropertyDescriptor, PROPF_ES5|PROPF_METHOD|2}
};
static const builtin_info_t ObjectConstr_info = {
JSCLASS_FUNCTION,
DEFAULT_FUNCTION_VALUE,
sizeof(ObjectConstr_props)/sizeof(*ObjectConstr_props),
ObjectConstr_props,
NULL,
NULL
};
static HRESULT ObjectConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
jsval_t *r)
{
@ -303,7 +384,7 @@ HRESULT create_object_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdi
{
static const WCHAR ObjectW[] = {'O','b','j','e','c','t',0};
return create_builtin_constructor(ctx, ObjectConstr_value, ObjectW, NULL, PROPF_CONSTR,
return create_builtin_constructor(ctx, ObjectConstr_value, ObjectW, &ObjectConstr_info, PROPF_CONSTR,
object_prototype, ret);
}

View File

@ -140,6 +140,10 @@ function test_javascript() {
test_exposed("toISOString", Date.prototype, v >= 9);
test_exposed("isArray", Array, v >= 9);
test_exposed("indexOf", Array.prototype, v >= 9);
/* FIXME: IE8 implements weird semi-functional property descriptors. */
if(v != 8) {
test_exposed("getOwnPropertyDescriptor", Object, v >= 8);
}
test_parses("if(false) { o.default; }", v >= 9);
test_parses("if(false) { o.with; }", v >= 9);

View File

@ -28,8 +28,6 @@ function test_date_now() {
}
function test_toISOString() {
var s;
function expect(date, expected) {
var s = date.toISOString();
ok(s === expected, "toISOString returned " + s + " expected " + expected);
@ -53,8 +51,6 @@ function test_toISOString() {
expect(new Date(-6216721920000100), "-195031-12-03T23:59:59.900Z");
expect(new Date(1092830912830100), "+036600-06-07T22:27:10.100Z");
trace("" + 0xdeadbeef);
expect_exception(function() { new Date(NaN).toISOString(); });
expect_exception(function() { new Date(31494784780800001).toISOString(); });
@ -147,10 +143,47 @@ function test_identifier_keywords() {
next_test();
}
function test_own_data_prop_desc(obj, prop, expected_writable, expected_enumerable,
expected_configurable) {
var desc = Object.getOwnPropertyDescriptor(obj, prop);
ok("value" in desc, "value is not in desc");
ok(desc.value === obj[prop], "desc.value = " + desc.value + " expected " + obj[prop]);
ok(desc.writable === expected_writable, "desc(" + prop + ").writable = " + desc.writable
+ " expected " + expected_writable);
ok(desc.enumerable === expected_enumerable, "desc.enumerable = " + desc.enumerable
+ " expected " + expected_enumerable);
ok(desc.configurable === expected_configurable, "desc.configurable = " + desc.configurable
+ " expected " + expected_configurable);
}
function test_getOwnPropertyDescriptor() {
var obj;
obj = { test: 1 };
test_own_data_prop_desc(obj, "test", true, true, true);
test_own_data_prop_desc(Object, "getOwnPropertyDescriptor", true, false, true);
test_own_data_prop_desc(Math, "PI", false, false, false);
var obj = new String();
ok(Object.getOwnPropertyDescriptor(obj, "slice") === undefined,
"getOwnPropertyDescriptor(slice) did not return undefined");
test_own_data_prop_desc(String.prototype, "slice", true, false, true);
obj = new Array();
test_own_data_prop_desc(obj, "length", true, false, false);
obj = /test/;
test_own_data_prop_desc(obj, "lastIndex", true, false, false);
next_test();
}
var tests = [
test_date_now,
test_toISOString,
test_indexOf,
test_isArray,
test_identifier_keywords
test_identifier_keywords,
test_getOwnPropertyDescriptor
];