Implement jerry_get_own_property API function (#4612)

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg 2021-03-03 18:02:40 +01:00 committed by GitHub
parent a95e3e37e1
commit 29b7c8f8ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 346 additions and 0 deletions

View File

@ -6994,6 +6994,77 @@ jerry_get_property_by_index (const jerry_value_t obj_val,
- [jerry_set_property](#jerry_set_property)
- [jerry_set_property_by_index](#jerry_set_property_by_index)
## jerry_get_own_property
**Summary**
Get the own property value of an object with the given name. The function tells
whether the property is found, and the receiver object can be specified as well.
The receiver is passed as the `this` argument for getters, and the receiver
argument for Proxy `get` traps.
*Notes*:
- Returned value must be freed with [jerry_release_value](#jerry_release_value) when it is no longer needed.
- The `found_p` argument is ignored if its value is NULL.
- The target value of `found_p` argument is set to false when the arguments are invalid, e.g. `obj_val` is not an object.
**Prototype**
```c
jerry_value_t
jerry_get_own_property (const jerry_value_t obj_val,
const jerry_value_t prop_name_val,
const jerry_value_t receiver_val,
bool *found_p);
```
- `obj_val` - object value
- `prop_name_val` - property name
- `receiver_val` - receiver object
- `found_p` - [out] true, if the property is found or obj_val is a Proxy object, false otherwise
- return value
- value of property, if success
- thrown error, otherwise
**Example**
[doctest]: # ()
```c
#include "jerryscript.h"
#include "stdio.h"
int
main (void)
{
jerry_init (JERRY_INIT_EMPTY);
jerry_value_t global_object = jerry_get_global_object ();
jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) "Object");
bool found;
jerry_value_t prop_value = jerry_get_own_property (global_object, prop_name, global_object, &found);
if (found)
{
printf ("Property is found!\n");
}
/* use "prop_value" then release it. */
jerry_release_value (prop_value);
jerry_release_value (prop_name);
jerry_release_value (global_object);
return 0;
}
```
**See also**
- [jerry_get_property](#jerry_get_property)
- [jerry_get_property_by_index](#jerry_get_property_by_index)
## jerry_get_internal_property
**Summary**

View File

@ -3030,6 +3030,66 @@ jerry_get_property_by_index (const jerry_value_t obj_val, /**< object value */
return jerry_return (ret_value);
} /* jerry_get_property_by_index */
/**
* Get the own property value of an object with the given name.
*
* Note:
* returned value must be freed with jerry_release_value, when it is no longer needed.
*
* @return value of the property - if success
* value marked with error flag - otherwise
*/
jerry_value_t
jerry_get_own_property (const jerry_value_t obj_val, /**< object value */
const jerry_value_t prop_name_val, /**< property name (string value) */
const jerry_value_t receiver_val, /**< receiver object value */
bool *found_p) /**< [out] true, if the property is found
* or obj_val is a Proxy object, false otherwise */
{
jerry_assert_api_available ();
if (found_p != NULL)
{
*found_p = false;
}
if (!ecma_is_value_object (obj_val)
|| !ecma_is_value_prop_name (prop_name_val)
|| !ecma_is_value_object (receiver_val))
{
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p)));
}
ecma_object_t *object_p = ecma_get_object_from_value (obj_val);
ecma_string_t *property_name_p = ecma_get_prop_name_from_value (prop_name_val);
#if JERRY_BUILTIN_PROXY
if (ECMA_OBJECT_IS_PROXY (object_p))
{
if (found_p != NULL)
{
*found_p = true;
}
return jerry_return (ecma_proxy_object_get (object_p, property_name_p, receiver_val));
}
#endif /* JERRY_BUILTIN_PROXY */
ecma_value_t ret_value = ecma_op_object_find_own (receiver_val, object_p, property_name_p);
if (ecma_is_value_found (ret_value))
{
if (found_p != NULL)
{
*found_p = true;
}
return jerry_return (ret_value);
}
return ECMA_VALUE_UNDEFINED;
} /* jerry_get_own_property */
/**
* Get value of an internal property to the specified object with the given name.
*

View File

@ -687,6 +687,8 @@ bool jerry_delete_internal_property (const jerry_value_t obj_val, const jerry_va
jerry_value_t jerry_get_property (const jerry_value_t obj_val, const jerry_value_t prop_name_val);
jerry_value_t jerry_get_property_by_index (const jerry_value_t obj_val, uint32_t index);
jerry_value_t jerry_get_own_property (const jerry_value_t obj_val, const jerry_value_t prop_name_val,
const jerry_value_t receiver_val, bool *found_p);
jerry_value_t jerry_get_internal_property (const jerry_value_t obj_val, const jerry_value_t prop_name_val);
jerry_value_t jerry_set_property (const jerry_value_t obj_val, const jerry_value_t prop_name_val,
const jerry_value_t value_to_set);

View File

@ -50,6 +50,7 @@ set(SOURCE_UNIT_TEST_MAIN_MODULES
test-exec-stop.c
test-external-string.c
test-from-property-descriptor.c
test-get-own-property.c
test-has-property.c
test-internal-properties.c
test-jmem.c

View File

@ -0,0 +1,212 @@
/* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "jerryscript.h"
#include "test-common.h"
static jerry_value_t
create_object (const char *source_p) /**< source script */
{
jerry_value_t result = jerry_eval ((const jerry_char_t *) source_p, strlen (source_p), 0);
TEST_ASSERT (jerry_value_is_object (result));
return result;
} /* create_object */
static void
compare_string (jerry_value_t value, /**< value to compare */
const char *string_p) /**< expected value */
{
jerry_char_t string_buffer[64];
TEST_ASSERT (jerry_value_is_string (value));
size_t size = strlen (string_p);
TEST_ASSERT (size <= sizeof (string_buffer));
TEST_ASSERT (size == jerry_get_string_size (value));
jerry_string_to_char_buffer (value, string_buffer, (jerry_size_t) size);
TEST_ASSERT (memcmp (string_p, string_buffer, size) == 0);
} /* compare_string */
int
main (void)
{
TEST_INIT ();
jerry_init (JERRY_INIT_EMPTY);
jerry_value_t pp_string = jerry_create_string ((const jerry_char_t *) "pp");
jerry_value_t qq_string = jerry_create_string ((const jerry_char_t *) "qq");
jerry_value_t rr_string = jerry_create_string ((const jerry_char_t *) "rr");
jerry_value_t object = create_object ("'use strict';\n"
"({ pp:'A', get qq() { return 'B' } })");
jerry_value_t result = jerry_get_own_property (object, pp_string, object, NULL);
compare_string (result, "A");
jerry_release_value (result);
bool found = false;
result = jerry_get_own_property (object, pp_string, object, &found);
compare_string (result, "A");
TEST_ASSERT (found);
jerry_release_value (result);
result = jerry_get_own_property (object, qq_string, object, NULL);
compare_string (result, "B");
jerry_release_value (result);
found = false;
result = jerry_get_own_property (object, qq_string, object, &found);
compare_string (result, "B");
TEST_ASSERT (found);
jerry_release_value (result);
result = jerry_get_own_property (object, rr_string, object, NULL);
TEST_ASSERT (jerry_value_is_undefined (result));
jerry_release_value (result);
found = true;
result = jerry_get_own_property (object, rr_string, object, &found);
TEST_ASSERT (jerry_value_is_undefined (result));
TEST_ASSERT (!found);
jerry_release_value (result);
jerry_release_value (object);
object = create_object ("'use strict';\n"
"Object.create({ pp:'Found!' })\n");
found = true;
/* Does not check prototype. */
result = jerry_get_own_property (object, pp_string, object, &found);
TEST_ASSERT (jerry_value_is_undefined (result));
TEST_ASSERT (!found);
jerry_release_value (result);
jerry_release_value (object);
object = create_object ("'use strict';\n"
"var obj = Object.create({ get pp() { return this.qq } })\n"
"Object.defineProperty(obj, 'qq', { value: 'Prop' })\n"
"obj");
jerry_value_t prototype = jerry_get_prototype (object);
TEST_ASSERT (jerry_value_is_object (prototype));
found = false;
result = jerry_get_own_property (prototype, pp_string, object, &found);
compare_string (result, "Prop");
TEST_ASSERT (found);
jerry_release_value (result);
jerry_release_value (prototype);
jerry_release_value (object);
/* Error cases. */
jerry_value_t invalid_arg = jerry_create_null ();
object = jerry_create_object ();
found = true;
result = jerry_get_own_property (invalid_arg, pp_string, object, &found);
TEST_ASSERT (jerry_value_is_error (result));
TEST_ASSERT (!found);
jerry_release_value (result);
result = jerry_get_own_property (object, pp_string, invalid_arg, NULL);
TEST_ASSERT (jerry_value_is_error (result));
jerry_release_value (result);
found = true;
result = jerry_get_own_property (object, invalid_arg, object, &found);
TEST_ASSERT (jerry_value_is_error (result));
TEST_ASSERT (!found);
jerry_release_value (result);
jerry_release_value (object);
jerry_release_value (invalid_arg);
if (jerry_is_feature_enabled (JERRY_FEATURE_PROXY))
{
object = create_object ("'use strict';\n"
"var proxy = new Proxy({}, {\n"
" get: function(target, prop, receiver) {\n"
" if (prop === 'qq') return\n"
" return receiver[prop]\n"
" }\n"
"})\n"
"var obj = Object.create(proxy)\n"
"Object.defineProperty(obj, 'pp', { value: 'Prop' })\n"
"obj");
prototype = jerry_get_prototype (object);
found = false;
result = jerry_get_own_property (prototype, pp_string, object, &found);
compare_string (result, "Prop");
TEST_ASSERT (found);
jerry_release_value (result);
found = false;
result = jerry_get_own_property (prototype, qq_string, object, &found);
TEST_ASSERT (jerry_value_is_undefined (result));
TEST_ASSERT (found);
jerry_release_value (result);
jerry_release_value (prototype);
jerry_release_value (object);
object = create_object ("'use strict';\n"
"(new Proxy({}, {\n"
" get: function(target, prop, receiver) {\n"
" throw 'Error'\n"
" }\n"
"}))\n");
found = false;
result = jerry_get_own_property (object, qq_string, object, &found);
TEST_ASSERT (jerry_value_is_error (result));
TEST_ASSERT (found);
jerry_release_value (result);
jerry_release_value (object);
}
if (jerry_is_feature_enabled (JERRY_FEATURE_SYMBOL))
{
object = create_object ("'use strict'\n"
"var sym = Symbol();\n"
"({ pp:sym, [sym]:'Prop' })");
found = false;
jerry_value_t symbol = jerry_get_own_property (object, pp_string, object, &found);
TEST_ASSERT (jerry_value_is_symbol (symbol));
TEST_ASSERT (found);
found = false;
result = jerry_get_own_property (object, symbol, object, &found);
compare_string (result, "Prop");
TEST_ASSERT (found);
jerry_release_value (result);
jerry_release_value (symbol);
jerry_release_value (object);
}
jerry_release_value (pp_string);
jerry_release_value (qq_string);
jerry_release_value (rr_string);
jerry_cleanup ();
return 0;
} /* main */