Rework the public API (#4829)

Related to #4186.

Some notable changes:
  - The term 'Error' now strictly refers to native Error objects defined in
    the ECMA standard, which are ordinary objects. All other uses of
    'error' or 'error reference' where the term refers to a thrown value is
    now called 'exception'.

  - Simplified the naming scheme of many String API functions. These functions
    will now also take an 'encoding' argument to specify the desired
    encoding in which to operate.

  - Removed the substring-copy-to-buffer functions. These functions
    behaved awkwardly, as they use character index to specify the
    start/end positions, and were mostly used incorrectly with byte
    offsets instead. The functionality can still be replicated with
    other functions if necessary.

  - String-to-buffer functions will no longer fail if the buffer is not
    sufficiently large, the string will instead be cropped.

  - Fixed the usage of the '_sz' prefix in many API functions. The term
    'sz' means zero-terminated string in hungarian notation, this was
    used incorrectly in many cases.

  - Renamed most of the public API functions to have shorter, more on-point
    names, rather than the often too long descriptive names. Functions are now
    also grouped by the type of value they operate on, where this makes
    sense.

JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai dbatyai@inf.u-szeged.hu
This commit is contained in:
Dániel Bátyai
2021-12-06 10:20:09 +01:00
committed by GitHub
parent 81d2319144
commit 9860d66a56
180 changed files with 10738 additions and 11025 deletions
+112 -151
View File
@@ -35,47 +35,14 @@ Test if the `pkg-config` works for JerryScript:
$ pkg-config --cflags --libs libjerry-core libjerry-port-default libjerry-ext libjerry-math
```
## Example 1. Execute JavaScript from your application
The most basic example to test the engine is to create an `api-example-1.c` file containing the following code:
[doctest]: # ()
```c
#include "jerryscript.h"
int
main (void)
{
const jerry_char_t script[] = "var str = 'Hello, World!';";
bool ret_value = jerry_run_simple (script, sizeof (script) - 1, JERRY_INIT_EMPTY);
return (ret_value ? 0 : 1);
}
```
To compile it one can use the following command:
```sh
$ gcc api-example-1.c -o api-example-1 $(pkg-config --cflags --libs libjerry-core libjerry-port-default libjerry-math)
```
If everything is correct the application returns with a zero exit code:
```
$ ./api-example-1
$ echo $?
```
## Example 2. Split engine initialization and script execution.
In this example the engine is initialized directly with the `jerry_init` method
and cleaned up with the `jerry_cleanup` method. The example JavaScript code
is directly parsed and executed via the `jerry_eval` method. Each `jerry_value_t`
returned by the API methods is freed with the `jerry_release_value` method.
returned by the API methods is freed with the `jerry_value_free` method.
To make sure that the code parsing and execution was ok, the `jerry_value_is_error`
To make sure that the code parsing and execution was ok, the `jerry_value_is_exception`
method is used to check for any errors.
Use the following code for the `api-example-2.c` file:
@@ -103,10 +70,10 @@ main (void)
JERRY_PARSE_NO_OPTS);
/* Check if there was any error (syntax or runtime) */
bool run_ok = !jerry_value_is_error (eval_ret);
bool run_ok = !jerry_value_is_exception (eval_ret);
/* Parsed source code must be freed */
jerry_release_value (eval_ret);
jerry_value_free (eval_ret);
/* Cleanup engine */
jerry_cleanup ();
@@ -156,20 +123,20 @@ main (void)
jerry_value_t parsed_code = jerry_parse (script, sizeof (script) - 1, NULL);
/* Check if there is any JS code parse error */
if (!jerry_value_is_error (parsed_code))
if (!jerry_value_is_exception (parsed_code))
{
/* Execute the parsed source code in the Global scope */
jerry_value_t ret_value = jerry_run (parsed_code);
/* Check the execution return value if there is any error */
run_ok = !jerry_value_is_error (ret_value);
run_ok = !jerry_value_is_exception (ret_value);
/* Returned value must be freed */
jerry_release_value (ret_value);
jerry_value_free (ret_value);
}
/* Parsed source code must be freed */
jerry_release_value (parsed_code);
jerry_value_free (parsed_code);
/* Cleanup engine */
jerry_cleanup ();
@@ -200,10 +167,10 @@ In this example a very simple "print" method is added which prints out a static
This method will be implemented in C and will be called from the JavaScript code.
For this a few extra API methods are required:
- `jerry_get_global_object`
- `jerry_create_string`
- `jerry_set_property`
- `jerry_create_external_function`
- `jerry_current_realm`
- `jerry_string_sz`
- `jerry_object_set`
- `jerry_function_external`
The `api-example-4.c` file should contain the following code:
@@ -223,7 +190,7 @@ print_handler (const jerry_call_info_t *call_info_p,
printf ("Print handler was called\n");
/* Return an "undefined" value to the JavaScript engine */
return jerry_create_undefined ();
return jerry_undefined ();
}
int
@@ -238,40 +205,40 @@ main (void)
/* Add the "print" method for the JavaScript global object */
{
/* Get the "global" object */
jerry_value_t global_object = jerry_get_global_object ();
jerry_value_t global_object = jerry_current_realm ();
/* Create a "print" JS string */
jerry_value_t property_name_print = jerry_create_string ((const jerry_char_t *) "print");
jerry_value_t property_name_print = jerry_string_sz ("print");
/* Create a function from a native C method (this function will be called from JS) */
jerry_value_t property_value_func = jerry_create_external_function (print_handler);
jerry_value_t property_value_func = jerry_function_external (print_handler);
/* Add the "print" property with the function value to the "global" object */
jerry_value_t set_result = jerry_set_property (global_object, property_name_print, property_value_func);
jerry_value_t set_result = jerry_object_set (global_object, property_name_print, property_value_func);
/* Check if there was no error when adding the property (in this case it should never happen) */
if (jerry_value_is_error (set_result)) {
if (jerry_value_is_exception (set_result)) {
printf ("Failed to add the 'print' property\n");
}
/* Release all jerry_value_t-s */
jerry_release_value (set_result);
jerry_release_value (property_value_func);
jerry_release_value (property_name_print);
jerry_release_value (global_object);
jerry_value_free (set_result);
jerry_value_free (property_value_func);
jerry_value_free (property_name_print);
jerry_value_free (global_object);
}
/* Setup Global scope code */
jerry_value_t parsed_code = jerry_parse (script, script_size, NULL);
if (!jerry_value_is_error (parsed_code))
if (!jerry_value_is_exception (parsed_code))
{
/* Execute the parsed source code in the Global scope */
jerry_value_t ret_value = jerry_run (parsed_code);
/* Returned value must be freed */
jerry_release_value (ret_value);
jerry_value_free (ret_value);
}
/* Parsed source code must be freed */
jerry_release_value (parsed_code);
jerry_value_free (parsed_code);
/* Cleanup engine */
jerry_cleanup ();
@@ -304,7 +271,7 @@ argument (which probably comes from a JavaScript source) to a JS string and prin
New API methods used:
- `jerry_value_to_string`
- `jerry_string_to_utf8_char_buffer`
- `jerry_string_to_buffer`
The `api-example-5.c` file should contain the following code:
@@ -332,17 +299,17 @@ print_handler (const jerry_call_info_t *call_info_p,
* Please note that if the string does not fit into the buffer nothing will be copied.
* More details on the API reference page
*/
jerry_size_t copied_bytes = jerry_string_to_utf8_char_buffer (string_value, buffer, sizeof (buffer) - 1);
jerry_size_t copied_bytes = jerry_string_to_buffer (string_value, JERRY_ENCODING_UTF8, buffer, sizeof (buffer) - 1);
buffer[copied_bytes] = '\0';
/* Release the "toString" result */
jerry_release_value (string_value);
jerry_value_free (string_value);
printf ("%s\n", (const char *)buffer);
}
/* Return an "undefined" value to the JavaScript engine */
return jerry_create_undefined ();
return jerry_undefined ();
}
int
@@ -357,40 +324,40 @@ main (void)
/* Add the "print" method for the JavaScript global object */
{
/* Get the "global" object */
jerry_value_t global_object = jerry_get_global_object ();
jerry_value_t global_object = jerry_current_realm ();
/* Create a "print" JS string */
jerry_value_t property_name_print = jerry_create_string ((const jerry_char_t *) "print");
jerry_value_t property_name_print = jerry_string_sz ("print");
/* Create a function from a native C method (this function will be called from JS) */
jerry_value_t property_value_func = jerry_create_external_function (print_handler);
jerry_value_t property_value_func = jerry_function_external (print_handler);
/* Add the "print" property with the function value to the "global" object */
jerry_value_t set_result = jerry_set_property (global_object, property_name_print, property_value_func);
jerry_value_t set_result = jerry_object_set (global_object, property_name_print, property_value_func);
/* Check if there was no error when adding the property (in this case it should never happen) */
if (jerry_value_is_error (set_result)) {
if (jerry_value_is_exception (set_result)) {
printf ("Failed to add the 'print' property\n");
}
/* Release all jerry_value_t-s */
jerry_release_value (set_result);
jerry_release_value (property_value_func);
jerry_release_value (property_name_print);
jerry_release_value (global_object);
jerry_value_free (set_result);
jerry_value_free (property_value_func);
jerry_value_free (property_name_print);
jerry_value_free (global_object);
}
/* Setup Global scope code */
jerry_value_t parsed_code = jerry_parse (script, script_size, NULL);
if (!jerry_value_is_error (parsed_code))
if (!jerry_value_is_exception (parsed_code))
{
/* Execute the parsed source code in the Global scope */
jerry_value_t ret_value = jerry_run (parsed_code);
/* Returned value must be freed */
jerry_release_value (ret_value);
jerry_value_free (ret_value);
}
/* Parsed source code must be freed */
jerry_release_value (parsed_code);
jerry_value_free (parsed_code);
/* Cleanup engine */
jerry_cleanup ();
@@ -440,23 +407,22 @@ main (void)
jerry_init (JERRY_INIT_EMPTY);
/* Register 'print' function from the extensions to the global object */
jerryx_handler_register_global ((const jerry_char_t *) "print",
jerryx_handler_print);
jerryx_handler_register_global ("print", jerryx_handler_print);
/* Setup Global scope code */
jerry_value_t parsed_code = jerry_parse (script, script_size, NULL);
if (!jerry_value_is_error (parsed_code))
if (!jerry_value_is_exception (parsed_code))
{
/* Execute the parsed source code in the Global scope */
jerry_value_t ret_value = jerry_run (parsed_code);
/* Returned value must be freed */
jerry_release_value (ret_value);
jerry_value_free (ret_value);
}
/* Parsed source code must be freed */
jerry_release_value (parsed_code);
jerry_value_free (parsed_code);
/* Cleanup engine */
jerry_cleanup ();
@@ -502,30 +468,29 @@ main (void)
jerry_init (JERRY_INIT_EMPTY);
/* Register 'print' function from the extensions */
jerryx_handler_register_global ((const jerry_char_t *) "print",
jerryx_handler_print);
jerryx_handler_register_global ("print", jerryx_handler_print);
/* Getting pointer to the Global object */
jerry_value_t global_object = jerry_get_global_object ();
jerry_value_t global_object = jerry_current_realm ();
/* Constructing strings */
jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) "my_var");
jerry_value_t prop_value = jerry_create_string ((const jerry_char_t *) "Hello from C!");
jerry_value_t prop_name = jerry_string_sz ("my_var");
jerry_value_t prop_value = jerry_string_sz ("Hello from C!");
/* Setting the string value as a property of the Global object */
jerry_value_t set_result = jerry_set_property (global_object, prop_name, prop_value);
jerry_value_t set_result = jerry_object_set (global_object, prop_name, prop_value);
/* The 'set_result' should be checked if there was any error */
if (jerry_value_is_error (set_result)) {
if (jerry_value_is_exception (set_result)) {
printf ("Failed to add the 'my_var' property\n");
}
jerry_release_value (set_result);
jerry_value_free (set_result);
/* Releasing string values, as it is no longer necessary outside of engine */
jerry_release_value (prop_name);
jerry_release_value (prop_value);
jerry_value_free (prop_name);
jerry_value_free (prop_value);
/* Releasing the Global object */
jerry_release_value (global_object);
jerry_value_free (global_object);
/* Now starting script that would output value of just initialized field */
jerry_value_t eval_ret = jerry_eval (script,
@@ -533,7 +498,7 @@ main (void)
JERRY_PARSE_NO_OPTS);
/* Free JavaScript value, returned by eval */
jerry_release_value (eval_ret);
jerry_value_free (eval_ret);
/* Freeing engine */
jerry_cleanup ();
@@ -561,9 +526,9 @@ $ ./api-example-7
JerryScript value can be a boolean, number, null, object, string, undefined or some special type of objects (arraybuffer, symbols, etc).
There is a special "error" value which wraps another value. This "error" can be created by throwing a JavaScript value from JS code
or via API method(s). It is advised to check for this error with the `jerry_value_is_error` method as not all API methods
can process error values. To extract the value from the "error" the API method `jerry_get_value_from_error` should be used.
If an error object is created via API method (for example with `jerry_create_error`) the "error" value is automatically created.
or via API method(s). It is advised to check for this error with the `jerry_value_is_exception` method as not all API methods
can process error values. To extract the value from the "error" the API method `jerry_exception_value` should be used.
If an error object is created via API method (for example with `jerry_error`) the "error" value is automatically created.
Notice the difference between error value and error object:
- The error object is a object which was constructed via one of the `Error` objects (available from the global object or from API).
@@ -580,7 +545,7 @@ var error_object = new Error ("error message");
throw "message";
```
To check what type a given `jerry_value_t` is the `jerry_value_is_*` methods or the `jerry_value_get_type` could be used.
To check what type a given `jerry_value_t` is the `jerry_value_is_*` methods or the `jerry_value_type` could be used.
For example the following code snippet could print out a few types (not all types are checked):
[doctest]: # (test="compile")
@@ -595,14 +560,14 @@ print_value (const jerry_value_t jsvalue)
{
jerry_value_t value;
/* If there is an error extract the object from it */
if (jerry_value_is_error (jsvalue))
if (jerry_value_is_exception (jsvalue))
{
printf ("Error value detected: ");
value = jerry_get_value_from_error (jsvalue, false);
value = jerry_exception_value (jsvalue, false);
}
else
{
value = jerry_acquire_value (jsvalue);
value = jerry_value_copy (jsvalue);
}
if (jerry_value_is_undefined (value))
@@ -627,7 +592,7 @@ print_value (const jerry_value_t jsvalue)
/* Float value */
else if (jerry_value_is_number (value))
{
printf ("number: %lf", jerry_get_number_value (value));
printf ("number: %lf", jerry_value_as_number (value));
}
/* String value */
else if (jerry_value_is_string (value))
@@ -635,11 +600,11 @@ print_value (const jerry_value_t jsvalue)
jerry_char_t str_buf_p[256];
/* Determining required buffer size */
jerry_size_t req_sz = jerry_get_string_size (value);
jerry_size_t req_sz = jerry_string_size (value, JERRY_ENCODING_CESU8);
if (req_sz <= 255)
{
jerry_string_to_char_buffer (value, str_buf_p, req_sz);
jerry_string_to_buffer (value, JERRY_ENCODING_CESU8, str_buf_p, req_sz);
str_buf_p[req_sz] = '\0';
printf ("%s", (const char *) str_buf_p);
}
@@ -655,7 +620,7 @@ print_value (const jerry_value_t jsvalue)
}
printf ("\n");
jerry_release_value (value);
jerry_value_free (value);
}
```
@@ -689,14 +654,14 @@ print_value (const jerry_value_t jsvalue)
{
jerry_value_t value;
/* If there is an error extract the object from it */
if (jerry_value_is_error (jsvalue))
if (jerry_value_is_exception (jsvalue))
{
printf ("Error value detected: ");
value = jerry_get_value_from_error (jsvalue, false);
value = jerry_exception_value (jsvalue, false);
}
else
{
value = jerry_acquire_value (jsvalue);
value = jerry_value_copy (jsvalue);
}
if (jerry_value_is_undefined (value))
@@ -721,7 +686,7 @@ print_value (const jerry_value_t jsvalue)
/* Float value */
else if (jerry_value_is_number (value))
{
printf ("number: %lf", jerry_get_number_value (value));
printf ("number: %lf", jerry_value_as_number (value));
}
/* String value */
else if (jerry_value_is_string (value))
@@ -729,11 +694,11 @@ print_value (const jerry_value_t jsvalue)
jerry_char_t str_buf_p[256];
/* Determining required buffer size */
jerry_size_t req_sz = jerry_get_string_size (value);
jerry_size_t req_sz = jerry_string_size (value, JERRY_ENCODING_CESU8);
if (req_sz <= 255)
{
jerry_string_to_char_buffer (value, str_buf_p, req_sz);
jerry_string_to_buffer (value, JERRY_ENCODING_CESU8, str_buf_p, req_sz);
str_buf_p[req_sz] = '\0';
printf ("%s", (const char *) str_buf_p);
}
@@ -749,7 +714,7 @@ print_value (const jerry_value_t jsvalue)
}
printf ("\n");
jerry_release_value (value);
jerry_value_free (value);
}
int
@@ -761,8 +726,7 @@ main (void)
jerry_init (JERRY_INIT_EMPTY);
/* Register 'print' function from the extensions */
jerryx_handler_register_global ((const jerry_char_t *) "print",
jerryx_handler_print);
jerryx_handler_register_global ("print", jerryx_handler_print);
while (!is_done)
{
@@ -805,7 +769,7 @@ main (void)
/* Print out the value */
print_value (ret_val);
jerry_release_value (ret_val);
jerry_value_free (ret_val);
}
/* Cleanup engine */
@@ -853,7 +817,7 @@ get_msg_handler (const jerry_call_info_t *call_info_p, /**< call information */
const jerry_value_t *args_p, /**< function arguments */
const jerry_length_t args_cnt) /**< number of function arguments */
{
return jerry_create_string ((const jerry_char_t *) my_struct.msg);
return jerry_string_sz (my_struct.msg);
} /* get_msg_handler */
int
@@ -863,33 +827,32 @@ main (void)
jerry_init (JERRY_INIT_EMPTY);
/* Register 'print' function from the extensions */
jerryx_handler_register_global ((const jerry_char_t *) "print",
jerryx_handler_print);
jerryx_handler_register_global ("print", jerryx_handler_print);
/* Do something with the native object */
my_struct.msg = "Hello, World!";
/* Create an empty JS object */
jerry_value_t object = jerry_create_object ();
jerry_value_t object = jerry_object ();
/* Create a JS function object and wrap into a jerry value */
jerry_value_t func_obj = jerry_create_external_function (get_msg_handler);
jerry_value_t func_obj = jerry_function_external (get_msg_handler);
/* Set the native function as a property of the empty JS object */
jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) "myFunc");
jerry_release_value (jerry_set_property (object, prop_name, func_obj));
jerry_release_value (prop_name);
jerry_release_value (func_obj);
jerry_value_t prop_name = jerry_string_sz ("myFunc");
jerry_value_free (jerry_object_set (object, prop_name, func_obj));
jerry_value_free (prop_name);
jerry_value_free (func_obj);
/* Wrap the JS object (not empty anymore) into a jerry api value */
jerry_value_t global_object = jerry_get_global_object ();
jerry_value_t global_object = jerry_current_realm ();
/* Add the JS object to the global context */
prop_name = jerry_create_string ((const jerry_char_t *) "MyObject");
jerry_release_value (jerry_set_property (global_object, prop_name, object));
jerry_release_value (prop_name);
jerry_release_value (object);
jerry_release_value (global_object);
prop_name = jerry_string_sz ("MyObject");
jerry_value_free (jerry_object_set (global_object, prop_name, object));
jerry_value_free (prop_name);
jerry_value_free (object);
jerry_value_free (global_object);
/* Now we have a "builtin" object called MyObject with a function called myFunc()
*
@@ -905,7 +868,7 @@ main (void)
jerry_value_t eval_ret = jerry_eval (script, sizeof (script) - 1, JERRY_PARSE_NO_OPTS);
/* Free JavaScript value, returned by eval */
jerry_release_value (eval_ret);
jerry_value_free (eval_ret);
/* Cleanup engine */
jerry_cleanup ();
@@ -960,27 +923,27 @@ add_handler (const jerry_call_info_t *call_info_p, /**< call information */
/* Note: that the argument count check is ignored for the example's case */
/* Get 'this.x' */
jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) "x");
jerry_value_t x_val = jerry_get_property (call_info_p->this_value, prop_name);
jerry_value_t prop_name = jerry_string_sz ("x");
jerry_value_t x_val = jerry_object_get (call_info_p->this_value, prop_name);
if (!jerry_value_is_error (x_val))
if (!jerry_value_is_exception (x_val))
{
/* Convert Jerry API values to double */
double x = jerry_get_number_value (x_val);
double d = jerry_get_number_value (args_p[0]);
double x = jerry_value_as_number (x_val);
double d = jerry_value_as_number (args_p[0]);
/* Add the parameter to 'x' */
jerry_value_t res_val = jerry_create_number (x + d);
jerry_value_t res_val = jerry_number (x + d);
/* Set the new value of 'this.x' */
jerry_release_value (jerry_set_property (call_info_p->this_value, prop_name, res_val));
jerry_release_value (res_val);
jerry_value_free (jerry_object_set (call_info_p->this_value, prop_name, res_val));
jerry_value_free (res_val);
}
jerry_release_value (x_val);
jerry_release_value (prop_name);
jerry_value_free (x_val);
jerry_value_free (prop_name);
return jerry_create_undefined ();
return jerry_undefined ();
} /* add_handler */
int
@@ -990,8 +953,7 @@ main (void)
jerry_init (JERRY_INIT_EMPTY);
/* Register 'print' function from the extensions */
jerryx_handler_register_global ((const jerry_char_t *) "print",
jerryx_handler_print);
jerryx_handler_register_global ("print", jerryx_handler_print);
/* Create a JS object */
const jerry_char_t my_js_object[] = " \
@@ -1013,16 +975,16 @@ main (void)
JERRY_PARSE_NO_OPTS);
/* Create a JS function object and wrap into a jerry value */
jerry_value_t add_func_obj = jerry_create_external_function (add_handler);
jerry_value_t add_func_obj = jerry_function_external (add_handler);
/* Set the native function as a property of previously created MyObject */
jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) "add2x");
jerry_release_value (jerry_set_property (my_js_obj_val, prop_name, add_func_obj));
jerry_release_value (add_func_obj);
jerry_release_value (prop_name);
jerry_value_t prop_name = jerry_string_sz ("add2x");
jerry_value_free (jerry_object_set (my_js_obj_val, prop_name, add_func_obj));
jerry_value_free (add_func_obj);
jerry_value_free (prop_name);
/* Free JavaScript value, returned by eval (my_js_object) */
jerry_release_value (my_js_obj_val);
jerry_value_free (my_js_obj_val);
const jerry_char_t script[] = " \
var str = MyObject.foo (); \
@@ -1035,7 +997,7 @@ main (void)
jerry_value_t eval_ret = jerry_eval (script, sizeof (script) - 1, JERRY_PARSE_NO_OPTS);
/* Free JavaScript value, returned by eval */
jerry_release_value (eval_ret);
jerry_value_free (eval_ret);
/* Cleanup engine */
jerry_cleanup ();
@@ -1090,14 +1052,13 @@ main (void)
jerry_init (JERRY_INIT_EMPTY);
/* Register the print function */
jerryx_handler_register_global ((const jerry_char_t *) "print",
jerryx_handler_print);
jerryx_handler_register_global ("print", jerryx_handler_print);
/* Evaluate the script */
jerry_value_t eval_ret = jerry_eval (script, sizeof (script) - 1, JERRY_PARSE_NO_OPTS);
/* Free the JavaScript value returned by eval */
jerry_release_value (eval_ret);
jerry_value_free (eval_ret);
/* Cleanup the engine */
jerry_cleanup ();