[njs] Fixed the calculation of the scope indices for variables.
Dmitry Volyntsev
xeioex at nginx.com
Fri Feb 9 17:14:05 UTC 2018
details: http://hg.nginx.org/njs/rev/03eebf0e08cc
branches:
changeset: 438:03eebf0e08cc
user: Dmitry Volyntsev <xeioex at 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) {"
More information about the nginx-devel
mailing list