[njs] Interactive shell: console object.

Dmitry Volyntsev xeioex at nginx.com
Thu Aug 31 17:28:13 UTC 2017


details:   http://hg.nginx.org/njs/rev/27aa477208f5
branches:  
changeset: 403:27aa477208f5
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Thu Aug 31 20:27:31 2017 +0300
description:
Interactive shell: console object.

diffstat:

 nginx/ngx_http_js_module.c   |    2 +-
 nginx/ngx_stream_js_module.c |    2 +-
 njs/njs.c                    |  154 +++++++++++++++++++++++++++++++++++++++++-
 njs/njs_builtin.c            |  103 ++++++++++++++++++++++------
 njs/njs_builtin.h            |   15 ++++
 njs/njscript.c               |    8 +-
 njs/njscript.h               |    3 +-
 njs/test/njs_unit_test.c     |    2 +-
 8 files changed, 255 insertions(+), 34 deletions(-)

diffs (558 lines):

diff -r 46ea39d059e1 -r 27aa477208f5 nginx/ngx_http_js_module.c
--- a/nginx/ngx_http_js_module.c	Thu Aug 31 20:03:13 2017 +0300
+++ b/nginx/ngx_http_js_module.c	Thu Aug 31 20:27:31 2017 +0300
@@ -1322,7 +1322,7 @@ ngx_http_js_include(ngx_conf_t *cf, ngx_
     ngx_memzero(&options, sizeof(njs_vm_opt_t));
 
     options.mcp = mcp;
-    options.externals = &externals;
+    options.externals_hash = &externals;
 
     jlcf->vm = njs_vm_create(&options);
     if (jlcf->vm == NULL) {
diff -r 46ea39d059e1 -r 27aa477208f5 nginx/ngx_stream_js_module.c
--- a/nginx/ngx_stream_js_module.c	Thu Aug 31 20:03:13 2017 +0300
+++ b/nginx/ngx_stream_js_module.c	Thu Aug 31 20:27:31 2017 +0300
@@ -1032,7 +1032,7 @@ ngx_stream_js_include(ngx_conf_t *cf, ng
     ngx_memzero(&options, sizeof(njs_vm_opt_t));
 
     options.mcp = mcp;
-    options.externals = &externals;
+    options.externals_hash = &externals;
 
     jscf->vm = njs_vm_create(&options);
     if (jscf->vm == NULL) {
diff -r 46ea39d059e1 -r 27aa477208f5 njs/njs.c
--- a/njs/njs.c	Thu Aug 31 20:03:13 2017 +0300
+++ b/njs/njs.c	Thu Aug 31 20:27:31 2017 +0300
@@ -21,9 +21,12 @@
 #include <nxt_array.h>
 #include <nxt_lvlhsh.h>
 #include <nxt_random.h>
+#include <nxt_djb_hash.h>
 #include <nxt_mem_cache_pool.h>
 #include <njscript.h>
 #include <njs_vm.h>
+#include <njs_object.h>
+#include <njs_builtin.h>
 #include <njs_variable.h>
 #include <njs_parser.h>
 
@@ -54,6 +57,7 @@ typedef struct {
 
 
 static nxt_int_t njs_get_options(njs_opts_t *opts, int argc, char **argv);
+static nxt_int_t njs_externals_init(njs_opts_t *opts, njs_vm_opt_t *vm_options);
 static nxt_int_t njs_interactive_shell(njs_opts_t *opts,
     njs_vm_opt_t *vm_options);
 static nxt_int_t njs_process_file(njs_opts_t *opts, njs_vm_opt_t *vm_options);
@@ -64,7 +68,56 @@ static nxt_int_t njs_editline_init(njs_v
 static char **njs_completion_handler(const char *text, int start, int end);
 static char *njs_completion_generator(const char *text, int state);
 
+static njs_ret_t njs_ext_console_log(njs_vm_t *vm, njs_value_t *args,
+    nxt_uint_t nargs, njs_index_t unused);
+static njs_ret_t njs_ext_console_help(njs_vm_t *vm, njs_value_t *args,
+    nxt_uint_t nargs, njs_index_t unused);
 
+
+static njs_external_t  njs_ext_console[] = {
+
+    { nxt_string("log"),
+      NJS_EXTERN_METHOD,
+      NULL,
+      0,
+      NULL,
+      NULL,
+      NULL,
+      NULL,
+      NULL,
+      njs_ext_console_log,
+      0 },
+
+    { nxt_string("help"),
+      NJS_EXTERN_METHOD,
+      NULL,
+      0,
+      NULL,
+      NULL,
+      NULL,
+      NULL,
+      NULL,
+      njs_ext_console_help,
+      0 },
+};
+
+static njs_external_t  njs_externals[] = {
+
+    { nxt_string("console"),
+      NJS_EXTERN_OBJECT,
+      njs_ext_console,
+      nxt_nitems(njs_ext_console),
+      NULL,
+      NULL,
+      NULL,
+      NULL,
+      NULL,
+      NULL,
+      0 },
+};
+
+
+static nxt_lvlhsh_t      njs_externals_hash;
 static njs_completion_t  njs_completion;
 
 
@@ -96,6 +149,10 @@ main(int argc, char **argv)
     vm_options.accumulative = 1;
     vm_options.backtrace = 1;
 
+    if (njs_externals_init(&opts, &vm_options) != NXT_OK) {
+        return EXIT_FAILURE;
+    }
+
     if (opts.interactive) {
         ret = njs_interactive_shell(&opts, &vm_options);
 
@@ -150,6 +207,36 @@ njs_get_options(njs_opts_t *opts, int ar
 
 
 static nxt_int_t
+njs_externals_init(njs_opts_t *opts, njs_vm_opt_t *vm_options)
+{
+    void        **ext;
+    nxt_uint_t  i;
+
+    nxt_lvlhsh_init(&njs_externals_hash);
+
+    for (i = 0; i < nxt_nitems(njs_externals); i++) {
+        if (njs_vm_external_add(&njs_externals_hash, vm_options->mcp,
+                                (uintptr_t) i, &njs_externals[i], 1)
+            != NXT_OK)
+        {
+            fprintf(stderr, "could not add external objects\n");
+            return NXT_ERROR;
+        }
+    }
+
+    ext = nxt_mem_cache_zalloc(vm_options->mcp, sizeof(void *) * i);
+    if (ext == NULL) {
+        return NXT_ERROR;
+    }
+
+    vm_options->external = ext;
+    vm_options->externals_hash = &njs_externals_hash;
+
+    return NXT_OK;
+}
+
+
+static nxt_int_t
 njs_interactive_shell(njs_opts_t *opts, njs_vm_opt_t *vm_options)
 {
     njs_vm_t     *vm;
@@ -168,7 +255,11 @@ njs_interactive_shell(njs_opts_t *opts, 
         return NXT_ERROR;
     }
 
-    printf("interactive njscript\n");
+    printf("interactive njscript\n\n");
+
+    printf("v<Tab> -> the properties of v object.\n");
+    printf("v.<Tab> -> all the available prototype methods.\n");
+    printf("type console.help() for more information\n\n");
 
     for ( ;; ) {
         line.start = (u_char *) readline(">> ");
@@ -185,8 +276,8 @@ njs_interactive_shell(njs_opts_t *opts, 
 
         ret = njs_process_script(vm, opts, &line, &out);
         if (ret != NXT_OK) {
-            printf("njs_process_script() failed\n");
-            return NXT_ERROR;
+            printf("shell: failed to get retval from VM\n");
+            continue;
         }
 
         printf("%.*s\n", (int) out.length, out.start);
@@ -290,7 +381,7 @@ njs_process_file(njs_opts_t *opts, njs_v
 
     ret = njs_process_script(vm, opts, &script, &out);
     if (ret != NXT_OK) {
-        fprintf(stderr, "njs_process_script() failed\n");
+        fprintf(stderr, "failed to get retval from VM\n");
         return NXT_ERROR;
     }
 
@@ -498,3 +589,58 @@ njs_completion_generator(const char *tex
 
     return NULL;
 }
+
+
+static njs_ret_t
+njs_ext_console_log(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
+    njs_index_t unused)
+{
+    nxt_str_t  msg;
+
+    msg.length = 0;
+
+    if (nargs >= 2
+        && njs_value_to_ext_string(vm, &msg, njs_argument(args, 1))
+           == NJS_ERROR)
+    {
+
+        return NJS_ERROR;
+    }
+
+    printf("%.*s\n", (int) msg.length, msg.start);
+
+    vm->retval = njs_value_void;
+
+    return NJS_OK;
+}
+
+
+static njs_ret_t
+njs_ext_console_help(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
+    njs_index_t unused)
+{
+    nxt_uint_t  i;
+
+    printf("VM built-in objects:\n");
+    for (i = NJS_CONSTRUCTOR_OBJECT; i < NJS_CONSTRUCTOR_MAX; i++) {
+        printf("  %.*s\n", (int) njs_constructor_init[i]->name.length,
+               njs_constructor_init[i]->name.start);
+    }
+
+    for (i = NJS_OBJECT_THIS; i < NJS_OBJECT_MAX; i++) {
+        if (njs_object_init[i] != NULL) {
+            printf("  %.*s\n", (int) njs_object_init[i]->name.length,
+                   njs_object_init[i]->name.start);
+        }
+    }
+
+    printf("\nEmbedded objects:\n");
+    for (i = 0; i < nxt_nitems(njs_externals); i++) {
+        printf("  %.*s\n", (int) njs_externals[i].name.length,
+               njs_externals[i].name.start);
+    }
+
+    printf("\n");
+
+    return NJS_OK;
+}
diff -r 46ea39d059e1 -r 27aa477208f5 njs/njs_builtin.c
--- a/njs/njs_builtin.c	Thu Aug 31 20:03:13 2017 +0300
+++ b/njs/njs_builtin.c	Thu Aug 31 20:27:31 2017 +0300
@@ -22,6 +22,7 @@
 #include <njs_array.h>
 #include <njs_function.h>
 #include <njs_variable.h>
+#include <njs_extern.h>
 #include <njs_parser.h>
 #include <njs_regexp.h>
 #include <njs_date.h>
@@ -40,13 +41,13 @@ static nxt_int_t njs_builtin_completions
     const char **completions);
 
 
-static const njs_object_init_t    *object_init[] = {
+const njs_object_init_t    *njs_object_init[] = {
     NULL,                         /* global this        */
     &njs_math_object_init,        /* Math               */
 };
 
 
-static const njs_object_init_t  *prototype_init[] = {
+const njs_object_init_t  *njs_prototype_init[] = {
     &njs_object_prototype_init,
     &njs_array_prototype_init,
     &njs_boolean_prototype_init,
@@ -58,7 +59,7 @@ static const njs_object_init_t  *prototy
 };
 
 
-static const njs_object_init_t    *constructor_init[] = {
+const njs_object_init_t    *njs_constructor_init[] = {
     &njs_object_constructor_init,
     &njs_array_constructor_init,
     &njs_boolean_constructor_init,
@@ -189,10 +190,10 @@ njs_builtin_objects_create(njs_vm_t *vm)
     objects = vm->shared->objects;
 
     for (i = NJS_OBJECT_THIS; i < NJS_OBJECT_MAX; i++) {
-        if (object_init[i] != NULL) {
+        if (njs_object_init[i] != NULL) {
             ret = njs_object_hash_create(vm, &objects[i].shared_hash,
-                                         object_init[i]->properties,
-                                         object_init[i]->items);
+                                         njs_object_init[i]->properties,
+                                         njs_object_init[i]->items);
             if (nxt_slow_path(ret != NXT_OK)) {
                 return NXT_ERROR;
             }
@@ -231,8 +232,8 @@ njs_builtin_objects_create(njs_vm_t *vm)
         prototypes[i] = prototype_values[i];
 
         ret = njs_object_hash_create(vm, &prototypes[i].object.shared_hash,
-                                     prototype_init[i]->properties,
-                                     prototype_init[i]->items);
+                                     njs_prototype_init[i]->properties,
+                                     njs_prototype_init[i]->items);
         if (nxt_slow_path(ret != NXT_OK)) {
             return NXT_ERROR;
         }
@@ -257,8 +258,8 @@ njs_builtin_objects_create(njs_vm_t *vm)
         constructors[i].args_types[4] = native_constructors[i].args_types[4];
 
         ret = njs_object_hash_create(vm, &constructors[i].object.shared_hash,
-                                     constructor_init[i]->properties,
-                                     constructor_init[i]->items);
+                                     njs_constructor_init[i]->properties,
+                                     njs_constructor_init[i]->items);
         if (nxt_slow_path(ret != NXT_OK)) {
             return NXT_ERROR;
         }
@@ -375,11 +376,12 @@ njs_builtin_completions(njs_vm_t *vm, si
     size_t                  n, len;
     nxt_str_t               string;
     nxt_uint_t              i, k;
+    njs_extern_t            *ext_object, *ext_prop;
     njs_object_t            *objects;
     njs_keyword_t           *keyword;
     njs_function_t          *constructors;
     njs_object_prop_t       *prop;
-    nxt_lvlhsh_each_t       lhe;
+    nxt_lvlhsh_each_t       lhe, lhe_prop;
     njs_object_prototype_t  *prototypes;
 
     n = 0;
@@ -404,7 +406,7 @@ njs_builtin_completions(njs_vm_t *vm, si
     objects = vm->shared->objects;
 
     for (i = NJS_OBJECT_THIS; i < NJS_OBJECT_MAX; i++) {
-        if (object_init[i] == NULL) {
+        if (njs_object_init[i] == NULL) {
             continue;
         }
 
@@ -419,14 +421,14 @@ njs_builtin_completions(njs_vm_t *vm, si
 
             if (completions != NULL) {
                 njs_string_get(&prop->name, &string);
-                len = object_init[i]->name.length + string.length + 2;
+                len = njs_object_init[i]->name.length + string.length + 2;
 
                 compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len);
                 if (compl == NULL) {
                     return NXT_ERROR;
                 }
 
-                snprintf(compl, len, "%s.%s", object_init[i]->name.start,
+                snprintf(compl, len, "%s.%s", njs_object_init[i]->name.start,
                          string.start);
 
                 completions[n++] = (char *) compl;
@@ -490,15 +492,68 @@ njs_builtin_completions(njs_vm_t *vm, si
 
             if (completions != NULL) {
                 njs_string_get(&prop->name, &string);
-                len = constructor_init[i]->name.length + string.length + 2;
+                len = njs_constructor_init[i]->name.length + string.length + 2;
 
                 compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len);
                 if (compl == NULL) {
                     return NXT_ERROR;
                 }
 
-                snprintf(compl, len, "%s.%s", constructor_init[i]->name.start,
-                         string.start);
+                snprintf(compl, len, "%s.%s",
+                         njs_constructor_init[i]->name.start, string.start);
+
+                completions[n++] = (char *) compl;
+
+            } else {
+                n++;
+            }
+        }
+    }
+
+    nxt_lvlhsh_each_init(&lhe, &njs_extern_hash_proto);
+
+    for ( ;; ) {
+        ext_object = nxt_lvlhsh_each(&vm->externals_hash, &lhe);
+
+        if (ext_object == NULL) {
+            break;
+        }
+
+        nxt_lvlhsh_each_init(&lhe_prop, &njs_extern_hash_proto);
+
+        if (completions != NULL) {
+            len = ext_object->name.length + 1;
+            compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len);
+            if (compl == NULL) {
+                return NXT_ERROR;
+            }
+
+            snprintf(compl, len, "%.*s",
+                     (int) ext_object->name.length, ext_object->name.start);
+
+            completions[n++] = (char *) compl;
+
+        } else {
+            n++;
+        }
+
+        for ( ;; ) {
+            ext_prop = nxt_lvlhsh_each(&ext_object->hash, &lhe_prop);
+
+            if (ext_prop == NULL) {
+                break;
+            }
+
+            if (completions != NULL) {
+                len = ext_object->name.length + ext_prop->name.length + 2;
+                compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len);
+                if (compl == NULL) {
+                    return NXT_ERROR;
+                }
+
+                snprintf(compl, len, "%.*s.%.*s",
+                         (int) ext_object->name.length, ext_object->name.start,
+                         (int) ext_prop->name.length, ext_prop->name.start);
 
                 completions[n++] = (char *) compl;
 
@@ -533,7 +588,7 @@ njs_builtin_match_native_function(njs_vm
     objects = vm->shared->objects;
 
     for (i = NJS_OBJECT_THIS; i < NJS_OBJECT_MAX; i++) {
-        if (object_init[i] == NULL) {
+        if (njs_object_init[i] == NULL) {
             continue;
         }
 
@@ -552,7 +607,7 @@ njs_builtin_match_native_function(njs_vm
 
             if (function == prop->value.data.u.function) {
                 njs_string_get(&prop->name, &string);
-                len = object_init[i]->name.length + string.length
+                len = njs_object_init[i]->name.length + string.length
                       + sizeof(".");
 
                 buf = nxt_mem_cache_zalloc(vm->mem_cache_pool, len);
@@ -560,7 +615,7 @@ njs_builtin_match_native_function(njs_vm
                     return NXT_ERROR;
                 }
 
-                snprintf(buf, len, "%s.%s", object_init[i]->name.start,
+                snprintf(buf, len, "%s.%s", njs_object_init[i]->name.start,
                          string.start);
 
                 name->length = len;
@@ -589,7 +644,7 @@ njs_builtin_match_native_function(njs_vm
 
             if (function == prop->value.data.u.function) {
                 njs_string_get(&prop->name, &string);
-                len = prototype_init[i]->name.length + string.length
+                len = njs_prototype_init[i]->name.length + string.length
                       + sizeof(".prototype.");
 
                 buf = nxt_mem_cache_zalloc(vm->mem_cache_pool, len);
@@ -598,7 +653,7 @@ njs_builtin_match_native_function(njs_vm
                 }
 
                 snprintf(buf, len, "%s.prototype.%s",
-                         prototype_init[i]->name.start, string.start);
+                         njs_prototype_init[i]->name.start, string.start);
 
                 name->length = len;
                 name->start = (u_char *) buf;
@@ -626,7 +681,7 @@ njs_builtin_match_native_function(njs_vm
 
             if (function == prop->value.data.u.function) {
                 njs_string_get(&prop->name, &string);
-                len = constructor_init[i]->name.length + string.length
+                len = njs_constructor_init[i]->name.length + string.length
                       + sizeof(".");
 
                 buf = nxt_mem_cache_zalloc(vm->mem_cache_pool, len);
@@ -634,7 +689,7 @@ njs_builtin_match_native_function(njs_vm
                     return NXT_ERROR;
                 }
 
-                snprintf(buf, len, "%s.%s", constructor_init[i]->name.start,
+                snprintf(buf, len, "%s.%s", njs_constructor_init[i]->name.start,
                          string.start);
 
                 name->length = len;
diff -r 46ea39d059e1 -r 27aa477208f5 njs/njs_builtin.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/njs/njs_builtin.h	Thu Aug 31 20:27:31 2017 +0300
@@ -0,0 +1,15 @@
+
+/*
+ * Copyright (C) Dmitry Volyntsev
+ * Copyright (C) NGINX, Inc.
+ */
+
+#ifndef _NJS_BUILTIN_H_INCLUDED_
+#define _NJS_BUILTIN_H_INCLUDED_
+
+
+extern const njs_object_init_t  *njs_object_init[];
+extern const njs_object_init_t  *njs_prototype_init[];
+extern const njs_object_init_t  *njs_constructor_init[];
+
+#endif /* _NJS_BUILTIN_H_INCLUDED_ */
diff -r 46ea39d059e1 -r 27aa477208f5 njs/njscript.c
--- a/njs/njscript.c	Thu Aug 31 20:03:13 2017 +0300
+++ b/njs/njscript.c	Thu Aug 31 20:27:31 2017 +0300
@@ -162,12 +162,16 @@ njs_vm_create(njs_vm_opt_t *options)
             if (nxt_slow_path(ret != NXT_OK)) {
                 return NULL;
             }
+
+            if (options->externals_hash != NULL) {
+                vm->external = options->external;
+            }
         }
 
         nxt_lvlhsh_init(&vm->values_hash);
 
-        if (options->externals != NULL) {
-            vm->externals_hash = *options->externals;
+        if (options->externals_hash != NULL) {
+            vm->externals_hash = *options->externals_hash;
         }
 
         vm->trace.level = NXT_LEVEL_TRACE;
diff -r 46ea39d059e1 -r 27aa477208f5 njs/njscript.h
--- a/njs/njscript.h	Thu Aug 31 20:03:13 2017 +0300
+++ b/njs/njscript.h	Thu Aug 31 20:27:31 2017 +0300
@@ -66,7 +66,8 @@ struct njs_external_s {
 };
 
 typedef struct {
-    nxt_lvlhsh_t                    *externals;
+    void                            **external;
+    nxt_lvlhsh_t                    *externals_hash;
     njs_vm_shared_t                 *shared;
     nxt_mem_cache_pool_t            *mcp;
 
diff -r 46ea39d059e1 -r 27aa477208f5 njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c	Thu Aug 31 20:03:13 2017 +0300
+++ b/njs/test/njs_unit_test.c	Thu Aug 31 20:27:31 2017 +0300
@@ -8170,7 +8170,7 @@ njs_unit_test(nxt_bool_t disassemble)
         memset(&options, 0, sizeof(njs_vm_opt_t));
 
         options.mcp = mcp;
-        options.externals = &externals;
+        options.externals_hash = &externals;
 
         vm = njs_vm_create(&options);
         if (vm == NULL) {


More information about the nginx-devel mailing list