From e0c5e10e49836068800942165645aef5931f4bc8 Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Sun, 14 Jun 2015 23:16:14 +0300 Subject: [PATCH] Update development guide --- 05.dev-guide.md | 171 ++++++++++++++++++++++++++++++------------------ 1 file changed, 109 insertions(+), 62 deletions(-) diff --git a/05.dev-guide.md b/05.dev-guide.md index 2ff8aed7b..c6ca527c9 100644 --- a/05.dev-guide.md +++ b/05.dev-guide.md @@ -4,10 +4,11 @@ title: Development permalink: /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 +This guide is intended to introduce you to JerryScript embedding API through creation of simple JavaScript shell. + +## Step 1. Execute JavaScript from your application ```cpp #include @@ -23,20 +24,20 @@ main (int argc, char * argv[]) { } ``` -The described application will generate the following output: +The application will generate the following output: ```bash Hello, World! ``` -## Adding more control over what's happening +## Step 2. Split execution environment initialization, script execution and execution environment cleanup Here we perform the same actions, as `jerry_run_simple`, while splitting into several steps: - engine initialization - script code setup - script execution -- engine free +- engine cleanup ```cpp @@ -47,18 +48,23 @@ int main (int argc, char * argv[]) { char script [] = "print ('Hello, World!');"; + // Initialize engine jerry_init (JERRY_FLAG_EMPTY); + // Setup Global scope code jerry_parse (script, strlen (script)); - jerry_run (); + // Execute Global scope code + jerry_completion_code_t code = jerry_run (); + + // Cleanup engine 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. +While code became a bit more complex, the change introduced possibilities to interact with JerryScript step by step, setup native objects, call Javascript functions, etc. -## 'eval'-mode execution +## Step 3. Execution in 'eval'-mode ```cpp #include @@ -69,27 +75,31 @@ main (int argc, char * argv[]) { char script1 [] = "var s = 'Hello, World!';"; char script2 [] = "print (s);"; + // Initialize engine jerry_init (JERRY_FLAG_EMPTY); jerry_api_value_t eval_ret; - // Step 1 + // Evaluate script1 jerry_api_eval (script1, strlen (script1), false, false, &eval_ret); + // Free JavaScript value, returned by eval jerry_api_release_value (&eval_ret); - // Step 2 + // Evaluate script2 jerry_api_eval (script2, strlen (script2), false, false, &eval_ret); + // Free JavaScript value, returned by eval jerry_api_release_value (&eval_ret); + // Cleanup engine 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 +## Step 4. Interaction with JavaScript environment ```cpp #include @@ -110,7 +120,7 @@ main (int argc, char * argv[]) { // Constructing string jerry_api_string_t *str_val_p = jerry_api_create_string (str); - // Construction string value descriptor + // Constructing string value descriptor jerry_api_value_t val; val.type = JERRY_API_DATA_TYPE_STRING; val.string_p = str_val_p; @@ -136,13 +146,89 @@ main (int argc, char * argv[]) { } ``` -The sample would also output 'Hello, World!'. +The sample would also output 'Hello, World!'. However, now it is not just part of source script, but value, dynamically supplied to the engine. -However, now we have base for some real application. +## Step 5. Description of JavaScript value descriptors + +Structure, used to put values to / receive values from engine is the following: + +- `type` of value: + - JERRY_API_DATA_TYPE_UNDEFINED (undefined); + - JERRY_API_DATA_TYPE_NULL (null); + - JERRY_API_DATA_TYPE_BOOLEAN (true / false); + - JERRY_API_DATA_TYPE_FLOAT64 (number); + - JERRY_API_DATA_TYPE_STRING (string); + - JERRY_API_DATA_TYPE_OBJECT (object reference); +- `v_bool` (if JERRY_API_DATA_TYPE_BOOLEAN) - boolean value; +- `v_float64` (if JERRY_API_DATA_TYPE_FLOAT64) - number value; +- `v_string` (if JERRY_API_DATA_TYPE_STRING) - pointer to string; +- `v_object` (if JERRY_API_DATA_TYPE_OBJECT) - pointer to object. + +Abstract values, to be sent to / received from engine are described with the structure. + +Pointers to strings / objects and values should be released just when become unnecessary, using `jerry_api_release_string` / `jerry_api_release_object` and `jerry_api_release_value`, correspondingly. + +The following example function would output a JavaScript value: + +```cpp +static void +print_value (const jerry_api_value_t * value_p) +{ + switch (value_p->type) + { + // Simple values: undefined, null, false, true + 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; + + // Number value + case JERRY_API_DATA_TYPE_FLOAT64: + printf ("%lf", value_p->v_float64); + break; + + // String value + 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; + } + + // Object reference + case JERRY_API_DATA_TYPE_OBJECT: + printf ("[JS object]"); + break; + } + + printf ("\n"); +} +``` ## Simple JavaScript shell -Let's construct simple JavaScript shell. +Now we have build blocks to construct JavaScript shell. Shell operation can be described with following loop: @@ -167,23 +253,28 @@ print_value (const jerry_api_value_t * value_p); int main (int argc, char * argv[]) { + // Initialize engine jerry_init (JERRY_FLAG_EMPTY); char cmd [256]; while (true) { printf ("> "); + // Input next command if (fgets (cmd, sizeof (cmd), stdin) == NULL || strcmp (cmd, "quit\n") == 0) { + // If the command is 'quit', exit from loop break; } jerry_api_value_t ret_val; + // Evaluate entered command jerry_completion_code_t status = jerry_api_eval (cmd, strlen (cmd), false, false, &ret_val); + // If command evaluated successfully, print value, returned by eval if (status == JERRY_COMPLETION_CODE_OK) { // 'eval' completed successfully print_value (&ret_val); @@ -198,55 +289,11 @@ main (int argc, char * argv[]) { fflush (stdout); } + // Cleanup engine 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"); -} ``` + +For further API description, please look at [Embedding API](/API).