details: http://hg.nginx.org/njs/rev/27aa477208f5 branches: changeset: 403:27aa477208f5 user: Dmitry Volyntsev <xei...@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) { _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-devel