Skip to content

Latest commit

 

History

History
1111 lines (834 loc) · 30.6 KB

03.API-EXAMPLE.md

File metadata and controls

1111 lines (834 loc) · 30.6 KB

JerryScript Engine can be embedded into any application, providing the way to run JavaScript in a large range of environments - from desktops to low-memory microcontrollers.

This guide is intended to introduce you to JerryScript embedding API and to create a minimal JavaScript shell. The examples are not using all API methods please also check out the API reference document which contains additional examples.

Before trying out the examples: Get and build JerryScript library

Before getting started using the JerryScript library it should be cloned and built for a target os/device.

There are quite a few configuration options but for these examples the JerryScript is built with default configuration and installed to a user directory on a Linux system. This is done by the following commands:

$ mkdir jerry
$ cd jerry
$ git clone https://github.com/jerryscript-project/jerryscript.git
$ jerryscript/tools/build.py --builddir=$(pwd)/example_build --cmake-param="-DCMAKE_INSTALL_PREFIX=$(pwd)/example_install/"
$ make -C $(pwd)/example_build install

With this the JerryScript library is installed into the $(pwd)/example_install/{include,lib} directories.

In this guide we will use pkg-config to ease the usage of headers and libraries. In order to do so, the following export is required (executed from the jerry directory):

$ export PKG_CONFIG_PATH=$(pwd)/example_install/lib/pkgconfig/

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:

#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:

$ 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.

To make sure that the code parsing and execution was ok, the jerry_value_is_error method is used to check for any errors.

Use the following code for the api-example-2.c file:

#include "jerryscript.h"

int
main (void)
{
  const jerry_char_t script[] = "var str = 'Hello, World!';";
  const jerry_length_t script_size = sizeof (script) - 1;
  /* Note: sizeof can be used here only because the compiler knows the static character arrays's size.
   * If this is not the case, strlen should be used instead.
   */

  /* Initialize engine */
  jerry_init (JERRY_INIT_EMPTY);

  /* Run the demo script with 'eval' */
  jerry_value_t eval_ret = jerry_eval (script,
                                       script_size,
                                       JERRY_PARSE_NO_OPTS);

  /* Check if there was any error (syntax or runtime) */
  bool run_ok = !jerry_value_is_error (eval_ret);

  /* Parsed source code must be freed */
  jerry_release_value (eval_ret);

  /* Cleanup engine */
  jerry_cleanup ();

  return (run_ok ? 0 : 1);
}

To compile it one can use the following command:

$ gcc api-example-2.c -o api-example-2 $(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-2
$ echo $?

Example 3. Split JavaScript parsing and script execution

In this example the jerry_eval is replaced with a more common API calls:

  • script code setup - jerry_parse.
  • script execution - jerry_run.

The api-example-3.c file should contain the following code:

#include "jerryscript.h"

int
main (void)
{
  bool run_ok = false;

  const jerry_char_t script[] = "var str = 'Hello, World!';";

  /* Initialize engine */
  jerry_init (JERRY_INIT_EMPTY);

  /* Setup Global scope code */
  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))
  {
    /* 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);

    /* Returned value must be freed */
    jerry_release_value (ret_value);
  }

  /* Parsed source code must be freed */
  jerry_release_value (parsed_code);

  /* Cleanup engine */
  jerry_cleanup ();

  return (run_ok ? 0 : 1);
}

To compile it one can use the following command:

$ gcc api-example-3.c -o api-example-3 $(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-3
$ echo $?

Example 4. Adding a C method for JavaScript

The previous examples were not that eye catching as there were no visual output by the JavaScript code and C program.

In this example a very simple "print" method is added which prints out a static string. 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

The api-example-4.c file should contain the following code:

#include <stdio.h>
#include "jerryscript.h"

static jerry_value_t
print_handler (const jerry_call_info_t *call_info_p,
               const jerry_value_t arguments[],
               const jerry_length_t argument_count)
{
  /* No arguments are used in this example */
  /* Print out a static string */
  printf ("Print handler was called\n");

  /* Return an "undefined" value to the JavaScript engine */
  return jerry_create_undefined ();
}

int
main (void)
{
  const jerry_char_t script[] = "print ();";
  const jerry_length_t script_size = sizeof (script) - 1;

  /* Initialize engine */
  jerry_init (JERRY_INIT_EMPTY);

  /* Add the "print" method for the JavaScript global object */
  {
    /* Get the "global" object */
    jerry_value_t global_object = jerry_get_global_object ();
    /* Create a "print" JS string */
    jerry_value_t property_name_print = jerry_create_string ((const jerry_char_t *) "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);
    /* 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);

    /* Check if there was no error when adding the property (in this case it should never happen) */
    if (jerry_value_is_error (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);
  }

  /* Setup Global scope code */
  jerry_value_t parsed_code = jerry_parse (script, script_size, NULL);

  if (!jerry_value_is_error (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);
  }

  /* Parsed source code must be freed */
  jerry_release_value (parsed_code);

  /* Cleanup engine */
  jerry_cleanup ();

  return 0;
}

To compile it one can use the following command:

$ gcc api-example-4.c -o api-example-4 $(pkg-config --cflags --libs libjerry-core libjerry-port-default libjerry-math)

If everything is correct the application should print out the message present in the print_handler method:

$ ./api-example-4

Example 5. Passing and processing arguments for native C code

In the previous example the print_handler simply wrote a static string to the standard output. However in most cases this is not useful, ideally the method's argument(s) should be printed.

In this example the print_handler is extended to convert the first argument (which probably comes from a JavaScript source) to a JS string and prints it out to the standard output.

New API methods used:

  • jerry_value_to_string
  • jerry_string_to_utf8_char_buffer

The api-example-5.c file should contain the following code:

#include <stdio.h>
#include "jerryscript.h"

static jerry_value_t
print_handler (const jerry_call_info_t *call_info_p,
               const jerry_value_t arguments[],
               const jerry_length_t arguments_count)
{
  /* There should be at least one argument */
  if (arguments_count > 0)
  {
    /* Convert the first argument to a string (JS "toString" operation) */
    jerry_value_t string_value = jerry_value_to_string (arguments[0]);

    /* A naive allocation of buffer for the string */
    jerry_char_t buffer[256];

    /* Copy the whole string to the buffer, without a null termination character,
     * 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);
    buffer[copied_bytes] = '\0';

    /* Release the "toString" result */
    jerry_release_value (string_value);

    printf ("%s\n", (const char *)buffer);
  }

  /* Return an "undefined" value to the JavaScript engine */
  return jerry_create_undefined ();
}

int
main (void)
{
  const jerry_char_t script[] = "print ('Hello from JS!');";
  const jerry_length_t script_size = sizeof (script) - 1;

  /* Initialize engine */
  jerry_init (JERRY_INIT_EMPTY);

  /* Add the "print" method for the JavaScript global object */
  {
    /* Get the "global" object */
    jerry_value_t global_object = jerry_get_global_object ();
    /* Create a "print" JS string */
    jerry_value_t property_name_print = jerry_create_string ((const jerry_char_t *) "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);
    /* 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);

    /* Check if there was no error when adding the property (in this case it should never happen) */
    if (jerry_value_is_error (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);
  }

  /* Setup Global scope code */
  jerry_value_t parsed_code = jerry_parse (script, script_size, NULL);

  if (!jerry_value_is_error (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);
  }

  /* Parsed source code must be freed */
  jerry_release_value (parsed_code);

  /* Cleanup engine */
  jerry_cleanup ();

  return 0;
}

To compile it one can use the following command:

$ gcc api-example-5.c -o api-example-5 $(pkg-config --cflags --libs libjerry-core libjerry-port-default libjerry-math)

If everything is correct the application should print out the string passed for the print method in the JS code:

$ ./api-example-5

Example 6. Using JerryScript Extensions

Some of the previous examples used a "print" method to write data out to the standard output. For convenience JerryScript provides an extension to add a simple "print" handler which can be used by other applications.

In this example the following extension methods are used:

  • jerryx_handler_register_global
  • jerryx_handler_print

In further examples this "print" handler will be used.

#include "jerryscript.h"
#include "jerryscript-ext/handler.h"

int
main (void)
{
  const jerry_char_t script[] = "print ('Hello from JS with ext!');";
  const jerry_length_t script_size = sizeof (script) - 1;

  /* Initialize engine */
  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);

  /* Setup Global scope code */
  jerry_value_t parsed_code = jerry_parse (script, script_size, NULL);

  if (!jerry_value_is_error (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);
  }

  /* Parsed source code must be freed */
  jerry_release_value (parsed_code);

  /* Cleanup engine */
  jerry_cleanup ();

  return 0;
}

To compile it one can use the following command:

(Note that the libjerry-ext was added before the libjerry-port-default entry for the pkg-config call.

$ gcc api-example-6.c -o api-example-6 $(pkg-config --cflags --libs libjerry-core libjerry-ext libjerry-port-default libjerry-math)

If everything is correct the application should print out the string passed for the print method in the JS code:

$ ./api-example-6

Example 7. Interaction with JavaScript environment - adding a string property

Previously a C method was registered for the global object, now this examples show how one can add a string property.

Use the following code as the api-example-7.c file:

#include "jerryscript.h"
#include "jerryscript-ext/handler.h"

int
main (void)
{
  const jerry_char_t script[] = "print (my_var);";

  /* Initializing JavaScript environment */
  jerry_init (JERRY_INIT_EMPTY);

  /* Register 'print' function from the extensions */
  jerryx_handler_register_global ((const jerry_char_t *) "print",
                                  jerryx_handler_print);

  /* Getting pointer to the Global object */
  jerry_value_t global_object = jerry_get_global_object ();

  /* 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!");

  /* 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);
  /* The 'set_result' should be checked if there was any error */
  if (jerry_value_is_error (set_result)) {
    printf ("Failed to add the 'my_var' property\n");
  }
  jerry_release_value (set_result);

  /* Releasing string values, as it is no longer necessary outside of engine */
  jerry_release_value (prop_name);
  jerry_release_value (prop_value);

  /* Releasing the Global object */
  jerry_release_value (global_object);

  /* Now starting script that would output value of just initialized field */
  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);

  /* Freeing engine */
  jerry_cleanup ();

  return 0;
}

To compile it one can use the following command:

(Note that the libjerry-ext was added before the libjerry-port-default entry for the pkg-config call.

$ gcc api-example-7.c -o api-example-7 $(pkg-config --cflags --libs libjerry-core libjerry-ext libjerry-port-default libjerry-math)

The sample will output 'Hello from C!'. However, now it is not just a part of the source script, but the value, dynamically supplied to the engine:

$ ./api-example-7

Example 8. Description of JerryScript value descriptors

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.

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). For example in JS such object be created with the following code example:
var error_object = new Error ("error message");
  • The error value is not an object on its own. This is the exception raised/thrown either via API methods or from JS. For example, creating such error value in JS would look like this:
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. For example the following code snippet could print out a few types (not all types are checked):

#include <stdio.h>
#include <stdlib.h>
#include "jerryscript.h"

static void
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))
  {
    printf ("Error value detected: ");
    value = jerry_get_value_from_error (jsvalue, false);
  }
  else
  {
    value = jerry_acquire_value (jsvalue);
  }

  if (jerry_value_is_undefined (value))
  {
    printf ("undefined");
  }
  else if (jerry_value_is_null (value))
  {
    printf ("null");
  }
  else if (jerry_value_is_boolean (value))
  {
    if (jerry_value_is_true (value))
    {
      printf ("true");
    }
    else
    {
      printf ("false");
    }
  }
  /* Float value */
  else if (jerry_value_is_number (value))
  {
    printf ("number: %lf", jerry_get_number_value (value));
  }
  /* String value */
  else if (jerry_value_is_string (value))
  {
    jerry_char_t str_buf_p[256];

    /* Determining required buffer size */
    jerry_size_t req_sz = jerry_get_string_size (value);

    if (req_sz <= 255)
    {
      jerry_string_to_char_buffer (value, str_buf_p, req_sz);
      str_buf_p[req_sz] = '\0';
      printf ("%s", (const char *) str_buf_p);
    }
    else
    {
      printf ("error: buffer isn't big enough");
    }
  }
  /* Object reference */
  else if (jerry_value_is_object (value))
  {
    printf ("[JS object]");
  }

  printf ("\n");
  jerry_release_value (value);
}

Example 8: Simple JavaScript shell

Now all building blocks, necessary to construct JavaScript shell, are ready.

Shell operation can be described with the following loop:

  • read command;
  • if command is 'quit'
    • exit loop;
  • else
    • eval (command);
    • print result of eval;
    • loop.

See the following api-example-8-shell.c file:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "jerryscript.h"
#include "jerryscript-ext/handler.h"

static void
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))
  {
    printf ("Error value detected: ");
    value = jerry_get_value_from_error (jsvalue, false);
  }
  else
  {
    value = jerry_acquire_value (jsvalue);
  }

  if (jerry_value_is_undefined (value))
  {
    printf ("undefined");
  }
  else if (jerry_value_is_null (value))
  {
    printf ("null");
  }
  else if (jerry_value_is_boolean (value))
  {
    if (jerry_value_is_true (value))
    {
      printf ("true");
    }
    else
    {
      printf ("false");
    }
  }
  /* Float value */
  else if (jerry_value_is_number (value))
  {
    printf ("number: %lf", jerry_get_number_value (value));
  }
  /* String value */
  else if (jerry_value_is_string (value))
  {
    jerry_char_t str_buf_p[256];

    /* Determining required buffer size */
    jerry_size_t req_sz = jerry_get_string_size (value);

    if (req_sz <= 255)
    {
      jerry_string_to_char_buffer (value, str_buf_p, req_sz);
      str_buf_p[req_sz] = '\0';
      printf ("%s", (const char *) str_buf_p);
    }
    else
    {
      printf ("error: buffer isn't big enough");
    }
  }
  /* Object reference */
  else if (jerry_value_is_object (value))
  {
    printf ("[JS object]");
  }

  printf ("\n");
  jerry_release_value (value);
}

int
main (void)
{
  bool is_done = false;

  /* Initialize engine */
  jerry_init (JERRY_INIT_EMPTY);

  /* Register 'print' function from the extensions */
  jerryx_handler_register_global ((const jerry_char_t *) "print",
                                  jerryx_handler_print);

  while (!is_done)
  {
    char cmd[256];
    char *cmd_tail = cmd;
    size_t len = 0;

    printf ("> ");

    /* Read next command */
    while (true)
    {
      if (fread (cmd_tail, 1, 1, stdin) != 1 && len == 0)
      {
        is_done = true;
        break;
      }
      if (*cmd_tail == '\n')
      {
        break;
      }

      cmd_tail++;
      len++;
    }

    /* If the command is "quit", break the loop */
    if (!strncmp (cmd, "quit\n", sizeof ("quit\n") - 1))
    {
      break;
    }

    jerry_value_t ret_val;

    /* Evaluate entered command */
    ret_val = jerry_eval ((const jerry_char_t *) cmd,
                          len,
                          JERRY_PARSE_NO_OPTS);

    /* Print out the value */
    print_value (ret_val);

    jerry_release_value (ret_val);
  }

  /* Cleanup engine */
  jerry_cleanup ();

  return 0;
}

To compile it one can use the following command:

(Note that the libjerry-ext was added before the libjerry-port-default entry for the pkg-config call.

$ gcc api-example-8-shell.c -o api-example-8-shell $(pkg-config --cflags --libs libjerry-core libjerry-ext libjerry-port-default libjerry-math)

The application reads lines from standard input and evaluates them, one after another. To try out run:

$ ./api-example-8-shell

Example 9. Creating JS object in global context

In this example (api-example-9.c) an object with a native function is added to the global object.

#include "jerryscript.h"
#include "jerryscript-ext/handler.h"

struct my_struct
{
  const char *msg;
} my_struct;

/**
 * Get a string from a native object
 */
static jerry_value_t
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);
} /* get_msg_handler */

int
main (void)
{
  /* Initialize engine */
  jerry_init (JERRY_INIT_EMPTY);

  /* Register 'print' function from the extensions */
  jerryx_handler_register_global ((const jerry_char_t *) "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 ();

  /* Create a JS function object and wrap into a jerry value */
  jerry_value_t func_obj = jerry_create_external_function (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);

  /* Wrap the JS object (not empty anymore) into a jerry api value */
  jerry_value_t global_object = jerry_get_global_object ();

  /* 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);

  /* Now we have a "builtin" object called MyObject with a function called myFunc()
   *
   * Equivalent JS code:
   *                    var MyObject = { myFunc : function () { return "some string value"; } }
   */
  const jerry_char_t script[] = " \
    var str = MyObject.myFunc (); \
    print (str); \
  ";

  /* Evaluate script */
  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);

  /* Cleanup engine */
  jerry_cleanup ();

  return 0;
}

To compile it one can use the following command:

(Note that the libjerry-ext was added before the libjerry-port-default entry for the pkg-config call.

$ gcc api-example-9.c -o api-example-9 $(pkg-config --cflags --libs libjerry-core libjerry-ext libjerry-port-default libjerry-math)

Execute the example with:

$ ./api-example-9

The application will generate the following output:

Hello, World

Example 10. Extending JS Objects with native functions

The example creates a JS Object with jerry_eval, then it is extended from C with a native function. In addition this native function shows how to get a property value from the object and how to manipulate it.

Use the following code for api-example-10.c:

#include "jerryscript.h"
#include "jerryscript-ext/handler.h"

/**
 * Add param to 'this.x'
 */
static jerry_value_t
add_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 */
{
  /* The the 'this_val' is the 'MyObject' from the JS code below */
  /* 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);

  if (!jerry_value_is_error (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]);

    /* Add the parameter to 'x' */
    jerry_value_t res_val = jerry_create_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_release_value (x_val);
  jerry_release_value (prop_name);

  return jerry_create_undefined ();
} /* add_handler */

int
main (void)
{
  /* Initialize engine */
  jerry_init (JERRY_INIT_EMPTY);

  /* Register 'print' function from the extensions */
  jerryx_handler_register_global ((const jerry_char_t *) "print",
                                  jerryx_handler_print);

  /* Create a JS object */
  const jerry_char_t my_js_object[] = " \
    MyObject = \
    { x : 12, \
      y : 'Value of x is ', \
      foo: function () \
      { \
        return this.y + this.x; \
      } \
    } \
  ";

  jerry_value_t my_js_obj_val;

  /* Evaluate script */
  my_js_obj_val = jerry_eval (my_js_object,
                              sizeof (my_js_object) - 1,
                              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);

  /* 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);

  /* Free JavaScript value, returned by eval (my_js_object) */
  jerry_release_value (my_js_obj_val);

  const jerry_char_t script[] = " \
    var str = MyObject.foo (); \
    print (str); \
    MyObject.add2x (5); \
    print (MyObject.foo ()); \
  ";

  /* Evaluate script */
  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);

  /* Cleanup engine */
  jerry_cleanup ();

  return 0;
}

To compile it one can use the following command:

(Note that the libjerry-ext was added before the libjerry-port-default entry for the pkg-config call.

$ gcc api-example-10.c -o api-example-10 $(pkg-config --cflags --libs libjerry-core libjerry-ext libjerry-port-default libjerry-math)

Execute the example with:

$ ./api-example-10
Value of x is 12
Value of x is 17

Example 11. Changing the seed of pseudorandom generated numbers

If you want to change the seed of Math.random() generated numbers, you have to initialize the seed value with srand. A recommended method is using jerry_port_get_current_time() or something based on a constantly changing value, therefore every run produces truly random numbers.

#include <stdlib.h>
#include "jerryscript.h"
#include "jerryscript-port.h"
#include "jerryscript-ext/handler.h"

int
main (void)
{
  /* Initialize srand value */
  union { double d; unsigned u; } now = { .d = jerry_port_get_current_time () };
  srand (now.u);

  /* Generate a random number, and print it */
  const jerry_char_t script[] = "var a = Math.random (); print(a)";

  /* Initialize the engine */
  jerry_init (JERRY_INIT_EMPTY);

  /* Register the print function */
  jerryx_handler_register_global ((const jerry_char_t *) "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);

  /* Cleanup the engine */
  jerry_cleanup ();

  return 0;
}

Further steps

For further API description, please visit API Reference page on JerryScript home page.