Introduce new jerry-ext methods to ease property registration (#2715)
New methods
* jerryx_set_properties: Allows multiple property registration for via a single call
* jerryx_set_property_str: Allows property registration without the need to
create the property name JS value. The property name can be directly passed
as a `const char*` value and must be zero terminated.
* jerryx_get_property_str: Allows getting a property value on a given object.
The property name can be directly passed as a `const char*` value.
* jerryx_has_property_str: Allows checking if a property exists on a given object.
JerryScript-DCO-1.0-Signed-off-by: Peter Gal pgal.u-szeged@partner.samsung.com
This commit is contained in:
committed by
Robert Fancsik
parent
3e12738037
commit
c64ee882da
@@ -1,3 +1,418 @@
|
|||||||
|
# Common methods to handle properties
|
||||||
|
|
||||||
|
The `jerryscript-ext/handler.h` header defines a set of convenience methods
|
||||||
|
which makes the property access a bit straightforward.
|
||||||
|
|
||||||
|
## jerryx_set_property_str
|
||||||
|
|
||||||
|
**Summary**
|
||||||
|
|
||||||
|
Set a property on a target object with a given name.
|
||||||
|
|
||||||
|
*Note*:
|
||||||
|
- The property name must be a zero terminated UTF-8 string.
|
||||||
|
- There should be no '\0' (NULL) character in the name excluding the string terminator.
|
||||||
|
- Returned value must be freed with [jerry_release_value](#jerry_release_value) when it
|
||||||
|
is no longer needed.
|
||||||
|
|
||||||
|
|
||||||
|
**Prototype**
|
||||||
|
|
||||||
|
```c
|
||||||
|
jerry_value_t
|
||||||
|
jerryx_set_property_str (const jerry_value_t target_object,
|
||||||
|
const char *name,
|
||||||
|
const jerry_value_t value);
|
||||||
|
```
|
||||||
|
|
||||||
|
- `target_object` - the object where the property should be set
|
||||||
|
- `name` - name of the property
|
||||||
|
- `value` - property value to be set
|
||||||
|
- return value
|
||||||
|
- JS true value, if success
|
||||||
|
- thrown error, if there was a problem setting the property
|
||||||
|
|
||||||
|
**Example**
|
||||||
|
|
||||||
|
[doctest]: # ()
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "jerryscript.h"
|
||||||
|
#include "jerryscript-ext/handler.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char **argv)
|
||||||
|
{
|
||||||
|
jerry_init (JERRY_INIT_EMPTY);
|
||||||
|
|
||||||
|
jerry_value_t global = jerry_get_global_object ();
|
||||||
|
|
||||||
|
jerry_value_t value = jerry_create_number (3.3);
|
||||||
|
jerry_value_t result = jerryx_set_property_str (global, "value", value);
|
||||||
|
if (jerry_value_is_error (result))
|
||||||
|
{
|
||||||
|
/* The error type/reason can be extracted via the `jerry_get_value_from_error` method */
|
||||||
|
printf ("Error during property configuration\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
jerry_release_value (result);
|
||||||
|
jerry_release_value (value);
|
||||||
|
jerry_release_value (global);
|
||||||
|
jerry_cleanup();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## jerryx_get_property_str
|
||||||
|
|
||||||
|
**Summary**
|
||||||
|
|
||||||
|
Get the value of a property from the specified object with the given name.
|
||||||
|
|
||||||
|
*Notes*:
|
||||||
|
- The property name must be a zero terminated UTF-8 string.
|
||||||
|
- There should be no '\0' (NULL) character in the name excluding the string terminator.
|
||||||
|
- Returned value must be freed with [jerry_release_value](#jerry_release_value) when it
|
||||||
|
is no longer needed.
|
||||||
|
|
||||||
|
|
||||||
|
**Prototype**
|
||||||
|
|
||||||
|
```
|
||||||
|
jerry_value_t
|
||||||
|
jerryx_get_property_str (const jerry_value_t target_object,
|
||||||
|
const char *name);
|
||||||
|
```
|
||||||
|
|
||||||
|
- `target_object` - object on which the property name is accessed
|
||||||
|
- `name` - property name as an UTF-8 `char*`
|
||||||
|
- return value
|
||||||
|
- value of property, if success
|
||||||
|
- thrown error, if there was a problem accessing the property
|
||||||
|
|
||||||
|
**Example**
|
||||||
|
|
||||||
|
[doctest]: # ()
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "jerryscript.h"
|
||||||
|
#include "jerryscript-ext/handler.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char **argv)
|
||||||
|
{
|
||||||
|
jerry_init (JERRY_INIT_EMPTY);
|
||||||
|
|
||||||
|
jerry_value_t global = jerry_get_global_object ();
|
||||||
|
|
||||||
|
jerry_value_t math_object = jerryx_get_property_str (global, "Math");
|
||||||
|
|
||||||
|
/* use math_object */
|
||||||
|
|
||||||
|
jerry_release_value (math_object);
|
||||||
|
jerry_release_value (global);
|
||||||
|
jerry_cleanup();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## jerryx_has_property_str
|
||||||
|
|
||||||
|
**Summary**
|
||||||
|
|
||||||
|
Check if a property exists on an object.
|
||||||
|
|
||||||
|
*Notes*:
|
||||||
|
- The operation performed is the same as what the `jerry_has_property` method.
|
||||||
|
- The property name must be a zero terminated UTF-8 string.
|
||||||
|
- There should be no '\0' (NULL) character in the name excluding the string terminator.
|
||||||
|
|
||||||
|
|
||||||
|
**Prototype**
|
||||||
|
|
||||||
|
```
|
||||||
|
bool
|
||||||
|
jerryx_has_property_str (const jerry_value_t target_object,
|
||||||
|
const char *name);
|
||||||
|
```
|
||||||
|
|
||||||
|
- `target_object` - object on which the property name is accessed
|
||||||
|
- `name` - property name as an UTF-8 `char*`
|
||||||
|
- return value
|
||||||
|
- true, if the given property name exsits on the object
|
||||||
|
- false, if there is no such property name or there was an error accessing the property
|
||||||
|
|
||||||
|
**Example**
|
||||||
|
|
||||||
|
[doctest]: # ()
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "jerryscript.h"
|
||||||
|
#include "jerryscript-ext/handler.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char **argv)
|
||||||
|
{
|
||||||
|
jerry_init (JERRY_INIT_EMPTY);
|
||||||
|
|
||||||
|
jerry_value_t global = jerry_get_global_object ();
|
||||||
|
|
||||||
|
bool have_math = jerryx_has_property_str (global, "Math");
|
||||||
|
|
||||||
|
jerry_release_value (global);
|
||||||
|
jerry_cleanup();
|
||||||
|
|
||||||
|
return have_math ? 0 : 1;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# Utility to register multiple properties in bulk
|
||||||
|
|
||||||
|
In some cases it is useful to register multiple properties for a given object
|
||||||
|
for this the following utility structures and methods are provided.
|
||||||
|
|
||||||
|
## jerryx_property_entry
|
||||||
|
|
||||||
|
**Summary**
|
||||||
|
|
||||||
|
Structure to define an array of properties with `name` and `value` fields which
|
||||||
|
can be registered to a target object.
|
||||||
|
|
||||||
|
The engine must be initialied before specifying the `jerry_value_t` in the struct.
|
||||||
|
|
||||||
|
|
||||||
|
**Prototype**
|
||||||
|
|
||||||
|
```c
|
||||||
|
typedef struct {
|
||||||
|
const char *name;
|
||||||
|
jerry_value_t value;
|
||||||
|
} jerryx_function_list_entry;
|
||||||
|
```
|
||||||
|
|
||||||
|
**See also**
|
||||||
|
|
||||||
|
- [jerryx_set_properties](#jerryx_set_properties)
|
||||||
|
|
||||||
|
|
||||||
|
## jerryx_register_result
|
||||||
|
|
||||||
|
**Summary**
|
||||||
|
|
||||||
|
Structure returned as the result of the [jerryx_set_properties](#jerryx_set_properties) operation.
|
||||||
|
The `result` field will either be a JavaScript undefined value or an error object.
|
||||||
|
In every case the `registered` field is used to indicated the number of
|
||||||
|
successfully registered methods.
|
||||||
|
|
||||||
|
This must be passed for the [jerryx_release_property_entry](#jerryx_release_property_entry) method
|
||||||
|
after the property registration.
|
||||||
|
|
||||||
|
If any error occured during the property registration the `result` field of the structure
|
||||||
|
must be manually released after processing the error value.
|
||||||
|
|
||||||
|
**Prototype**
|
||||||
|
|
||||||
|
```c
|
||||||
|
typedef struct {
|
||||||
|
jerry_value_t result;
|
||||||
|
uint32_t registered;
|
||||||
|
} jerryx_register_result;
|
||||||
|
```
|
||||||
|
|
||||||
|
**See also**
|
||||||
|
|
||||||
|
- [jerryx_set_properties](#jerryx_set_properties)
|
||||||
|
- [jerryx_release_property_entry](#jerryx_release_property_entry)
|
||||||
|
|
||||||
|
|
||||||
|
## jerryx_set_properties
|
||||||
|
|
||||||
|
**Summary**
|
||||||
|
|
||||||
|
Set multiple properties on a target object.
|
||||||
|
|
||||||
|
The properties are an array of (name, jerry_value_t) pairs and
|
||||||
|
this list must end with a (NULL, 0) entry.
|
||||||
|
|
||||||
|
Important notes:
|
||||||
|
* Each property value in the input array is released after a successful property registration.
|
||||||
|
* The method [jerryx_release_property_entry](#jerryx_release_property_entry) must be called if there is any failed registration
|
||||||
|
to release the values in the entries array.
|
||||||
|
It is safe to call this cleanup method in every case not just in case of failure.
|
||||||
|
* If the error value is reported via the result it must be freed manually.
|
||||||
|
|
||||||
|
**Prototype**
|
||||||
|
|
||||||
|
```c
|
||||||
|
jerryx_register_result
|
||||||
|
jerryx_set_properties (const jerry_value_t target_object,
|
||||||
|
const jerryx_property_entry entries[]);
|
||||||
|
```
|
||||||
|
|
||||||
|
- `target_object` - object on which the entries will be set.
|
||||||
|
- `entries` - array of (name, jerry_value_t) pairs.
|
||||||
|
- return a [jerryx_register_result](#jerryx_register_result).
|
||||||
|
- if everything is ok, the struct's `result` field is set to a JS undefined value.
|
||||||
|
- otherwise the `result` field is an error object indicating the problem.
|
||||||
|
- in every case the `registered` field contains the number of successfully registered properties.
|
||||||
|
|
||||||
|
**Example**
|
||||||
|
|
||||||
|
[doctest]: # ()
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "jerryscript.h"
|
||||||
|
#include "jerryscript-ext/handler.h"
|
||||||
|
|
||||||
|
static jerry_value_t
|
||||||
|
handler (const jerry_value_t function_obj,
|
||||||
|
const jerry_value_t this_val,
|
||||||
|
const jerry_value_t args_p[],
|
||||||
|
const jerry_length_t args_cnt)
|
||||||
|
{
|
||||||
|
printf ("native handler called!\n");
|
||||||
|
|
||||||
|
return jerry_create_boolean (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char **argv)
|
||||||
|
{
|
||||||
|
jerry_init (JERRY_INIT_EMPTY);
|
||||||
|
|
||||||
|
jerryx_property_entry methods[] =
|
||||||
|
{
|
||||||
|
{ "demo", jerry_create_external_function (handler) },
|
||||||
|
{ NULL, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
jerry_value_t global = jerry_get_global_object ();
|
||||||
|
jerryx_register_result reg = jerryx_set_properties (global, methods);
|
||||||
|
/* if `reg.result` is undefined all methods are registered */
|
||||||
|
if (jerry_value_is_error (reg.result))
|
||||||
|
{
|
||||||
|
printf ("Only registered %d properties\r\n", reg.registered);
|
||||||
|
/* clean up not registered property values */
|
||||||
|
jerryx_release_property_entry (methods, reg);
|
||||||
|
|
||||||
|
/* clean up the error */
|
||||||
|
jerry_release_value (reg.result);
|
||||||
|
}
|
||||||
|
|
||||||
|
jerry_release_value (global);
|
||||||
|
|
||||||
|
jerry_cleanup();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Convenience macros**
|
||||||
|
|
||||||
|
To make property registration convenient, there are a set of macros to use
|
||||||
|
when setting a property entry:
|
||||||
|
|
||||||
|
* `JERRYX_PROPERTY_NUMBER(NAME, NUMBER)` - creates a number entry.
|
||||||
|
* `JERRYX_PROPERTY_STRING(NAME, STR)` - creates an UTF-8 string entry. This string must be zero terminated.
|
||||||
|
* `JERRYX_PROPERTY_STRING_SZ(NAME, STR, SIZE)` - creates an UTF-8 string entry using only `SIZE` bytes from the string.
|
||||||
|
* `JERRYX_PROPERTY_BOOLEAN(NAME, VALUE)` - creates a boolean entry.
|
||||||
|
* `JERRYX_PROPERTY_FUNCTION(NAME, NATIVE)` - creates a native C function entry.
|
||||||
|
* `JERRYX_PROPERTY_UNDEFINED(NAME)` - creates an undefined property entry.
|
||||||
|
* `JERRYX_PROPERTY_LIST_END()` - indicates the end of the property list.
|
||||||
|
|
||||||
|
**Example usage of Convenience macros**
|
||||||
|
|
||||||
|
[doctest]: # ()
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "jerryscript.h"
|
||||||
|
#include "jerryscript-ext/handler.h"
|
||||||
|
|
||||||
|
static jerry_value_t
|
||||||
|
handler (const jerry_value_t function_obj,
|
||||||
|
const jerry_value_t this_val,
|
||||||
|
const jerry_value_t args_p[],
|
||||||
|
const jerry_length_t args_cnt)
|
||||||
|
{
|
||||||
|
printf ("native handler called!\n");
|
||||||
|
|
||||||
|
return jerry_create_boolean (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char **argv)
|
||||||
|
{
|
||||||
|
jerry_init (JERRY_INIT_EMPTY);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a array of properties to be registered.
|
||||||
|
* This must be done after initializing the engine as creating `jerry_value_t`
|
||||||
|
* elements are invalid before `jerry_init`.
|
||||||
|
*/
|
||||||
|
jerryx_property_entry methods[] =
|
||||||
|
{
|
||||||
|
JERRYX_PROPERTY_FUNCTION ("demo", handler),
|
||||||
|
JERRYX_PROPERTY_NUMBER ("test_num", 2.3),
|
||||||
|
JERRYX_PROPERTY_UNDEFINED ("this_is_undefined"),
|
||||||
|
JERRYX_PROPERTY_LIST_END(),
|
||||||
|
};
|
||||||
|
|
||||||
|
jerry_value_t global = jerry_get_global_object ();
|
||||||
|
jerryx_register_result reg = jerryx_set_properties (global, methods);
|
||||||
|
/* if `reg.result` is undefined all methods are registered */
|
||||||
|
if (jerry_value_is_error (reg.result))
|
||||||
|
{
|
||||||
|
printf ("Only registered %d properties\r\n", reg.registered);
|
||||||
|
/* clean up not registered property values */
|
||||||
|
jerryx_release_property_entry (methods, reg);
|
||||||
|
|
||||||
|
/* clean up the error */
|
||||||
|
jerry_release_value (reg.result);
|
||||||
|
}
|
||||||
|
|
||||||
|
jerry_release_value (global);
|
||||||
|
|
||||||
|
jerry_cleanup();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
**See also**
|
||||||
|
|
||||||
|
- [jerryx_property_entry](#jerryx_property_entry)
|
||||||
|
- [jerryx_release_property_entry](#jerryx_release_property_entry)
|
||||||
|
- [jerryx_register_result](#jerryx_register_result)
|
||||||
|
|
||||||
|
## jerryx_release_property_entry
|
||||||
|
|
||||||
|
**Summary**
|
||||||
|
|
||||||
|
Release all `jerry_value_t` in a `jerryx_property_entry` array based on a previous [jerryx_set_properties](#jerryx_set_properties) call
|
||||||
|
and also the error value (if any) in the `jerryx_register_result` structure.
|
||||||
|
In case of a successful registration it is safe to call this method.
|
||||||
|
|
||||||
|
After the method call the `ęntries` array should not be used as all values are released.
|
||||||
|
|
||||||
|
**Prototype**
|
||||||
|
|
||||||
|
```
|
||||||
|
void
|
||||||
|
jerryx_release_property_entry (const jerryx_property_entry entries[],
|
||||||
|
const jerryx_register_result register_result);
|
||||||
|
```
|
||||||
|
|
||||||
|
- `entires` - array of [jerryx_property_entry](#jerryx_property_entry).
|
||||||
|
- `register_result` - result of a previous [jerryx_set_properties](#jerryx_set_properties) call.
|
||||||
|
|
||||||
|
**Example**
|
||||||
|
|
||||||
|
For example usage see [jerryx_set_properties](#jerryx_set_properties).
|
||||||
|
|
||||||
|
|
||||||
# Common external function handlers
|
# Common external function handlers
|
||||||
|
|
||||||
## jerryx_handler_assert_fatal
|
## jerryx_handler_assert_fatal
|
||||||
|
|||||||
@@ -40,3 +40,147 @@ jerryx_handler_register_global (const jerry_char_t *name_p, /**< name of the fun
|
|||||||
|
|
||||||
return result_val;
|
return result_val;
|
||||||
} /* jerryx_handler_register_global */
|
} /* jerryx_handler_register_global */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set multiple properties on a target object.
|
||||||
|
*
|
||||||
|
* The properties are an array of (name, property value) pairs and
|
||||||
|
* this list must end with a (NULL, 0) entry.
|
||||||
|
*
|
||||||
|
* Notes:
|
||||||
|
* - Each property value in the input array is released after a successful property registration.
|
||||||
|
* - The property name must be a zero terminated UTF-8 string.
|
||||||
|
* - There should be no '\0' (NULL) character in the name excluding the string terminator.
|
||||||
|
* - The method `jerryx_release_property_entry` must be called if there is any failed registration
|
||||||
|
* to release the values in the entries array.
|
||||||
|
*
|
||||||
|
* @return `jerryx_register_result` struct - if everything is ok with the (undefined, property entry count) values.
|
||||||
|
* In case of error the (error object, registered property count) pair.
|
||||||
|
*/
|
||||||
|
jerryx_register_result
|
||||||
|
jerryx_set_properties (const jerry_value_t target_object, /**< target object */
|
||||||
|
const jerryx_property_entry entries[]) /**< array of method entries */
|
||||||
|
{
|
||||||
|
#define JERRYX_SET_PROPERTIES_RESULT(VALUE, IDX) ((jerryx_register_result) { VALUE, IDX })
|
||||||
|
uint32_t idx = 0;
|
||||||
|
for (; ((entries + idx) != NULL) && (entries[idx].name != NULL); idx++)
|
||||||
|
{
|
||||||
|
const jerryx_property_entry *entry = &entries[idx];
|
||||||
|
|
||||||
|
jerry_value_t prop_name = jerry_create_string_from_utf8 ((const jerry_char_t *) entry->name);
|
||||||
|
jerry_value_t result = jerry_set_property (target_object, prop_name, entry->value);
|
||||||
|
|
||||||
|
jerry_release_value (prop_name);
|
||||||
|
|
||||||
|
// By API definition:
|
||||||
|
// The jerry_set_property returns TRUE if there is no problem
|
||||||
|
// and error object if there is any problem.
|
||||||
|
// Thus there is no need to check if the boolean value is false or not.
|
||||||
|
if (!jerry_value_is_boolean (result))
|
||||||
|
{
|
||||||
|
return JERRYX_SET_PROPERTIES_RESULT (result, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
jerry_release_value (entry->value);
|
||||||
|
jerry_release_value (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return JERRYX_SET_PROPERTIES_RESULT (jerry_create_undefined (), idx);
|
||||||
|
#undef JERRYX_SET_PROPERTIES_RESULT
|
||||||
|
} /* jerryx_set_properties */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release all jerry_value_t in a jerryx_property_entry array based on
|
||||||
|
* a previous jerryx_set_properties call.
|
||||||
|
*
|
||||||
|
* In case of a successful registration it is safe to call this method.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
jerryx_release_property_entry (const jerryx_property_entry entries[], /**< list of property entries */
|
||||||
|
const jerryx_register_result register_result) /**< previous result of registration */
|
||||||
|
{
|
||||||
|
for (uint32_t idx = register_result.registered;
|
||||||
|
((entries + idx) != NULL) && (entries[idx].name != NULL);
|
||||||
|
idx++)
|
||||||
|
{
|
||||||
|
jerry_release_value (entries[idx].value);
|
||||||
|
}
|
||||||
|
} /* jerryx_release_property_entry */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a property to a specified value with a given name.
|
||||||
|
*
|
||||||
|
* Notes:
|
||||||
|
* - The operation performed is the same as what the `jerry_set_property` method.
|
||||||
|
* - The property name must be a zero terminated UTF-8 string.
|
||||||
|
* - There should be no '\0' (NULL) character in the name excluding the string terminator.
|
||||||
|
* - Returned value must be freed with jerry_release_value, when it is no longer needed.
|
||||||
|
*
|
||||||
|
* @return true value - if the operation was successful
|
||||||
|
* thrown error - otherwise
|
||||||
|
*/
|
||||||
|
jerry_value_t
|
||||||
|
jerryx_set_property_str (const jerry_value_t target_object, /**< target object */
|
||||||
|
const char *name, /**< property name */
|
||||||
|
const jerry_value_t value) /**< value to set */
|
||||||
|
{
|
||||||
|
jerry_value_t property_name_val = jerry_create_string_from_utf8 ((const jerry_char_t *) name);
|
||||||
|
jerry_value_t result_val = jerry_set_property (target_object, property_name_val, value);
|
||||||
|
|
||||||
|
jerry_release_value (property_name_val);
|
||||||
|
|
||||||
|
return result_val;
|
||||||
|
} /* jerryx_set_property_str */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a property value of a specified object.
|
||||||
|
*
|
||||||
|
* Notes:
|
||||||
|
* - The operation performed is the same as what the `jerry_get_property` method.
|
||||||
|
* - The property name must be a zero terminated UTF-8 string.
|
||||||
|
* - There should be no '\0' (NULL) character in the name excluding the string terminator.
|
||||||
|
* - Returned value must be freed with jerry_release_value, when it is no longer needed.
|
||||||
|
*
|
||||||
|
* @return jerry_value_t - the property value
|
||||||
|
*/
|
||||||
|
jerry_value_t
|
||||||
|
jerryx_get_property_str (const jerry_value_t target_object, /**< target object */
|
||||||
|
const char *name) /**< property name */
|
||||||
|
{
|
||||||
|
jerry_value_t prop_name = jerry_create_string_from_utf8 ((const jerry_char_t *) name);
|
||||||
|
jerry_value_t result_val = jerry_get_property (target_object, prop_name);
|
||||||
|
jerry_release_value (prop_name);
|
||||||
|
|
||||||
|
return result_val;
|
||||||
|
} /* jerryx_get_property_str */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a property exists on an object.
|
||||||
|
*
|
||||||
|
* Notes:
|
||||||
|
* - The operation performed is the same as what the `jerry_has_property` method.
|
||||||
|
* - The property name must be a zero terminated UTF-8 string.
|
||||||
|
* - There should be no '\0' (NULL) character in the name excluding the string terminator.
|
||||||
|
*
|
||||||
|
* @return true - if the property exists on the given object.
|
||||||
|
* false - if there is no such property or there was an error accessing the property.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
jerryx_has_property_str (const jerry_value_t target_object, /**< target object */
|
||||||
|
const char *name) /**< property name */
|
||||||
|
{
|
||||||
|
bool has_property = false;
|
||||||
|
|
||||||
|
jerry_value_t prop_name = jerry_create_string_from_utf8 ((const jerry_char_t *) name);
|
||||||
|
jerry_value_t has_prop_val = jerry_has_property (target_object, prop_name);
|
||||||
|
|
||||||
|
if (!jerry_value_is_error (has_prop_val))
|
||||||
|
{
|
||||||
|
has_property = jerry_get_boolean_value (has_prop_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
jerry_release_value (has_prop_val);
|
||||||
|
jerry_release_value (prop_name);
|
||||||
|
|
||||||
|
return has_property;
|
||||||
|
} /* jerryx_has_property_str */
|
||||||
|
|||||||
@@ -45,6 +45,56 @@ jerry_value_t jerryx_handler_gc (const jerry_value_t func_obj_val, const jerry_v
|
|||||||
jerry_value_t jerryx_handler_print (const jerry_value_t func_obj_val, const jerry_value_t this_p,
|
jerry_value_t jerryx_handler_print (const jerry_value_t func_obj_val, const jerry_value_t this_p,
|
||||||
const jerry_value_t args_p[], const jerry_length_t args_cnt);
|
const jerry_value_t args_p[], const jerry_length_t args_cnt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Struct used by the `jerryx_set_functions` method to
|
||||||
|
* register multiple methods for a given object.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const char *name; /**< name of the property to add */
|
||||||
|
jerry_value_t value; /**< value of the property */
|
||||||
|
} jerryx_property_entry;
|
||||||
|
|
||||||
|
#define JERRYX_PROPERTY_NUMBER(NAME, NUMBER) (jerryx_property_entry) { NAME, jerry_create_number (NUMBER) }
|
||||||
|
#define JERRYX_PROPERTY_STRING(NAME, STR) \
|
||||||
|
(jerryx_property_entry) { NAME, jerry_create_string_from_utf8 ((const jerry_char_t *) STR) }
|
||||||
|
#define JERRYX_PROPERTY_STRING_SZ(NAME, STR, SIZE) \
|
||||||
|
(jerryx_property_entry) { NAME, jerry_create_string_sz_from_utf8 ((const jerry_char_t *) STR, SIZE) }
|
||||||
|
#define JERRYX_PROPERTY_BOOLEAN(NAME, VALUE) (jerryx_property_entry) { NAME, jerry_create_boolean (VALUE) }
|
||||||
|
#define JERRYX_PROPERTY_FUNCTION(NAME, FUNC) (jerryx_property_entry) { NAME, jerry_create_external_function (FUNC) }
|
||||||
|
#define JERRYX_PROPERTY_UNDEFINED(NAME) (jerryx_property_entry) { NAME, jerry_create_undefined() }
|
||||||
|
#define JERRYX_PROPERTY_LIST_END() (jerryx_property_entry) { NULL, 0 }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the result of property register operation.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
jerry_value_t result; /**< result of property registraion (undefined or error object) */
|
||||||
|
uint32_t registered; /**< number of successfully registered methods */
|
||||||
|
} jerryx_register_result;
|
||||||
|
|
||||||
|
jerryx_register_result
|
||||||
|
jerryx_set_properties (const jerry_value_t target_object,
|
||||||
|
const jerryx_property_entry entries[]);
|
||||||
|
|
||||||
|
void
|
||||||
|
jerryx_release_property_entry (const jerryx_property_entry entries[],
|
||||||
|
const jerryx_register_result register_result);
|
||||||
|
|
||||||
|
jerry_value_t
|
||||||
|
jerryx_set_property_str (const jerry_value_t target_object,
|
||||||
|
const char *name,
|
||||||
|
const jerry_value_t value);
|
||||||
|
|
||||||
|
jerry_value_t
|
||||||
|
jerryx_get_property_str (const jerry_value_t target_object,
|
||||||
|
const char *name);
|
||||||
|
|
||||||
|
bool
|
||||||
|
jerryx_has_property_str (const jerry_value_t target_object,
|
||||||
|
const char *name);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|||||||
@@ -0,0 +1,316 @@
|
|||||||
|
/* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit test for jerry-ext/handler property registration
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "jerryscript.h"
|
||||||
|
#include "jerryscript-ext/handler.h"
|
||||||
|
#include "test-common.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static jerry_value_t
|
||||||
|
method_hello (const jerry_value_t jfunc, /**< function object */
|
||||||
|
const jerry_value_t jthis, /**< function this */
|
||||||
|
const jerry_value_t jargv[], /**< arguments */
|
||||||
|
const jerry_length_t jargc) /**< number of arguments */
|
||||||
|
{
|
||||||
|
(void) jfunc;
|
||||||
|
(void) jthis;
|
||||||
|
(void) jargv;
|
||||||
|
return jerry_create_number (jargc);
|
||||||
|
} /* method_hello */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to create a non-configurable property on an object
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
freeze_property (jerry_value_t target_obj, /**< target object */
|
||||||
|
const char *target_prop) /**< target property name */
|
||||||
|
{
|
||||||
|
// "freeze" property
|
||||||
|
jerry_property_descriptor_t prop_desc;
|
||||||
|
jerry_init_property_descriptor_fields (&prop_desc);
|
||||||
|
prop_desc.is_configurable_defined = true;
|
||||||
|
prop_desc.is_configurable = false;
|
||||||
|
|
||||||
|
jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) target_prop);
|
||||||
|
jerry_value_t return_value = jerry_define_own_property (target_obj, prop_name, &prop_desc);
|
||||||
|
TEST_ASSERT (jerry_value_is_boolean (return_value));
|
||||||
|
jerry_release_value (return_value);
|
||||||
|
jerry_release_value (prop_name);
|
||||||
|
|
||||||
|
jerry_free_property_descriptor_fields (&prop_desc);
|
||||||
|
} /* freeze_property */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test registration of various property values.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
test_simple_registration (void)
|
||||||
|
{
|
||||||
|
jerry_init (JERRY_INIT_EMPTY);
|
||||||
|
|
||||||
|
jerry_value_t target_object = jerry_create_object ();
|
||||||
|
|
||||||
|
// Test simple registration
|
||||||
|
jerryx_property_entry methods[] =
|
||||||
|
{
|
||||||
|
JERRYX_PROPERTY_FUNCTION ("hello", method_hello),
|
||||||
|
JERRYX_PROPERTY_NUMBER ("my_number", 42.5),
|
||||||
|
JERRYX_PROPERTY_STRING ("my_str", "super_str"),
|
||||||
|
JERRYX_PROPERTY_STRING_SZ ("my_str_sz", "super_str", 6),
|
||||||
|
JERRYX_PROPERTY_BOOLEAN ("my_bool", true),
|
||||||
|
JERRYX_PROPERTY_BOOLEAN ("my_bool_false", false),
|
||||||
|
JERRYX_PROPERTY_UNDEFINED ("my_non_value"),
|
||||||
|
JERRYX_PROPERTY_LIST_END (),
|
||||||
|
};
|
||||||
|
|
||||||
|
jerryx_register_result register_result = jerryx_set_properties (target_object, methods);
|
||||||
|
|
||||||
|
TEST_ASSERT (register_result.registered == 7);
|
||||||
|
TEST_ASSERT (jerry_value_is_undefined (register_result.result));
|
||||||
|
|
||||||
|
jerryx_release_property_entry (methods, register_result);
|
||||||
|
jerry_release_value (register_result.result);
|
||||||
|
|
||||||
|
jerry_value_t global_obj = jerry_get_global_object ();
|
||||||
|
jerryx_set_property_str (global_obj, "test", target_object);
|
||||||
|
jerry_release_value (target_object);
|
||||||
|
jerry_release_value (global_obj);
|
||||||
|
|
||||||
|
{
|
||||||
|
const char *test_A = "test.my_number";
|
||||||
|
jerry_value_t result = jerry_eval ((const jerry_char_t *) test_A, strlen (test_A), 0);
|
||||||
|
TEST_ASSERT (jerry_value_is_number (result));
|
||||||
|
TEST_ASSERT (jerry_get_number_value (result) == 42.5);
|
||||||
|
jerry_release_value (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const char *test_A = "test.my_str_sz === 'super_'";
|
||||||
|
jerry_value_t result = jerry_eval ((const jerry_char_t *) test_A, strlen (test_A), 0);
|
||||||
|
TEST_ASSERT (jerry_value_is_boolean (result));
|
||||||
|
TEST_ASSERT (jerry_get_boolean_value (result) == true);
|
||||||
|
jerry_release_value (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const char *test_A = "test.my_str === 'super_str'";
|
||||||
|
jerry_value_t result = jerry_eval ((const jerry_char_t *) test_A, strlen (test_A), 0);
|
||||||
|
TEST_ASSERT (jerry_value_is_boolean (result));
|
||||||
|
TEST_ASSERT (jerry_get_boolean_value (result) == true);
|
||||||
|
jerry_release_value (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const char *test_A = "test.my_bool";
|
||||||
|
jerry_value_t result = jerry_eval ((const jerry_char_t *) test_A, strlen (test_A), 0);
|
||||||
|
TEST_ASSERT (jerry_value_is_boolean (result));
|
||||||
|
TEST_ASSERT (jerry_get_boolean_value (result) == true);
|
||||||
|
jerry_release_value (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const char *test_A = "test.my_bool_false";
|
||||||
|
jerry_value_t result = jerry_eval ((const jerry_char_t *) test_A, strlen (test_A), 0);
|
||||||
|
TEST_ASSERT (jerry_value_is_boolean (result));
|
||||||
|
TEST_ASSERT (jerry_get_boolean_value (result) == false);
|
||||||
|
jerry_release_value (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const char *test_A = "test.my_non_value";
|
||||||
|
jerry_value_t result = jerry_eval ((const jerry_char_t *) test_A, strlen (test_A), 0);
|
||||||
|
TEST_ASSERT (jerry_value_is_undefined (result));
|
||||||
|
jerry_release_value (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const char *test_A = "test.hello(33, 42, 2);";
|
||||||
|
jerry_value_t result = jerry_eval ((const jerry_char_t *) test_A, strlen (test_A), 0);
|
||||||
|
TEST_ASSERT (jerry_value_is_number (result));
|
||||||
|
TEST_ASSERT ((uint32_t) jerry_get_number_value (result) == 3u);
|
||||||
|
jerry_release_value (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const char *test_A = "test.hello();";
|
||||||
|
jerry_value_t result = jerry_eval ((const jerry_char_t *) test_A, strlen (test_A), 0);
|
||||||
|
TEST_ASSERT (jerry_value_is_number (result));
|
||||||
|
TEST_ASSERT ((uint32_t) jerry_get_number_value (result) == 0u);
|
||||||
|
jerry_release_value (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
jerry_cleanup ();
|
||||||
|
} /* test_simple_registration */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test registration error.
|
||||||
|
*
|
||||||
|
* Trying to register a property which is already a non-configurable property
|
||||||
|
* should result in an error.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
test_error_setvalue (void)
|
||||||
|
{
|
||||||
|
jerry_init (JERRY_INIT_EMPTY);
|
||||||
|
|
||||||
|
const char *target_prop = "test_err";
|
||||||
|
jerry_value_t global_obj = jerry_get_global_object ();
|
||||||
|
freeze_property (global_obj, target_prop);
|
||||||
|
|
||||||
|
jerry_value_t new_object = jerry_create_object ();
|
||||||
|
jerry_value_t set_result = jerryx_set_property_str (global_obj, target_prop, new_object);
|
||||||
|
TEST_ASSERT (jerry_value_is_error (set_result));
|
||||||
|
|
||||||
|
jerry_release_value (set_result);
|
||||||
|
jerry_release_value (new_object);
|
||||||
|
jerry_release_value (global_obj);
|
||||||
|
|
||||||
|
jerry_cleanup ();
|
||||||
|
} /* test_error_setvalue */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test registration error with jerryx_set_properties.
|
||||||
|
*
|
||||||
|
* Trying to register a property which is already a non-configurable property
|
||||||
|
* should result in an error.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
test_error_single_function (void)
|
||||||
|
{
|
||||||
|
jerry_init (JERRY_INIT_EMPTY);
|
||||||
|
|
||||||
|
const char *target_prop = "test_err";
|
||||||
|
jerry_value_t target_object = jerry_create_object ();
|
||||||
|
freeze_property (target_object, target_prop);
|
||||||
|
|
||||||
|
jerryx_property_entry methods[] =
|
||||||
|
{
|
||||||
|
JERRYX_PROPERTY_FUNCTION (target_prop, method_hello), // This registration should fail
|
||||||
|
JERRYX_PROPERTY_LIST_END (),
|
||||||
|
};
|
||||||
|
|
||||||
|
jerryx_register_result register_result = jerryx_set_properties (target_object, methods);
|
||||||
|
|
||||||
|
TEST_ASSERT (register_result.registered == 0);
|
||||||
|
TEST_ASSERT (jerry_value_is_error (register_result.result));
|
||||||
|
jerryx_release_property_entry (methods, register_result);
|
||||||
|
jerry_release_value (register_result.result);
|
||||||
|
|
||||||
|
jerry_release_value (target_object);
|
||||||
|
|
||||||
|
jerry_cleanup ();
|
||||||
|
} /* test_error_single_function */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test to see if jerryx_set_properties exits at the first error.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
test_error_multiple_functions (void)
|
||||||
|
{
|
||||||
|
jerry_init (JERRY_INIT_EMPTY);
|
||||||
|
|
||||||
|
const char *prop_ok = "prop_ok";
|
||||||
|
const char *prop_err = "prop_err";
|
||||||
|
const char *prop_not = "prop_not";
|
||||||
|
jerry_value_t target_object = jerry_create_object ();
|
||||||
|
freeze_property (target_object, prop_err);
|
||||||
|
|
||||||
|
jerryx_property_entry methods[] =
|
||||||
|
{
|
||||||
|
JERRYX_PROPERTY_FUNCTION (prop_ok, method_hello), // This registration is ok
|
||||||
|
JERRYX_PROPERTY_FUNCTION (prop_err, method_hello), // This registration should fail
|
||||||
|
JERRYX_PROPERTY_FUNCTION (prop_not, method_hello), // This registration is not done
|
||||||
|
JERRYX_PROPERTY_LIST_END (),
|
||||||
|
};
|
||||||
|
|
||||||
|
jerryx_register_result register_result = jerryx_set_properties (target_object, methods);
|
||||||
|
|
||||||
|
TEST_ASSERT (register_result.registered == 1);
|
||||||
|
TEST_ASSERT (jerry_value_is_error (register_result.result));
|
||||||
|
|
||||||
|
jerryx_release_property_entry (methods, register_result);
|
||||||
|
jerry_release_value (register_result.result);
|
||||||
|
|
||||||
|
{
|
||||||
|
// Test if property "prop_ok" is correctly registered.
|
||||||
|
jerry_value_t prop_ok_val = jerry_create_string ((const jerry_char_t *) prop_ok);
|
||||||
|
jerry_value_t prop_ok_exists = jerry_has_own_property (target_object, prop_ok_val);
|
||||||
|
TEST_ASSERT (jerry_get_boolean_value (prop_ok_exists) == true);
|
||||||
|
jerry_release_value (prop_ok_exists);
|
||||||
|
|
||||||
|
// Try calling the method
|
||||||
|
jerry_value_t prop_ok_func = jerry_get_property (target_object, prop_ok_val);
|
||||||
|
TEST_ASSERT (jerry_value_is_function (prop_ok_func) == true);
|
||||||
|
jerry_value_t args[2] =
|
||||||
|
{
|
||||||
|
jerry_create_number (22),
|
||||||
|
jerry_create_number (-3),
|
||||||
|
};
|
||||||
|
jerry_size_t args_cnt = sizeof (args) / sizeof (jerry_value_t);
|
||||||
|
jerry_value_t func_result = jerry_call_function (prop_ok_func,
|
||||||
|
jerry_create_undefined (),
|
||||||
|
args,
|
||||||
|
args_cnt);
|
||||||
|
TEST_ASSERT (jerry_value_is_number (func_result) == true);
|
||||||
|
TEST_ASSERT ((uint32_t) jerry_get_number_value (func_result) == 2u);
|
||||||
|
jerry_release_value (func_result);
|
||||||
|
for (jerry_size_t idx = 0; idx < args_cnt; idx++)
|
||||||
|
{
|
||||||
|
jerry_release_value (args[idx]);
|
||||||
|
}
|
||||||
|
jerry_release_value (prop_ok_func);
|
||||||
|
jerry_release_value (prop_ok_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// The "prop_err" should exist - as it was "freezed" - but it should not be a function
|
||||||
|
jerry_value_t prop_err_val = jerry_create_string ((const jerry_char_t *) prop_err);
|
||||||
|
jerry_value_t prop_err_exists = jerry_has_own_property (target_object, prop_err_val);
|
||||||
|
TEST_ASSERT (jerry_get_boolean_value (prop_err_exists) == true);
|
||||||
|
jerry_release_value (prop_err_exists);
|
||||||
|
|
||||||
|
jerry_value_t prop_err_func = jerry_value_is_function (prop_err_val);
|
||||||
|
TEST_ASSERT (jerry_value_is_function (prop_err_func) == false);
|
||||||
|
jerry_release_value (prop_err_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // The "prop_not" is not available on the target object
|
||||||
|
jerry_value_t prop_not_val = jerry_create_string ((const jerry_char_t *) prop_not);
|
||||||
|
jerry_value_t prop_not_exists = jerry_has_own_property (target_object, prop_not_val);
|
||||||
|
TEST_ASSERT (jerry_get_boolean_value (prop_not_exists) == false);
|
||||||
|
jerry_release_value (prop_not_exists);
|
||||||
|
jerry_release_value (prop_not_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
jerry_release_value (target_object);
|
||||||
|
|
||||||
|
jerry_cleanup ();
|
||||||
|
} /* test_error_multiple_functions */
|
||||||
|
|
||||||
|
int
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
test_simple_registration ();
|
||||||
|
test_error_setvalue ();
|
||||||
|
test_error_single_function ();
|
||||||
|
test_error_multiple_functions ();
|
||||||
|
return 0;
|
||||||
|
} /* main */
|
||||||
Reference in New Issue
Block a user