Browse Source

Merge pull request #1087 from svaarala/add-get-prop-desc

Implement duk_get_prop_desc() API call
pull/1097/head
Sami Vaarala 8 years ago
committed by GitHub
parent
commit
739fa194cc
  1. 4
      RELEASES.rst
  2. 7
      src-input/duk_api_object.c
  3. 2
      src-input/duk_api_public.h.in
  4. 5
      src-input/duk_bi_object.c
  5. 2
      src-input/duk_hobject.h
  6. 25
      src-input/duk_hobject_props.c
  7. 92
      tests/api/test-get-prop-desc.c
  8. 3
      website/api/duk_def_prop.yaml
  9. 43
      website/api/duk_get_prop_desc.yaml

4
RELEASES.rst

@ -1797,6 +1797,10 @@ Planned
duk_del_prop_lstring(), duk_has_prop_lstring(), duk_get_global_lstring(),
duk_put_global_lstring() (GH-946, GH-953)
* Add duk_get_prop_desc() API call which pushes a property descriptor object
for a target object and key, similar to Object.getOwnPropertyDescriptor()
(GH-1087)
* Add duk_suspend() and duk_resume() which allow a native thread running a
Duktape/C function to be suspended temporarily (e.g. when a native system
call blocks) so that other native threads may execute while the thread is

7
src-input/duk_api_object.c

@ -382,6 +382,13 @@ DUK_INTERNAL void duk_xdef_prop_stridx_thrower(duk_context *ctx, duk_idx_t obj_i
duk_def_prop(ctx, obj_idx, DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_FORCE); /* attributes always 0 */
}
/* Object.getOwnPropertyDescriptor() equivalent C binding. */
DUK_EXTERNAL void duk_get_prop_desc(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t flags) {
DUK_UNREF(flags); /* no flags defined yet */
duk_hobject_object_get_own_property_descriptor(ctx, obj_idx); /* [ ... key ] -> [ ... desc ] */
}
/* Object.defineProperty() equivalent C binding. */
DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t flags) {
duk_hthread *thr = (duk_hthread *) ctx;

2
src-input/duk_api_public.h.in

@ -759,6 +759,8 @@ DUK_EXTERNAL_DECL duk_bool_t duk_has_prop(duk_context *ctx, duk_idx_t obj_idx);
DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key);
DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len);
DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx);
DUK_EXTERNAL_DECL void duk_get_prop_desc(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t flags);
DUK_EXTERNAL_DECL void duk_def_prop(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t flags);
DUK_EXTERNAL_DECL duk_bool_t duk_get_global_string(duk_context *ctx, const char *key);

5
src-input/duk_bi_object.c

@ -603,8 +603,9 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_property(duk_context *ct
#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
DUK_INTERNAL duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_context *ctx) {
/* XXX: no need for indirect call */
return duk_hobject_object_get_own_property_descriptor(ctx);
/* [ obj key ] */
duk_hobject_object_get_own_property_descriptor(ctx, -2);
return 1;
}
#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */

2
src-input/duk_hobject.h

@ -908,7 +908,7 @@ duk_bool_t duk_hobject_define_property_helper(duk_context *ctx,
duk_bool_t throw_flag);
/* Object built-in methods */
DUK_INTERNAL_DECL duk_ret_t duk_hobject_object_get_own_property_descriptor(duk_context *ctx);
DUK_INTERNAL_DECL void duk_hobject_object_get_own_property_descriptor(duk_context *ctx, duk_idx_t obj_idx);
DUK_INTERNAL_DECL void duk_hobject_object_seal_freeze_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_freeze);
DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_is_sealed_frozen_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_frozen);
DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_ownprop_helper(duk_context *ctx, duk_small_uint_t required_desc_flags);

25
src-input/duk_hobject_props.c

@ -4790,10 +4790,10 @@ DUK_INTERNAL duk_uint32_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *
/*
* Object.getOwnPropertyDescriptor() (E5 Sections 15.2.3.3, 8.10.4)
*
* This is an actual function call.
* [ ... key ] -> [ ... desc/undefined ]
*/
DUK_INTERNAL duk_ret_t duk_hobject_object_get_own_property_descriptor(duk_context *ctx) {
DUK_INTERNAL void duk_hobject_object_get_own_property_descriptor(duk_context *ctx, duk_idx_t obj_idx) {
duk_hthread *thr = (duk_hthread *) ctx;
duk_hobject *obj;
duk_hstring *key;
@ -4804,8 +4804,8 @@ DUK_INTERNAL duk_ret_t duk_hobject_object_get_own_property_descriptor(duk_contex
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
obj = duk_require_hobject_promote_mask(ctx, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
key = duk_to_hstring(ctx, 1);
obj = duk_require_hobject_promote_mask(ctx, obj_idx, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
key = duk_to_hstring(ctx, -1);
DUK_ASSERT(obj != NULL);
DUK_ASSERT(key != NULL);
@ -4815,14 +4815,13 @@ DUK_INTERNAL duk_ret_t duk_hobject_object_get_own_property_descriptor(duk_contex
rc = duk_hobject_get_own_propdesc(thr, obj, key, &pd, DUK_GETDESC_FLAG_PUSH_VALUE);
if (!rc) {
duk_push_undefined(ctx);
/* [obj key undefined] */
return 1;
duk_remove(ctx, -2);
return;
}
duk_push_object(ctx);
/* [obj key value desc] */
/* [ ... key value desc ] */
if (DUK_PROPDESC_IS_ACCESSOR(&pd)) {
/* If a setter/getter is missing (undefined), the descriptor must
@ -4841,20 +4840,20 @@ DUK_INTERNAL duk_ret_t duk_hobject_object_get_own_property_descriptor(duk_contex
}
duk_put_prop_stridx(ctx, -2, DUK_STRIDX_SET);
} else {
duk_dup_m2(ctx); /* [obj key value desc value] */
duk_dup_m2(ctx);
duk_put_prop_stridx(ctx, -2, DUK_STRIDX_VALUE);
duk_push_boolean(ctx, DUK_PROPDESC_IS_WRITABLE(&pd));
duk_put_prop_stridx(ctx, -2, DUK_STRIDX_WRITABLE);
/* [obj key value desc] */
}
duk_push_boolean(ctx, DUK_PROPDESC_IS_ENUMERABLE(&pd));
duk_put_prop_stridx(ctx, -2, DUK_STRIDX_ENUMERABLE);
duk_push_boolean(ctx, DUK_PROPDESC_IS_CONFIGURABLE(&pd));
duk_put_prop_stridx(ctx, -2, DUK_STRIDX_CONFIGURABLE);
/* [obj key value desc] */
return 1;
/* [ ... key value desc ] */
duk_replace(ctx, -3);
duk_pop(ctx); /* -> [ ... desc ] */
}
/*

92
tests/api/test-get-prop-desc.c

@ -0,0 +1,92 @@
/*
* duk_get_prop_desc()
*/
/*===
*** test_basic (duk_safe_call)
top before: 4
top after: 4
top before: 5
top after: 5
{value:"foo",writable:true,enumerable:true,configurable:false}
{get:{_func:true},set:{_func:true},enumerable:false,configurable:true}
final top: 6
==> rc=0, result='undefined'
*** test_nonobject (duk_safe_call)
==> rc=1, result='TypeError: object required, found null (stack index 0)'
*** test_invalid_index (duk_safe_call)
==> rc=1, result='TypeError: object required, found none (stack index 3)'
===*/
static duk_ret_t test_basic(duk_context *ctx, void *udata) {
(void) udata;
duk_push_string(ctx, "dummy");
duk_eval_string(ctx,
"(function () {\n"
" var obj = {};\n"
" Object.defineProperties(obj, {\n"
" normal: { value: 'foo', writable: true, enumerable: true, configurable: false },\n"
" accessor: { get: function mygetter() {}, set: function mysetter() {}, enumerable: false, configurable: true }\n"
" });\n"
" return obj;\n"
"})()\n");
duk_push_string(ctx, "dummy");
/* [ dummy obj dummy ] */
duk_push_string(ctx, "normal");
printf("top before: %ld\n", (long) duk_get_top(ctx));
duk_get_prop_desc(ctx, -3, 0 /*flags*/);
printf("top after: %ld\n", (long) duk_get_top(ctx));
duk_push_string(ctx, "accessor");
printf("top before: %ld\n", (long) duk_get_top(ctx));
duk_get_prop_desc(ctx, 1, 0 /*flags*/);
printf("top after: %ld\n", (long) duk_get_top(ctx));
/* [ dummy obj dummy desc1 desc2 ] */
duk_eval_string(ctx,
"(function (d1, d2) {\n"
" print(Duktape.enc('jx', d1));\n"
" print(Duktape.enc('jx', d2));\n"
"})");
duk_dup(ctx, 3);
duk_dup(ctx, 4);
duk_call(ctx, 2);
/* [ dummy obj dummy desc1 desc2 result ] */
printf("final top: %ld\n", (long) duk_get_top(ctx));
return 0;
}
static duk_ret_t test_nonobject(duk_context *ctx, void *udata) {
(void) udata;
duk_push_null(ctx);
duk_push_string(ctx, "prop");
duk_get_prop_desc(ctx, 0, 0 /*flags*/);
printf("final top: %ld\n", (long) duk_get_top(ctx));
return 0;
}
static duk_ret_t test_invalid_index(duk_context *ctx, void *udata) {
(void) udata;
duk_push_null(ctx);
duk_push_string(ctx, "prop");
duk_get_prop_desc(ctx, 3, 0 /*flags*/);
printf("final top: %ld\n", (long) duk_get_top(ctx));
return 0;
}
void test(duk_context *ctx) {
TEST_SAFE_CALL(test_basic);
TEST_SAFE_CALL(test_nonobject);
TEST_SAFE_CALL(test_invalid_index);
}

3
website/api/duk_def_prop.yaml

@ -158,4 +158,7 @@ tags:
- property
- sandbox
seealso:
- duk_get_prop_desc
introduced: 1.1.0

43
website/api/duk_get_prop_desc.yaml

@ -0,0 +1,43 @@
name: duk_get_prop_desc
proto: |
void duk_get_prop_desc(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t flags);
stack: |
[ ... obj! ... key! ] -> [ ... obj! ... desc! ] (if property exists)
[ ... obj! ... key! ] -> [ ... obj! ... undefined! ] (if property doesn't exist)
summary: |
<p>Equivalent of <code>Object.getOwnPropertyDescriptor()</code> in the C API:
pushes a property descriptor object for a named property of the object at
<code>obj_idx</code>. If the target is not an object (or the index is invalid)
an error is thrown.</p>
<p>No flags are defined yet, use 0 for <code>flags</code>.</p>
example: |
duk_idx_t obj_idx = /* ... */;
/* Check if property "my_prop" is a getter. */
duk_push_string(ctx, "my_prop");
duk_get_prop_desc(ctx, obj_idx, 0 /*flags*/);
if (duk_is_object(ctx, -1)) {
/* Property found. */
if (duk_has_prop_string(ctx, -1, "get")) {
printf("my_prop is a getter\n");
} else {
printf("my_prop is not a getter\n");
}
} else {
printf("my_prop not found\n");
}
tags:
- property
- sandbox
seealso:
- duk_def_prop
introduced: 2.0.0
Loading…
Cancel
Save