E.g., * `ssize_t` was used where `lit_utf8_size_t` or `jerry_api_size_t` would have been correct, * `lit_utf8_size_t` was used where `ecma_length_t` would have been correct. Note, the patch also includes internal and public API changes: * `ecma_string_to_utf8_string` does not return negative value if output buffer is not large enough to contain the string; the buffer is expected to be large enough. (`ecma_string_get_size` can be used to retrieve the required size.) * `jerry_api_string_to_char_buffer` adapts the same logic (and `jerry_api_get_string_size` can be used to determine the required size of the buffer). Related issue: #942 JerryScript-DCO-1.0-Signed-off-by: Akos Kiss akiss@inf.u-szeged.hu
7.6 KiB
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 through creation of simple JavaScript shell.
Step 1. Execute JavaScript 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 application will generate the following output:
Hello, World!
Step 2. Split engine initialization and script execution
Here we perform the same actions, as jerry_run_simple, while splitting into several steps:
- engine initialization
- script code setup
- script execution
- engine cleanup
#include <string.h>
#include "jerry.h"
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));
// Execute Global scope code
jerry_completion_code_t code = jerry_run ();
// Cleanup engine
jerry_cleanup ();
}
Our code is more complex now, but it introduces possibilities to interact with JerryScript step-by-step: setup native objects, call JavaScript functions, etc.
Step 3. Execution in 'eval'-mode
#include <string.h>
#include "jerry.h"
int
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;
// Evaluate script1
jerry_api_eval (script1, strlen (script1),
false, false, &eval_ret);
// Free JavaScript value, returned by eval
jerry_api_release_value (&eval_ret);
// 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.
Step 4. Interaction with JavaScript environment
#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);
// Constructing 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 will also output 'Hello, World!'. However, now it is not just a part of the source script, but the value, dynamically supplied to the engine.
Step 5. Description of JavaScript value descriptors
Structure, used to put values to or receive values from the engine is the following:
typeof the 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 or received from the engine are described with the structure.
Pointers to strings or objects and values should be released just when become unnecessary, using jerry_api_release_string or jerry_api_release_object and jerry_api_release_value, correspondingly.
The following example function will output a JavaScript value:
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:
{
jerry_api_size_t req_sz, sz;
// determining required buffer size
req_sz = jerry_api_get_string_size (value_p->v_string);
char * str_buf_p = (char*) malloc (req_sz);
sz = jerry_api_string_to_char_buffer (value_p->v_string,
str_buf_p,
req_sz);
assert (sz == 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
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.
#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[]) {
// 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);
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);
}
// Cleanup engine
jerry_cleanup ();
return 0;
}
The application inputs commands and evaluates them, one after another.
Further steps
For further API description, please look at Embedding API.