details: https://hg.nginx.org/njs/rev/88c5787352b2 branches: changeset: 978:88c5787352b2 user: Alexander Borisov <alexander.bori...@nginx.com> date: Wed May 22 21:01:39 2019 +0300 description: Improved working with undefined symbols.
Throwing ReferenceError in runtime. This closes #150 issue on GitHub. diffstat: njs/njs_disassembler.c | 8 ++++++++ njs/njs_generator.c | 33 ++++++++++++++++++++++++++++++--- njs/njs_variable.c | 19 +++---------------- njs/njs_variable.h | 1 + njs/njs_vm.c | 15 +++++++++++++++ njs/njs_vm.h | 9 +++++++++ njs/test/njs_unit_test.c | 24 ++++++++++++++++++++++++ 7 files changed, 90 insertions(+), 19 deletions(-) diffs (244 lines): diff -r 260d9d4f29ee -r 88c5787352b2 njs/njs_disassembler.c --- a/njs/njs_disassembler.c Tue May 21 21:15:21 2019 +0300 +++ b/njs/njs_disassembler.c Wed May 22 21:01:39 2019 +0300 @@ -411,6 +411,14 @@ njs_disassemble(u_char *start, u_char *e continue; } + if (operation == njs_vmcode_reference_error) { + nxt_printf("%05uz REFERENCE ERROR\n", p - start); + + p += sizeof(njs_vmcode_reference_error_t); + + continue; + } + code_name = code_names; n = nxt_nitems(code_names); diff -r 260d9d4f29ee -r 88c5787352b2 njs/njs_generator.c --- a/njs/njs_generator.c Tue May 21 21:15:21 2019 +0300 +++ b/njs/njs_generator.c Wed May 22 21:01:39 2019 +0300 @@ -174,6 +174,8 @@ static nxt_noinline nxt_int_t njs_genera njs_generator_t *generator, njs_parser_node_t *node); static nxt_noinline nxt_int_t njs_generate_index_release(njs_vm_t *vm, njs_generator_t *generator, njs_index_t index); +static nxt_int_t njs_generate_reference_error(njs_vm_t *vm, + njs_generator_t *generator, njs_parser_node_t *node); static nxt_int_t njs_generate_function_debug(njs_vm_t *vm, const nxt_str_t *name, njs_function_lambda_t *lambda, @@ -550,7 +552,7 @@ njs_generate_name(njs_vm_t *vm, njs_gene var = njs_variable_resolve(vm, node); if (nxt_slow_path(var == NULL)) { - return NXT_ERROR; + return njs_generate_reference_error(vm, generator, node); } if (var->type == NJS_VARIABLE_FUNCTION) { @@ -606,7 +608,7 @@ njs_generate_variable(njs_vm_t *vm, njs_ index = njs_variable_index(vm, node); if (nxt_slow_path(index == NJS_INDEX_NONE)) { - return NXT_ERROR; + return njs_generate_reference_error(vm, generator, node); } node->index = index; @@ -2304,7 +2306,7 @@ njs_generate_function_declaration(njs_vm var = njs_variable_resolve(vm, node); if (nxt_slow_path(var == NULL)) { - return NXT_ERROR; + return njs_generate_reference_error(vm, generator, node); } if (!njs_is_function(&var->value)) { @@ -2591,6 +2593,10 @@ njs_generate_function_call(njs_vm_t *vm, name = node; } + if (node->u.reference.not_defined) { + return NXT_OK; + } + njs_generate_code(generator, njs_vmcode_function_frame_t, func, njs_vmcode_function_frame, 2, 0); func_offset = njs_code_offset(generator, func); @@ -3273,6 +3279,27 @@ njs_generate_index_release(njs_vm_t *vm, static nxt_int_t +njs_generate_reference_error(njs_vm_t *vm, njs_generator_t *generator, + njs_parser_node_t *node) +{ + njs_vmcode_reference_error_t *ref_err; + + if (nxt_slow_path(!node->u.reference.not_defined)) { + njs_internal_error(vm, "variable is not defined but not_defined " + "is not set"); + return NJS_ERROR; + } + + njs_generate_code(generator, njs_vmcode_reference_error_t, ref_err, + njs_vmcode_reference_error, 0, 0); + + ref_err->token_line = node->token_line; + + return njs_name_copy(vm, &ref_err->name, &node->u.reference.name); +} + + +static nxt_int_t njs_generate_function_debug(njs_vm_t *vm, const nxt_str_t *name, njs_function_lambda_t *lambda, njs_parser_node_t *node) { diff -r 260d9d4f29ee -r 88c5787352b2 njs/njs_variable.c --- a/njs/njs_variable.c Tue May 21 21:15:21 2019 +0300 +++ b/njs/njs_variable.c Wed May 22 21:01:39 2019 +0300 @@ -280,7 +280,6 @@ njs_variables_scope_resolve(njs_vm_t *vm { njs_ret_t ret; nxt_queue_t *nested; - njs_variable_t *var; nxt_queue_link_t *lnk; njs_parser_node_t *node; nxt_lvlhsh_each_t lhe; @@ -321,13 +320,7 @@ njs_variables_scope_resolve(njs_vm_t *vm } } - var = njs_variable_resolve(vm, node); - - if (nxt_slow_path(var == NULL)) { - if (vr->type != NJS_TYPEOF) { - return NXT_ERROR; - } - } + (void) njs_variable_resolve(vm, node); } } @@ -415,7 +408,8 @@ njs_variable_resolve(njs_vm_t *vm, njs_p ret = njs_variable_reference_resolve(vm, vr, node->scope); if (nxt_slow_path(ret != NXT_OK)) { - goto not_found; + node->u.reference.not_defined = 1; + return NULL; } scope_index = vr->scope_index; @@ -455,13 +449,6 @@ njs_variable_resolve(njs_vm_t *vm, njs_p node->index = index; return var; - -not_found: - - njs_parser_node_error(vm, node, NJS_OBJECT_REF_ERROR, - "\"%V\" is not defined", &vr->name); - - return NULL; } diff -r 260d9d4f29ee -r 88c5787352b2 njs/njs_variable.h --- a/njs/njs_variable.h Tue May 21 21:15:21 2019 +0300 +++ b/njs/njs_variable.h Wed May 22 21:01:39 2019 +0300 @@ -50,6 +50,7 @@ typedef struct { njs_variable_t *variable; njs_parser_scope_t *scope; nxt_uint_t scope_index; /* NJS_SCOPE_INDEX_... */ + nxt_bool_t not_defined; } njs_variable_reference_t; diff -r 260d9d4f29ee -r 88c5787352b2 njs/njs_vm.c --- a/njs/njs_vm.c Tue May 21 21:15:21 2019 +0300 +++ b/njs/njs_vm.c Wed May 22 21:01:39 2019 +0300 @@ -2523,6 +2523,21 @@ njs_vmcode_finally(njs_vm_t *vm, njs_val } +njs_ret_t +njs_vmcode_reference_error(njs_vm_t *vm, njs_value_t *invld1, + njs_value_t *invld2) +{ + njs_vmcode_reference_error_t *ref_err; + + ref_err = (njs_vmcode_reference_error_t *) vm->current; + + njs_reference_error(vm, "\"%V\" is not defined in %uD", &ref_err->name, + ref_err->token_line); + + return NJS_ERROR; +} + + static const njs_vmcode_1addr_t njs_trap_number[] = { { .code = { .operation = njs_vmcode_number_primitive, .operands = NJS_VMCODE_1OPERAND, diff -r 260d9d4f29ee -r 88c5787352b2 njs/njs_vm.h --- a/njs/njs_vm.h Tue May 21 21:15:21 2019 +0300 +++ b/njs/njs_vm.h Wed May 22 21:01:39 2019 +0300 @@ -849,6 +849,13 @@ typedef struct { } njs_vmcode_finally_t; +typedef struct { + njs_vmcode_t code; + nxt_str_t name; + uint32_t token_line; +} njs_vmcode_reference_error_t; + + typedef enum { NJS_SCOPE_ABSOLUTE = 0, NJS_SCOPE_GLOBAL = 1, @@ -1303,6 +1310,8 @@ njs_ret_t njs_vmcode_catch(njs_vm_t *vm, njs_value_t *exception); njs_ret_t njs_vmcode_finally(njs_vm_t *vm, njs_value_t *invld, njs_value_t *retval); +njs_ret_t njs_vmcode_reference_error(njs_vm_t *vm, njs_value_t *invld1, + njs_value_t *invld2); nxt_bool_t njs_values_strict_equal(const njs_value_t *val1, const njs_value_t *val2); diff -r 260d9d4f29ee -r 88c5787352b2 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue May 21 21:15:21 2019 +0300 +++ b/njs/test/njs_unit_test.c Wed May 22 21:01:39 2019 +0300 @@ -6294,8 +6294,32 @@ static njs_unit_test_t njs_test[] = nxt_string("a") }, { nxt_string("function f() { var a = f2(); }"), + nxt_string("undefined") }, + + { nxt_string("function f() { var a = f2(); } f();"), nxt_string("ReferenceError: \"f2\" is not defined in 1") }, + { nxt_string("typeof Buffer !== 'undefined' ? Buffer : function Buffer(){}"), + nxt_string("[object Function]") }, + + { nxt_string("1 == 2 ? func() : '123'"), + nxt_string("123") }, + + { nxt_string("1 == 1 ? func() : '123'"), + nxt_string("ReferenceError: \"func\" is not defined in 1") }, + + { nxt_string("function f(){ if (1 == 1) { 1 == 2 ? some_var : '123' } }; f()"), + nxt_string("undefined") }, + + { nxt_string("function f(){ if (1 == 1) { 1 == 1 ? some_var : '123' } }; f()"), + nxt_string("ReferenceError: \"some_var\" is not defined in 1") }, + + { nxt_string("function f(){ if (1 == 1) { 1 == 2 ? some_func() : '123' } }; f()"), + nxt_string("undefined") }, + + { nxt_string("function f(){ if (1 == 1) { 1 == 1 ? some_func() : '123' } }; f()"), + nxt_string("ReferenceError: \"some_func\" is not defined in 1") }, + { nxt_string("(function(){ function f() {return f}; return f()})()"), nxt_string("[object Function]") }, _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-devel