[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