1JerryScript 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. 2 3This guide is intended to introduce you to JerryScript embedding API and to create a minimal JavaScript shell. 4The examples are not using all API methods please also check out the API reference document which contains additional examples. 5 6 7## Before trying out the examples: Get and build JerryScript library 8 9Before getting started using the JerryScript library it should be cloned and built for a target os/device. 10 11There are quite a few configuration options but for these examples the JerryScript is built 12**with default configuration** and installed to a user directory on a Linux system. 13This is done by the following commands: 14 15```sh 16$ mkdir jerry 17$ cd jerry 18$ git clone https://github.com/jerryscript-project/jerryscript.git 19$ jerryscript/tools/build.py --builddir=$(pwd)/example_build --cmake-param="-DCMAKE_INSTALL_PREFIX=$(pwd)/example_install/" 20$ make -C $(pwd)/example_build install 21``` 22 23With this the JerryScript library is installed into the `$(pwd)/example_install/{include,lib}` directories. 24 25In this guide we will use `pkg-config` to ease the usage of headers and libraries. 26In order to do so, the following export is required (executed from the jerry directory): 27 28```sh 29$ export PKG_CONFIG_PATH=$(pwd)/example_install/lib/pkgconfig/ 30``` 31 32Test if the `pkg-config` works for JerryScript: 33 34```sh 35$ pkg-config --cflags --libs libjerry-core libjerry-port-default libjerry-ext libjerry-libm 36``` 37 38## Example 1. Execute JavaScript from your application 39 40The most basic example to test the engine is to create an `api-example-1.c` file containing the following code: 41 42[doctest]: # () 43 44```c 45#include "jerryscript.h" 46 47int 48main (void) 49{ 50 const jerry_char_t script[] = "var str = 'Hello, World!';"; 51 52 bool ret_value = jerry_run_simple (script, sizeof (script) - 1, JERRY_INIT_EMPTY); 53 54 return (ret_value ? 0 : 1); 55} 56``` 57 58To compile it one can use the following command: 59 60```sh 61$ gcc api-example-1.c -o api-example-1 $(pkg-config --cflags --libs libjerry-core libjerry-port-default libjerry-libm) 62``` 63 64If everything is correct the application returns with a zero exit code: 65 66``` 67$ ./api-example-1 68$ echo $? 69``` 70 71## Example 2. Split engine initialization and script execution. 72 73In this example the engine is initialized directly with the `jerry_init` method 74and cleaned up with the `jerry_cleanup` method. The example JavaScript code 75is directly parsed and executed via the `jerry_eval` method. Each `jerry_value_t` 76returned by the API methods is freed with the `jerry_release_value` method. 77 78To make sure that the code parsing and execution was ok, the `jerry_value_is_error` 79method is used to check for any errors. 80 81Use the following code for the `api-example-2.c` file: 82 83[doctest]: # () 84 85```c 86#include "jerryscript.h" 87 88int 89main (void) 90{ 91 const jerry_char_t script[] = "var str = 'Hello, World!';"; 92 const jerry_length_t script_size = sizeof (script) - 1; 93 /* Note: sizeof can be used here only because the compiler knows the static character arrays's size. 94 * If this is not the case, strlen should be used instead. 95 */ 96 97 /* Initialize engine */ 98 jerry_init (JERRY_INIT_EMPTY); 99 100 /* Run the demo script with 'eval' */ 101 jerry_value_t eval_ret = jerry_eval (script, 102 script_size, 103 JERRY_PARSE_NO_OPTS); 104 105 /* Check if there was any error (syntax or runtime) */ 106 bool run_ok = !jerry_value_is_error (eval_ret); 107 108 /* Parsed source code must be freed */ 109 jerry_release_value (eval_ret); 110 111 /* Cleanup engine */ 112 jerry_cleanup (); 113 114 return (run_ok ? 0 : 1); 115} 116``` 117 118To compile it one can use the following command: 119 120```sh 121$ gcc api-example-2.c -o api-example-2 $(pkg-config --cflags --libs libjerry-core libjerry-port-default libjerry-libm) 122``` 123 124If everything is correct the application returns with a zero exit code: 125 126``` 127$ ./api-example-2 128$ echo $? 129``` 130 131## Example 3. Split JavaScript parsing and script execution 132 133In this example the `jerry_eval` is replaced with a more common API calls: 134 135- script code setup - `jerry_parse`. 136- script execution - `jerry_run`. 137 138The `api-example-3.c` file should contain the following code: 139 140[doctest]: # () 141 142```c 143#include "jerryscript.h" 144 145int 146main (void) 147{ 148 bool run_ok = false; 149 150 const jerry_char_t script[] = "var str = 'Hello, World!';"; 151 152 /* Initialize engine */ 153 jerry_init (JERRY_INIT_EMPTY); 154 155 /* Setup Global scope code */ 156 jerry_value_t parsed_code = jerry_parse (NULL, 0, script, sizeof (script) - 1, JERRY_PARSE_NO_OPTS); 157 158 /* Check if there is any JS code parse error */ 159 if (!jerry_value_is_error (parsed_code)) 160 { 161 /* Execute the parsed source code in the Global scope */ 162 jerry_value_t ret_value = jerry_run (parsed_code); 163 164 /* Check the execution return value if there is any error */ 165 run_ok = !jerry_value_is_error (ret_value); 166 167 /* Returned value must be freed */ 168 jerry_release_value (ret_value); 169 } 170 171 /* Parsed source code must be freed */ 172 jerry_release_value (parsed_code); 173 174 /* Cleanup engine */ 175 jerry_cleanup (); 176 177 return (run_ok ? 0 : 1); 178} 179``` 180 181To compile it one can use the following command: 182 183```sh 184$ gcc api-example-3.c -o api-example-3 $(pkg-config --cflags --libs libjerry-core libjerry-port-default libjerry-libm) 185``` 186 187If everything is correct the application returns with a zero exit code: 188 189``` 190$ ./api-example-3 191$ echo $? 192``` 193 194## Example 4. Adding a C method for JavaScript 195 196The previous examples were not that eye catching as there were no visual output by the JavaScript code 197and C program. 198 199In this example a very simple "print" method is added which prints out a static string. 200This method will be implemented in C and will be called from the JavaScript code. 201For this a few extra API methods are required: 202 203- `jerry_get_global_object` 204- `jerry_create_string` 205- `jerry_set_property` 206- `jerry_create_external_function` 207 208The `api-example-4.c` file should contain the following code: 209 210[doctest]: # () 211 212```c 213#include <stdio.h> 214#include "jerryscript.h" 215 216static jerry_value_t 217print_handler (const jerry_value_t function_object, 218 const jerry_value_t function_this, 219 const jerry_value_t arguments[], 220 const jerry_length_t argument_count) 221{ 222 /* No arguments are used in this example */ 223 /* Print out a static string */ 224 printf ("Print handler was called\n"); 225 226 /* Return an "undefined" value to the JavaScript engine */ 227 return jerry_create_undefined (); 228} 229 230int 231main (void) 232{ 233 const jerry_char_t script[] = "print ();"; 234 const jerry_length_t script_size = sizeof (script) - 1; 235 236 /* Initialize engine */ 237 jerry_init (JERRY_INIT_EMPTY); 238 239 /* Add the "print" method for the JavaScript global object */ 240 { 241 /* Get the "global" object */ 242 jerry_value_t global_object = jerry_get_global_object (); 243 /* Create a "print" JS string */ 244 jerry_value_t property_name_print = jerry_create_string ((const jerry_char_t *) "print"); 245 /* Create a function from a native C method (this function will be called from JS) */ 246 jerry_value_t property_value_func = jerry_create_external_function (print_handler); 247 /* Add the "print" property with the function value to the "global" object */ 248 jerry_value_t set_result = jerry_set_property (global_object, property_name_print, property_value_func); 249 250 /* Check if there was no error when adding the property (in this case it should never happen) */ 251 if (jerry_value_is_error (set_result)) { 252 printf ("Failed to add the 'print' property\n"); 253 } 254 255 /* Release all jerry_value_t-s */ 256 jerry_release_value (set_result); 257 jerry_release_value (property_value_func); 258 jerry_release_value (property_name_print); 259 jerry_release_value (global_object); 260 } 261 262 /* Setup Global scope code */ 263 jerry_value_t parsed_code = jerry_parse (NULL, 0, script, script_size, JERRY_PARSE_NO_OPTS); 264 265 if (!jerry_value_is_error (parsed_code)) 266 { 267 /* Execute the parsed source code in the Global scope */ 268 jerry_value_t ret_value = jerry_run (parsed_code); 269 270 /* Returned value must be freed */ 271 jerry_release_value (ret_value); 272 } 273 274 /* Parsed source code must be freed */ 275 jerry_release_value (parsed_code); 276 277 /* Cleanup engine */ 278 jerry_cleanup (); 279 280 return 0; 281} 282``` 283 284 285To compile it one can use the following command: 286 287```sh 288$ gcc api-example-4.c -o api-example-4 $(pkg-config --cflags --libs libjerry-core libjerry-port-default libjerry-libm) 289``` 290 291If everything is correct the application should print out the message present in the `print_handler` method: 292 293``` 294$ ./api-example-4 295``` 296 297## Example 5. Passing and processing arguments for native C code 298 299In the previous example the `print_handler` simply wrote a static string to the standard output. 300However in most cases this is not useful, ideally the method's argument(s) should be printed. 301 302In this example the `print_handler` is extended to convert the first 303argument (which probably comes from a JavaScript source) to a JS string and prints it out to the standard output. 304 305New API methods used: 306 307- `jerry_value_to_string` 308- `jerry_string_to_utf8_char_buffer` 309 310The `api-example-5.c` file should contain the following code: 311 312[doctest]: # () 313 314```c 315#include <stdio.h> 316#include "jerryscript.h" 317 318static jerry_value_t 319print_handler (const jerry_value_t function_object, 320 const jerry_value_t function_this, 321 const jerry_value_t arguments[], 322 const jerry_length_t arguments_count) 323{ 324 /* There should be at least one argument */ 325 if (arguments_count > 0) 326 { 327 /* Convert the first argument to a string (JS "toString" operation) */ 328 jerry_value_t string_value = jerry_value_to_string (arguments[0]); 329 330 /* A naive allocation of buffer for the string */ 331 jerry_char_t buffer[256]; 332 333 /* Copy the whole string to the buffer, without a null termination character, 334 * Please note that if the string does not fit into the buffer nothing will be copied. 335 * More details on the API reference page 336 */ 337 jerry_size_t copied_bytes = jerry_string_to_utf8_char_buffer (string_value, buffer, sizeof (buffer) - 1); 338 buffer[copied_bytes] = '\0'; 339 340 /* Release the "toString" result */ 341 jerry_release_value (string_value); 342 343 printf ("%s\n", (const char *)buffer); 344 } 345 346 /* Return an "undefined" value to the JavaScript engine */ 347 return jerry_create_undefined (); 348} 349 350int 351main (void) 352{ 353 const jerry_char_t script[] = "print ('Hello from JS!');"; 354 const jerry_length_t script_size = sizeof (script) - 1; 355 356 /* Initialize engine */ 357 jerry_init (JERRY_INIT_EMPTY); 358 359 /* Add the "print" method for the JavaScript global object */ 360 { 361 /* Get the "global" object */ 362 jerry_value_t global_object = jerry_get_global_object (); 363 /* Create a "print" JS string */ 364 jerry_value_t property_name_print = jerry_create_string ((const jerry_char_t *) "print"); 365 /* Create a function from a native C method (this function will be called from JS) */ 366 jerry_value_t property_value_func = jerry_create_external_function (print_handler); 367 /* Add the "print" property with the function value to the "global" object */ 368 jerry_value_t set_result = jerry_set_property (global_object, property_name_print, property_value_func); 369 370 /* Check if there was no error when adding the property (in this case it should never happen) */ 371 if (jerry_value_is_error (set_result)) { 372 printf ("Failed to add the 'print' property\n"); 373 } 374 375 /* Release all jerry_value_t-s */ 376 jerry_release_value (set_result); 377 jerry_release_value (property_value_func); 378 jerry_release_value (property_name_print); 379 jerry_release_value (global_object); 380 } 381 382 /* Setup Global scope code */ 383 jerry_value_t parsed_code = jerry_parse (NULL, 0, script, script_size, JERRY_PARSE_NO_OPTS); 384 385 if (!jerry_value_is_error (parsed_code)) 386 { 387 /* Execute the parsed source code in the Global scope */ 388 jerry_value_t ret_value = jerry_run (parsed_code); 389 390 /* Returned value must be freed */ 391 jerry_release_value (ret_value); 392 } 393 394 /* Parsed source code must be freed */ 395 jerry_release_value (parsed_code); 396 397 /* Cleanup engine */ 398 jerry_cleanup (); 399 400 return 0; 401} 402``` 403 404 405To compile it one can use the following command: 406 407```sh 408$ gcc api-example-5.c -o api-example-5 $(pkg-config --cflags --libs libjerry-core libjerry-port-default libjerry-libm) 409``` 410 411If everything is correct the application should print out the string passed for the `print` method in the JS code: 412 413``` 414$ ./api-example-5 415``` 416 417 418## Example 6. Using JerryScript Extensions 419 420Some of the previous examples used a "print" method to write data out to the standard output. 421For convenience JerryScript provides an extension to add a simple "print" handler which 422can be used by other applications. 423 424In this example the following extension methods are used: 425 426- `jerryx_handler_register_global` 427- `jerryx_handler_print` 428 429In further examples this "print" handler will be used. 430 431```c 432#include "jerryscript.h" 433#include "jerryscript-ext/handler.h" 434 435int 436main (void) 437{ 438 const jerry_char_t script[] = "print ('Hello from JS with ext!');"; 439 const jerry_length_t script_size = sizeof (script) - 1; 440 441 /* Initialize engine */ 442 jerry_init (JERRY_INIT_EMPTY); 443 444 /* Register 'print' function from the extensions to the global object */ 445 jerryx_handler_register_global ((const jerry_char_t *) "print", 446 jerryx_handler_print); 447 448 /* Setup Global scope code */ 449 jerry_value_t parsed_code = jerry_parse (NULL, 0, script, script_size, JERRY_PARSE_NO_OPTS); 450 451 if (!jerry_value_is_error (parsed_code)) 452 { 453 /* Execute the parsed source code in the Global scope */ 454 jerry_value_t ret_value = jerry_run (parsed_code); 455 456 /* Returned value must be freed */ 457 jerry_release_value (ret_value); 458 } 459 460 /* Parsed source code must be freed */ 461 jerry_release_value (parsed_code); 462 463 /* Cleanup engine */ 464 jerry_cleanup (); 465 466 return 0; 467} 468``` 469 470 471To compile it one can use the following command: 472 473(**Note** that the `libjerry-ext` was added **before** the `libjerry-port-default` entry for the `pkg-config` call. 474 475```sh 476$ gcc api-example-6.c -o api-example-6 $(pkg-config --cflags --libs libjerry-core libjerry-ext libjerry-port-default libjerry-libm) 477``` 478 479If everything is correct the application should print out the string passed for the `print` method in the JS code: 480 481``` 482$ ./api-example-6 483``` 484 485## Example 7. Interaction with JavaScript environment - adding a string property 486 487Previously a C method was registered for the global object, now this examples show how one can add a string 488property. 489 490Use the following code as the `api-example-7.c` file: 491 492[doctest]: # () 493 494```c 495#include "jerryscript.h" 496#include "jerryscript-ext/handler.h" 497 498int 499main (void) 500{ 501 const jerry_char_t script[] = "print (my_var);"; 502 503 /* Initializing JavaScript environment */ 504 jerry_init (JERRY_INIT_EMPTY); 505 506 /* Register 'print' function from the extensions */ 507 jerryx_handler_register_global ((const jerry_char_t *) "print", 508 jerryx_handler_print); 509 510 /* Getting pointer to the Global object */ 511 jerry_value_t global_object = jerry_get_global_object (); 512 513 /* Constructing strings */ 514 jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) "my_var"); 515 jerry_value_t prop_value = jerry_create_string ((const jerry_char_t *) "Hello from C!"); 516 517 /* Setting the string value as a property of the Global object */ 518 jerry_value_t set_result = jerry_set_property (global_object, prop_name, prop_value); 519 /* The 'set_result' should be checked if there was any error */ 520 if (jerry_value_is_error (set_result)) { 521 printf ("Failed to add the 'my_var' property\n"); 522 } 523 jerry_release_value (set_result); 524 525 /* Releasing string values, as it is no longer necessary outside of engine */ 526 jerry_release_value (prop_name); 527 jerry_release_value (prop_value); 528 529 /* Releasing the Global object */ 530 jerry_release_value (global_object); 531 532 /* Now starting script that would output value of just initialized field */ 533 jerry_value_t eval_ret = jerry_eval (script, 534 sizeof (script) - 1, 535 JERRY_PARSE_NO_OPTS); 536 537 /* Free JavaScript value, returned by eval */ 538 jerry_release_value (eval_ret); 539 540 /* Freeing engine */ 541 jerry_cleanup (); 542 543 return 0; 544} 545``` 546 547To compile it one can use the following command: 548 549(**Note** that the `libjerry-ext` was added **before** the `libjerry-port-default` entry for the `pkg-config` call. 550 551```sh 552$ gcc api-example-7.c -o api-example-7 $(pkg-config --cflags --libs libjerry-core libjerry-ext libjerry-port-default libjerry-libm) 553``` 554 555The 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: 556 557``` 558$ ./api-example-7 559``` 560 561## Example 8. Description of JerryScript value descriptors 562 563JerryScript value can be a boolean, number, null, object, string, undefined or some special type of objects (arraybuffer, symbols, etc). 564 565There is a special "error" value which wraps another value. This "error" can be created by throwing a JavaScript value from JS code 566or via API method(s). It is advised to check for this error with the `jerry_value_is_error` method as not all API methods 567can process error values. To extract the value from the "error" the API method `jerry_get_value_from_error` should be used. 568If an error object is created via API method (for example with `jerry_create_error`) the "error" value is automatically created. 569 570Notice the difference between error value and error object: 571- The error object is a object which was constructed via one of the `Error` objects (available from the global object or from API). 572 For example in JS such object be created with the following code example: 573 574```js 575var error_object = new Error ("error message"); 576``` 577 578- The error value is not an object on its own. This is the exception raised/thrown either via API methods or from JS. 579 For example, creating such error value in JS would look like this: 580 581```js 582throw "message"; 583``` 584 585To check what type a given `jerry_value_t` is the `jerry_value_is_*` methods or the `jerry_value_get_type` could be used. 586For example the following code snippet could print out a few types (not all types are checked): 587 588[doctest]: # (test="compile") 589 590```c 591#include <stdio.h> 592#include <stdlib.h> 593#include "jerryscript.h" 594 595static void 596print_value (const jerry_value_t jsvalue) 597{ 598 jerry_value_t value; 599 /* If there is an error extract the object from it */ 600 if (jerry_value_is_error (jsvalue)) 601 { 602 printf ("Error value detected: "); 603 value = jerry_get_value_from_error (jsvalue, false); 604 } 605 else 606 { 607 value = jerry_acquire_value (jsvalue); 608 } 609 610 if (jerry_value_is_undefined (value)) 611 { 612 printf ("undefined"); 613 } 614 else if (jerry_value_is_null (value)) 615 { 616 printf ("null"); 617 } 618 else if (jerry_value_is_boolean (value)) 619 { 620 if (jerry_get_boolean_value (value)) 621 { 622 printf ("true"); 623 } 624 else 625 { 626 printf ("false"); 627 } 628 } 629 /* Float value */ 630 else if (jerry_value_is_number (value)) 631 { 632 printf ("number: %lf", jerry_get_number_value (value)); 633 } 634 /* String value */ 635 else if (jerry_value_is_string (value)) 636 { 637 jerry_char_t str_buf_p[256]; 638 639 /* Determining required buffer size */ 640 jerry_size_t req_sz = jerry_get_string_size (value); 641 642 if (req_sz <= 255) 643 { 644 jerry_string_to_char_buffer (value, str_buf_p, req_sz); 645 str_buf_p[req_sz] = '\0'; 646 printf ("%s", (const char *) str_buf_p); 647 } 648 else 649 { 650 printf ("error: buffer isn't big enough"); 651 } 652 } 653 /* Object reference */ 654 else if (jerry_value_is_object (value)) 655 { 656 printf ("[JS object]"); 657 } 658 659 printf ("\n"); 660 jerry_release_value (value); 661} 662``` 663 664## Example 8: Simple JavaScript shell 665 666Now all building blocks, necessary to construct JavaScript shell, are ready. 667 668Shell operation can be described with the following loop: 669 670- read command; 671- if command is 'quit' 672 - exit loop; 673- else 674 - eval (command); 675 - print result of eval; 676 - loop. 677 678See the following `api-example-8-shell.c` file: 679 680[doctest]: # (test="link") 681 682```c 683#include <stdio.h> 684#include <stdlib.h> 685#include <string.h> 686#include "jerryscript.h" 687#include "jerryscript-ext/handler.h" 688 689static void 690print_value (const jerry_value_t jsvalue) 691{ 692 jerry_value_t value; 693 /* If there is an error extract the object from it */ 694 if (jerry_value_is_error (jsvalue)) 695 { 696 printf ("Error value detected: "); 697 value = jerry_get_value_from_error (jsvalue, false); 698 } 699 else 700 { 701 value = jerry_acquire_value (jsvalue); 702 } 703 704 if (jerry_value_is_undefined (value)) 705 { 706 printf ("undefined"); 707 } 708 else if (jerry_value_is_null (value)) 709 { 710 printf ("null"); 711 } 712 else if (jerry_value_is_boolean (value)) 713 { 714 if (jerry_get_boolean_value (value)) 715 { 716 printf ("true"); 717 } 718 else 719 { 720 printf ("false"); 721 } 722 } 723 /* Float value */ 724 else if (jerry_value_is_number (value)) 725 { 726 printf ("number: %lf", jerry_get_number_value (value)); 727 } 728 /* String value */ 729 else if (jerry_value_is_string (value)) 730 { 731 jerry_char_t str_buf_p[256]; 732 733 /* Determining required buffer size */ 734 jerry_size_t req_sz = jerry_get_string_size (value); 735 736 if (req_sz <= 255) 737 { 738 jerry_string_to_char_buffer (value, str_buf_p, req_sz); 739 str_buf_p[req_sz] = '\0'; 740 printf ("%s", (const char *) str_buf_p); 741 } 742 else 743 { 744 printf ("error: buffer isn't big enough"); 745 } 746 } 747 /* Object reference */ 748 else if (jerry_value_is_object (value)) 749 { 750 printf ("[JS object]"); 751 } 752 753 printf ("\n"); 754 jerry_release_value (value); 755} 756 757int 758main (void) 759{ 760 bool is_done = false; 761 762 /* Initialize engine */ 763 jerry_init (JERRY_INIT_EMPTY); 764 765 /* Register 'print' function from the extensions */ 766 jerryx_handler_register_global ((const jerry_char_t *) "print", 767 jerryx_handler_print); 768 769 while (!is_done) 770 { 771 char cmd[256]; 772 char *cmd_tail = cmd; 773 size_t len = 0; 774 775 printf ("> "); 776 777 /* Read next command */ 778 while (true) 779 { 780 if (fread (cmd_tail, 1, 1, stdin) != 1 && len == 0) 781 { 782 is_done = true; 783 break; 784 } 785 if (*cmd_tail == '\n') 786 { 787 break; 788 } 789 790 cmd_tail++; 791 len++; 792 } 793 794 /* If the command is "quit", break the loop */ 795 if (!strncmp (cmd, "quit\n", sizeof ("quit\n") - 1)) 796 { 797 break; 798 } 799 800 jerry_value_t ret_val; 801 802 /* Evaluate entered command */ 803 ret_val = jerry_eval ((const jerry_char_t *) cmd, 804 len, 805 JERRY_PARSE_NO_OPTS); 806 807 /* Print out the value */ 808 print_value (ret_val); 809 810 jerry_release_value (ret_val); 811 } 812 813 /* Cleanup engine */ 814 jerry_cleanup (); 815 816 return 0; 817} 818``` 819 820To compile it one can use the following command: 821 822(**Note** that the `libjerry-ext` was added **before** the `libjerry-port-default` entry for the `pkg-config` call. 823 824```sh 825$ gcc api-example-8-shell.c -o api-example-8-shell $(pkg-config --cflags --libs libjerry-core libjerry-ext libjerry-port-default libjerry-libm) 826``` 827 828The application reads lines from standard input and evaluates them, one after another. To try out run: 829 830``` 831$ ./api-example-8-shell 832``` 833 834 835## Example 9. Creating JS object in global context 836 837In this example (`api-example-9.c`) an object with a native function is added to the global object. 838 839[doctest]: # () 840 841```c 842#include "jerryscript.h" 843#include "jerryscript-ext/handler.h" 844 845struct my_struct 846{ 847 const char *msg; 848} my_struct; 849 850/** 851 * Get a string from a native object 852 */ 853static jerry_value_t 854get_msg_handler (const jerry_value_t func_value, /**< function object */ 855 const jerry_value_t this_value, /**< this arg */ 856 const jerry_value_t *args_p, /**< function arguments */ 857 const jerry_length_t args_cnt) /**< number of function arguments */ 858{ 859 return jerry_create_string ((const jerry_char_t *) my_struct.msg); 860} /* get_msg_handler */ 861 862int 863main (void) 864{ 865 /* Initialize engine */ 866 jerry_init (JERRY_INIT_EMPTY); 867 868 /* Register 'print' function from the extensions */ 869 jerryx_handler_register_global ((const jerry_char_t *) "print", 870 jerryx_handler_print); 871 872 /* Do something with the native object */ 873 my_struct.msg = "Hello, World!"; 874 875 /* Create an empty JS object */ 876 jerry_value_t object = jerry_create_object (); 877 878 /* Create a JS function object and wrap into a jerry value */ 879 jerry_value_t func_obj = jerry_create_external_function (get_msg_handler); 880 881 /* Set the native function as a property of the empty JS object */ 882 jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) "myFunc"); 883 jerry_release_value (jerry_set_property (object, prop_name, func_obj)); 884 jerry_release_value (prop_name); 885 jerry_release_value (func_obj); 886 887 /* Wrap the JS object (not empty anymore) into a jerry api value */ 888 jerry_value_t global_object = jerry_get_global_object (); 889 890 /* Add the JS object to the global context */ 891 prop_name = jerry_create_string ((const jerry_char_t *) "MyObject"); 892 jerry_release_value (jerry_set_property (global_object, prop_name, object)); 893 jerry_release_value (prop_name); 894 jerry_release_value (object); 895 jerry_release_value (global_object); 896 897 /* Now we have a "builtin" object called MyObject with a function called myFunc() 898 * 899 * Equivalent JS code: 900 * var MyObject = { myFunc : function () { return "some string value"; } } 901 */ 902 const jerry_char_t script[] = " \ 903 var str = MyObject.myFunc (); \ 904 print (str); \ 905 "; 906 907 /* Evaluate script */ 908 jerry_value_t eval_ret = jerry_eval (script, sizeof (script) - 1, JERRY_PARSE_NO_OPTS); 909 910 /* Free JavaScript value, returned by eval */ 911 jerry_release_value (eval_ret); 912 913 /* Cleanup engine */ 914 jerry_cleanup (); 915 916 return 0; 917} 918``` 919 920To compile it one can use the following command: 921 922(**Note** that the `libjerry-ext` was added **before** the `libjerry-port-default` entry for the `pkg-config` call. 923 924```sh 925$ gcc api-example-9.c -o api-example-9 $(pkg-config --cflags --libs libjerry-core libjerry-ext libjerry-port-default libjerry-libm) 926``` 927 928Execute the example with: 929 930``` 931$ ./api-example-9 932``` 933 934The application will generate the following output: 935 936```bash 937Hello, World 938``` 939 940## Example 10. Extending JS Objects with native functions 941 942The example creates a JS Object with `jerry_eval`, then it is extended from C with a native function. 943In addition this native function shows how to get a property value from the object and how to manipulate it. 944 945 946Use the following code for `api-example-10.c`: 947 948[doctest]: # () 949 950```c 951#include "jerryscript.h" 952#include "jerryscript-ext/handler.h" 953 954/** 955 * Add param to 'this.x' 956 */ 957static jerry_value_t 958add_handler (const jerry_value_t func_value, /**< function object */ 959 const jerry_value_t this_val, /**< this arg */ 960 const jerry_value_t args_p[], /**< function arguments */ 961 const jerry_length_t args_cnt) /**< number of function arguments */ 962{ 963 /* The the 'this_val' is the 'MyObject' from the JS code below */ 964 /* Note: that the argument count check is ignored for the example's case */ 965 966 /* Get 'this.x' */ 967 jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) "x"); 968 jerry_value_t x_val = jerry_get_property (this_val, prop_name); 969 970 if (!jerry_value_is_error (x_val)) 971 { 972 /* Convert Jerry API values to double */ 973 double x = jerry_get_number_value (x_val); 974 double d = jerry_get_number_value (args_p[0]); 975 976 /* Add the parameter to 'x' */ 977 jerry_value_t res_val = jerry_create_number (x + d); 978 979 /* Set the new value of 'this.x' */ 980 jerry_release_value (jerry_set_property (this_val, prop_name, res_val)); 981 jerry_release_value (res_val); 982 } 983 984 jerry_release_value (x_val); 985 jerry_release_value (prop_name); 986 987 return jerry_create_undefined (); 988} /* add_handler */ 989 990int 991main (void) 992{ 993 /* Initialize engine */ 994 jerry_init (JERRY_INIT_EMPTY); 995 996 /* Register 'print' function from the extensions */ 997 jerryx_handler_register_global ((const jerry_char_t *) "print", 998 jerryx_handler_print); 999 1000 /* Create a JS object */ 1001 const jerry_char_t my_js_object[] = " \ 1002 MyObject = \ 1003 { x : 12, \ 1004 y : 'Value of x is ', \ 1005 foo: function () \ 1006 { \ 1007 return this.y + this.x; \ 1008 } \ 1009 } \ 1010 "; 1011 1012 jerry_value_t my_js_obj_val; 1013 1014 /* Evaluate script */ 1015 my_js_obj_val = jerry_eval (my_js_object, 1016 sizeof (my_js_object) - 1, 1017 JERRY_PARSE_NO_OPTS); 1018 1019 /* Create a JS function object and wrap into a jerry value */ 1020 jerry_value_t add_func_obj = jerry_create_external_function (add_handler); 1021 1022 /* Set the native function as a property of previously created MyObject */ 1023 jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) "add2x"); 1024 jerry_release_value (jerry_set_property (my_js_obj_val, prop_name, add_func_obj)); 1025 jerry_release_value (add_func_obj); 1026 jerry_release_value (prop_name); 1027 1028 /* Free JavaScript value, returned by eval (my_js_object) */ 1029 jerry_release_value (my_js_obj_val); 1030 1031 const jerry_char_t script[] = " \ 1032 var str = MyObject.foo (); \ 1033 print (str); \ 1034 MyObject.add2x (5); \ 1035 print (MyObject.foo ()); \ 1036 "; 1037 1038 /* Evaluate script */ 1039 jerry_value_t eval_ret = jerry_eval (script, sizeof (script) - 1, JERRY_PARSE_NO_OPTS); 1040 1041 /* Free JavaScript value, returned by eval */ 1042 jerry_release_value (eval_ret); 1043 1044 /* Cleanup engine */ 1045 jerry_cleanup (); 1046 1047 return 0; 1048} 1049``` 1050 1051To compile it one can use the following command: 1052 1053(**Note** that the `libjerry-ext` was added **before** the `libjerry-port-default` entry for the `pkg-config` call. 1054 1055```sh 1056$ gcc api-example-10.c -o api-example-10 $(pkg-config --cflags --libs libjerry-core libjerry-ext libjerry-port-default libjerry-libm) 1057``` 1058 1059Execute the example with: 1060 1061``` 1062$ ./api-example-10 1063``` 1064 1065```bash 1066Value of x is 12 1067Value of x is 17 1068``` 1069 1070## Example 11. Changing the seed of pseudorandom generated numbers 1071 1072If you want to change the seed of `Math.random()` generated numbers, you have to initialize the seed value with `srand`. 1073A recommended method is using `jerry_port_get_current_time()` or something based on a constantly changing value, therefore every run produces truly random numbers. 1074 1075[doctest]: # () 1076 1077```c 1078#include <stdlib.h> 1079#include "jerryscript.h" 1080#include "jerryscript-port.h" 1081#include "jerryscript-ext/handler.h" 1082 1083int 1084main (void) 1085{ 1086 /* Initialize srand value */ 1087 union { double d; unsigned u; } now = { .d = jerry_port_get_current_time () }; 1088 srand (now.u); 1089 1090 /* Generate a random number, and print it */ 1091 const jerry_char_t script[] = "var a = Math.random (); print(a)"; 1092 1093 /* Initialize the engine */ 1094 jerry_init (JERRY_INIT_EMPTY); 1095 1096 /* Register the print function */ 1097 jerryx_handler_register_global ((const jerry_char_t *) "print", 1098 jerryx_handler_print); 1099 1100 /* Evaluate the script */ 1101 jerry_value_t eval_ret = jerry_eval (script, sizeof (script) - 1, JERRY_PARSE_NO_OPTS); 1102 1103 /* Free the JavaScript value returned by eval */ 1104 jerry_release_value (eval_ret); 1105 1106 /* Cleanup the engine */ 1107 jerry_cleanup (); 1108 1109 return 0; 1110} 1111``` 1112 1113## Further steps 1114 1115For further API description, please visit [API Reference page](https://jerryscript-project.github.io/jerryscript/api-reference/) on [JerryScript home page](https://jerryscript-project.github.io/jerryscript/). 1116