details: http://hg.nginx.org/njs/rev/03eebf0e08cc branches: changeset: 438:03eebf0e08cc user: Dmitry Volyntsev <xei...@nginx.com> date: Fri Feb 09 20:11:17 2018 +0300 description: Fixed the calculation of the scope indices for variables.
diffstat: njs/njs_parser.h | 14 +++++--- njs/njs_variable.c | 80 +++++++++++++++++++++++++++++++++++++---------- njs/test/njs_unit_test.c | 21 ++++++++++++ 3 files changed, 93 insertions(+), 22 deletions(-) diffs (221 lines): diff -r 05605a9f0ad7 -r 03eebf0e08cc njs/njs_parser.h --- a/njs/njs_parser.h Fri Feb 09 19:16:19 2018 +0300 +++ b/njs/njs_parser.h Fri Feb 09 20:11:17 2018 +0300 @@ -235,11 +235,15 @@ struct njs_parser_scope_s { nxt_lvlhsh_t variables; nxt_lvlhsh_t references; - nxt_array_t *values[2]; /* Array of njs_value_t. */ + /* + * 0: local scope index; + * 1: closure scope index. + */ + nxt_array_t *values[2]; /* Array of njs_value_t. */ njs_index_t next_index[2]; njs_scope_t type:8; - uint8_t nesting; /* 4 bits */ + uint8_t nesting; /* 4 bits */ uint8_t argument_closures; }; @@ -248,9 +252,9 @@ typedef struct njs_parser_node_s njs_ struct njs_parser_node_s { njs_token_t token:16; - uint8_t ctor:1; /* 1 bit */ - uint8_t temporary; /* 1 bit */ - uint8_t reference; /* 1 bit */ + uint8_t ctor:1; /* 1 bit */ + uint8_t temporary; /* 1 bit */ + uint8_t reference; /* 1 bit */ uint32_t token_line; uint32_t variable_name_hash; diff -r 05605a9f0ad7 -r 03eebf0e08cc njs/njs_variable.c --- a/njs/njs_variable.c Fri Feb 09 19:16:19 2018 +0300 +++ b/njs/njs_variable.c Fri Feb 09 20:11:17 2018 +0300 @@ -223,15 +223,17 @@ njs_variable_reference(njs_vm_t *vm, njs } -njs_ret_t -njs_variables_scope_reference(njs_vm_t *vm, njs_parser_scope_t *scope) +static njs_ret_t +njs_variables_scope_resolve(njs_vm_t *vm, njs_parser_scope_t *scope, + nxt_bool_t local_scope) { - 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; + 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; + njs_variable_scope_t vs; nested = &scope->nested; @@ -241,7 +243,7 @@ njs_variables_scope_reference(njs_vm_t * { scope = nxt_queue_link_data(lnk, njs_parser_scope_t, link); - ret = njs_variables_scope_reference(vm, scope); + ret = njs_variables_scope_resolve(vm, scope, local_scope); if (nxt_slow_path(ret != NXT_OK)) { return NXT_ERROR; } @@ -255,6 +257,25 @@ njs_variables_scope_reference(njs_vm_t * break; } + if (!local_scope) { + ret = njs_variable_find(vm, node, &vs); + if (nxt_slow_path(ret != NXT_OK)) { + continue; + } + + if (vs.scope->type == NJS_SCOPE_GLOBAL) { + continue; + } + + if (node->scope->nesting == vs.scope->nesting) { + /* + * A variable is referenced locally here, but may be + * referenced non-locally in other places, skipping. + */ + continue; + } + } + var = njs_variable_get(vm, node); if (nxt_slow_path(var == NULL)) { return NXT_ERROR; @@ -266,6 +287,31 @@ njs_variables_scope_reference(njs_vm_t * } +njs_ret_t +njs_variables_scope_reference(njs_vm_t *vm, njs_parser_scope_t *scope) +{ + njs_ret_t ret; + + /* + * Calculating proper scope types for variables. + * A variable is considered to be local variable if it is referenced + * only in the local scope (reference and definition nestings are the same). + */ + + ret = njs_variables_scope_resolve(vm, scope, 0); + if (nxt_slow_path(ret != NXT_OK)) { + return NXT_ERROR; + } + + ret = njs_variables_scope_resolve(vm, scope, 1); + if (nxt_slow_path(ret != NXT_OK)) { + return NXT_ERROR; + } + + return NXT_OK; +} + + njs_index_t njs_variable_typeof(njs_vm_t *vm, njs_parser_node_t *node) { @@ -309,7 +355,7 @@ njs_variable_t * njs_variable_get(njs_vm_t *vm, njs_parser_node_t *node) { nxt_int_t ret; - nxt_uint_t n; + nxt_uint_t scope_index; nxt_array_t *values; njs_index_t index; njs_value_t *value; @@ -322,10 +368,10 @@ njs_variable_get(njs_vm_t *vm, njs_parse goto not_found; } - n = 0; + scope_index = 0; if (vs.scope->type > NJS_SCOPE_GLOBAL) { - n = (node->scope->nesting != vs.scope->nesting); + scope_index = (node->scope->nesting != vs.scope->nesting); } var = vs.variable; @@ -333,7 +379,7 @@ njs_variable_get(njs_vm_t *vm, njs_parse if (index != NJS_INDEX_NONE) { - if (n == 0 || njs_scope_type(index) != NJS_SCOPE_ARGUMENTS) { + if (scope_index == 0 || njs_scope_type(index) != NJS_SCOPE_ARGUMENTS) { node->index = index; return var; @@ -371,7 +417,7 @@ njs_variable_get(njs_vm_t *vm, njs_parse index = (njs_index_t) value; } else { - values = vs.scope->values[n]; + values = vs.scope->values[scope_index]; if (values == NULL) { values = nxt_array_create(4, sizeof(njs_value_t), @@ -380,7 +426,7 @@ njs_variable_get(njs_vm_t *vm, njs_parse return NULL; } - vs.scope->values[n] = values; + vs.scope->values[scope_index] = values; } value = nxt_array_add(values, &njs_array_mem_proto, vm->mem_cache_pool); @@ -388,8 +434,8 @@ njs_variable_get(njs_vm_t *vm, njs_parse return NULL; } - index = vs.scope->next_index[n]; - vs.scope->next_index[n] += sizeof(njs_value_t); + index = vs.scope->next_index[scope_index]; + vs.scope->next_index[scope_index] += sizeof(njs_value_t); } if (njs_is_object(&var->value)) { diff -r 05605a9f0ad7 -r 03eebf0e08cc njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Fri Feb 09 19:16:19 2018 +0300 +++ b/njs/test/njs_unit_test.c Fri Feb 09 20:11:17 2018 +0300 @@ -4591,6 +4591,27 @@ static njs_unit_test_t njs_test[] = "function f() { function h() { x = 3; return y; } }"), nxt_string("undefined") }, + { nxt_string("function f() {" + " var a = 'a';" + " if (0) { a = 'b' };" + " function f2() { return a };" + " return f2" + "};" + "f()()"), + nxt_string("a") }, + + { nxt_string("function f() {" + " var a = 'a'; " + " if (0) { if (0) {a = 'b'} };" + " function f2() { return a };" + " return f2" + "};" + "f()()"), + nxt_string("a") }, + + { nxt_string("function f() { var a = f2(); }"), + nxt_string("ReferenceError: \"f2\" is not defined in 1") }, + /* Recursive fibonacci. */ { nxt_string("function fibo(n) {" _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-devel