jerryscript/05.dev-guide.md
2015-06-14 22:40:29 +03:00

5.8 KiB

layout title permalink
page Development /dev-guide/

Embedding

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

How to execute simple JavaScript file from your application

#include <string.h>
#include "jerry.h"

int
main (int argc, char * argv[]) {
  char script [] = "print ('Hello, World!');";

  jerry_completion_code_t code = jerry_run_simple (script,
                                                   strlen (script),
                                                   JERRY_FLAG_EMPTY);
}

The described application will generate the following output:

Hello, World!

Adding more control over what's happening

Here we perform the same actions, as jerry_run_simple, while splitting into several steps:

  • engine initialization
  • script code setup
  • script execution
  • engine free
#include <string.h>
#include "jerry.h"

int
main (int argc, char * argv[]) {
  char script [] = "print ('Hello, World!');";

  jerry_init (JERRY_FLAG_EMPTY);

  jerry_parse (script, strlen (script));
  jerry_run ();

  jerry_cleanup ();
}

While the code became a bit more complex, the change introduced possibilities to interact with JavaScript step by step, setup native objects and functions, etc.

'eval'-mode execution

#include <string.h>
#include "jerry.h"

int
main (int argc, char * argv[]) {
  char script1 [] = "var s = 'Hello, World!';";
  char script2 [] = "print (s);";

  jerry_init (JERRY_FLAG_EMPTY);

  jerry_api_value_t eval_ret;

  // Step 1
  jerry_api_eval (script1, strlen (script1),
                  false, false, &eval_ret);
  jerry_api_release_value (&eval_ret);

  // Step 2
  jerry_api_eval (script2, strlen (script2),
                  false, false, &eval_ret);
  jerry_api_release_value (&eval_ret);

  jerry_cleanup ();
}

This way, we execute two independent script parts in one execution environment. The first part initializes string variable, and the second outputs the variable.

Interaction with JavaScript data

#include <string.h>
#include "jerry.h"

int
main (int argc, char * argv[]) {
  char str [] = "Hello, World!";
  char var_name [] = "s";
  char script [] = "print (s);";

  // Initializing JavaScript environment
  jerry_init (JERRY_FLAG_EMPTY);

  // Getting pointer to the Global object
  jerry_api_object_t *obj_p = jerry_api_get_global_object ();

  // Constructing string
  jerry_api_string_t *str_val_p = jerry_api_create_string (str);

  // Construction string value descriptor
  jerry_api_value_t val;
  val.type = JERRY_API_DATA_TYPE_STRING;
  val.string_p = str_val_p;

  // Setting the string value to field of the Global object
  jerry_api_set_object_field_value (obj_p, var_name, &val);

  // Releasing string value, as it is no longer necessary outside of engine
  jerry_api_release_string (str_val_p);

  // Same for pointer to the Global object
  jerry_api_release_object (obj_p);

  jerry_api_value_t eval_ret;

  // Now starting script that would output value of just initialized field
  jerry_api_eval (script, strlen (script),
                  false, false, &eval_ret);
  jerry_api_release_value (&eval_ret);

  // Freeing engine
  jerry_cleanup ();
}

The sample would also output 'Hello, World!'.

However, now we have base for some real application.

Simple JavaScript shell

Let's construct simple JavaScript shell.

Shell operation can be described with following loop:

  • read command;
  • if command is 'quit'
    • exit loop;
  • else
    • eval (command);
    • print result of eval;
    • loop.
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "jerry.h"

static void
print_value (const jerry_api_value_t * value_p);

int
main (int argc, char * argv[]) {
  jerry_init (JERRY_FLAG_EMPTY);

  char cmd [256];
  while (true) {
    printf ("> ");

    if (fgets (cmd, sizeof (cmd), stdin) == NULL
        || strcmp (cmd, "quit\n") == 0) {
      break;
    }

    jerry_api_value_t ret_val;

    jerry_completion_code_t status = jerry_api_eval (cmd, strlen (cmd),
                                                     false, false,
                                                     &ret_val);

    if (status == JERRY_COMPLETION_CODE_OK) {
      // 'eval' completed successfully
      print_value (&ret_val);
      jerry_api_release_value (&ret_val);
    } else {
      // evaluated JS code thrown an exception
      // and didn't handle it with try-catch-finally
      printf ("Unhandled JS exception occured\n");
    }

    printf ("\n");
    fflush (stdout);
  }

  jerry_cleanup ();

  return 0;
}

static void
print_value (const jerry_api_value_t * value_p)
{
  switch (value_p->type)
  {
    case JERRY_API_DATA_TYPE_UNDEFINED:
      printf ("undefined");
      break;
    case JERRY_API_DATA_TYPE_NULL:
      printf ("null");
      break;
    case JERRY_API_DATA_TYPE_BOOLEAN:
      if (value_p->v_bool)
        printf ("true");
      else
        printf ("false");
      break;
    case JERRY_API_DATA_TYPE_FLOAT64:
      printf ("%lf", value_p->v_float64);
      break;
    case JERRY_API_DATA_TYPE_STRING:
    {
      ssize_t neg_req_sz, sz;
      // determining required buffer size
      neg_req_sz = jerry_api_string_to_char_buffer (value_p->v_string,
                                                    NULL,
                                                    0);
      assert (neg_req_sz < 0);
      char * str_buf_p = (char*) malloc (-neg_req_sz);
      sz = jerry_api_string_to_char_buffer (value_p->v_string,
                                            str_buf_p,
                                            -neg_req_sz);
      assert (sz == -neg_req_sz);

      printf ("%s", str_buf_p);

      free (str_buf_p);
      break;
    }
    case JERRY_API_DATA_TYPE_OBJECT:
      printf ("[JS object]");
      break;
  }

  printf ("\n");
}