[njs] Global and function scopes have been fixed. Implicitly declared

Igor Sysoev igor at sysoev.ru
Tue Jan 3 15:35:27 UTC 2017


details:   http://hg.nginx.org/njs/rev/4337ed48d6d6
branches:  
changeset: 293:4337ed48d6d6
user:      Igor Sysoev <igor at sysoev.ru>
date:      Mon Jan 02 22:59:24 2017 +0300
description:
Global and function scopes have been fixed. Implicitly declared
variables are not supported anymore.

diffstat:

 Makefile                    |    3 +
 njs/njs_disassembler.c      |    2 -
 njs/njs_function.c          |    4 +-
 njs/njs_generator.c         |  436 +++++++++++++++++++++++++------------
 njs/njs_parser.c            |  445 +++++++++++++++++++++++---------------
 njs/njs_parser.h            |   49 ++-
 njs/njs_parser_expression.c |   71 +----
 njs/njs_variable.c          |  342 ++++++++++++++++++++++-------
 njs/njs_variable.h          |   35 +-
 njs/njs_vm.c                |   24 +-
 njs/njs_vm.h                |   19 +-
 njs/njscript.c              |   21 +-
 njs/test/njs_unit_test.c    |  503 +++++++++++++++++++++++--------------------
 13 files changed, 1171 insertions(+), 783 deletions(-)

diffs (truncated from 3807 to 1000 lines):

diff -r 2d9ccf739861 -r 4337ed48d6d6 Makefile
--- a/Makefile	Sun Jan 01 20:45:59 2017 +0300
+++ b/Makefile	Mon Jan 02 22:59:24 2017 +0300
@@ -334,6 +334,7 @@ dist:
 	njs/njs_string.h \
 	njs/njs_object.h \
 	njs/njs_function.h \
+	njs/njs_variable.h \
 	njs/njs_parser.h \
 	njs/njs_parser.c \
 
@@ -348,6 +349,7 @@ dist:
 	njs/njs_number.h \
 	njs/njs_object.h \
 	njs/njs_function.h \
+	njs/njs_variable.h \
 	njs/njs_parser.h \
 	njs/njs_parser_expression.c \
 
@@ -363,6 +365,7 @@ dist:
 	njs/njs_string.h \
 	njs/njs_object.h \
 	njs/njs_function.h \
+	njs/njs_variable.h \
 	njs/njs_parser.h \
 	njs/njs_generator.c \
 
diff -r 2d9ccf739861 -r 4337ed48d6d6 njs/njs_disassembler.c
--- a/njs/njs_disassembler.c	Sun Jan 01 20:45:59 2017 +0300
+++ b/njs/njs_disassembler.c	Mon Jan 02 22:59:24 2017 +0300
@@ -133,8 +133,6 @@ static njs_code_name_t  code_names[] = {
 
     { njs_vmcode_move, sizeof(njs_vmcode_move_t),
           nxt_string("MOVE            ") },
-    { njs_vmcode_validate, sizeof(njs_vmcode_validate_t),
-          nxt_string("VALIDATE        ") },
 
     { njs_vmcode_throw, sizeof(njs_vmcode_throw_t),
           nxt_string("THROW           ") },
diff -r 2d9ccf739861 -r 4337ed48d6d6 njs/njs_function.c
--- a/njs/njs_function.c	Sun Jan 01 20:45:59 2017 +0300
+++ b/njs/njs_function.c	Mon Jan 02 22:59:24 2017 +0300
@@ -307,8 +307,8 @@ njs_function_call(njs_vm_t *vm, njs_inde
 #if (NXT_DEBUG)
     vm->scopes[NJS_SCOPE_CALLEE_ARGUMENTS] = NULL;
 #endif
-    frame->prev_local = vm->scopes[NJS_SCOPE_LOCAL];
-    vm->scopes[NJS_SCOPE_LOCAL] = frame->local;
+    frame->prev_local = vm->scopes[NJS_SCOPE_FUNCTION];
+    vm->scopes[NJS_SCOPE_FUNCTION] = frame->local;
 
     return NJS_APPLIED;
 }
diff -r 2d9ccf739861 -r 4337ed48d6d6 njs/njs_generator.c
--- a/njs/njs_generator.c	Sun Jan 01 20:45:59 2017 +0300
+++ b/njs/njs_generator.c	Mon Jan 02 22:59:24 2017 +0300
@@ -30,7 +30,9 @@ static nxt_int_t njs_generate_name(njs_v
     njs_parser_node_t *node);
 static nxt_int_t njs_generate_builtin_object(njs_vm_t *vm, njs_parser_t *parser,
     njs_parser_node_t *node);
-static nxt_int_t njs_generate_variable(njs_parser_t *parser,
+static nxt_int_t njs_generate_variable(njs_vm_t *vm, njs_parser_t *parser,
+    njs_parser_node_t *node);
+static nxt_int_t njs_generate_var_statement(njs_vm_t *vm, njs_parser_t *parser,
     njs_parser_node_t *node);
 static nxt_int_t njs_generate_if_statement(njs_vm_t *vm, njs_parser_t *parser,
     njs_parser_node_t *node);
@@ -82,6 +84,8 @@ static nxt_int_t njs_generate_3addr_oper
     njs_parser_t *parser, njs_parser_node_t *node);
 static nxt_int_t njs_generate_2addr_operation(njs_vm_t *vm,
     njs_parser_t *parser, njs_parser_node_t *node);
+static nxt_int_t njs_generate_typeof_operation(njs_vm_t *vm,
+    njs_parser_t *parser, njs_parser_node_t *node);
 static nxt_int_t njs_generate_inc_dec_operation(njs_vm_t *vm,
     njs_parser_t *parser, njs_parser_node_t *node, nxt_bool_t post);
 static nxt_int_t njs_generate_function_declaration(njs_vm_t *vm,
@@ -103,12 +107,12 @@ static nxt_int_t njs_generate_throw_stat
 static nxt_noinline njs_index_t njs_generator_dest_index(njs_vm_t *vm,
     njs_parser_t *parser, njs_parser_node_t *node);
 static nxt_noinline njs_index_t
-    njs_generator_object_dest_index(njs_parser_t *parser,
+    njs_generator_object_dest_index(njs_vm_t *vm, njs_parser_t *parser,
     njs_parser_node_t *node);
-static njs_index_t njs_generator_node_temp_index_get(njs_parser_t *parser,
-    njs_parser_node_t *node);
-static nxt_noinline njs_index_t
-    njs_generator_temp_index_get(njs_parser_t *parser);
+static njs_index_t njs_generator_node_temp_index_get(njs_vm_t *vm,
+    njs_parser_t *parser, njs_parser_node_t *node);
+static nxt_noinline njs_index_t njs_generator_temp_index_get(njs_vm_t *vm,
+    njs_parser_t *parser, njs_parser_node_t *node);
 static nxt_noinline nxt_int_t
     njs_generator_children_indexes_release(njs_vm_t *vm, njs_parser_t *parser,
     njs_parser_node_t *node);
@@ -116,7 +120,6 @@ static nxt_noinline nxt_int_t njs_genera
     njs_parser_t *parser, njs_parser_node_t *node);
 static nxt_noinline nxt_int_t njs_generator_index_release(njs_vm_t *vm,
     njs_parser_t *parser, njs_index_t index);
-nxt_inline nxt_bool_t njs_generator_is_constant(njs_parser_node_t *node);
 
 
 static const nxt_str_t  no_label = { 0, NULL };
@@ -133,6 +136,9 @@ njs_generator(njs_vm_t *vm, njs_parser_t
 
     switch (node->token) {
 
+    case NJS_TOKEN_VAR:
+        return njs_generate_var_statement(vm, parser, node);
+
     case NJS_TOKEN_IF:
         return njs_generate_if_statement(vm, parser, node);
 
@@ -233,13 +239,15 @@ njs_generator(njs_vm_t *vm, njs_parser_t
 
     case NJS_TOKEN_DELETE:
     case NJS_TOKEN_VOID:
-    case NJS_TOKEN_TYPEOF:
     case NJS_TOKEN_UNARY_PLUS:
     case NJS_TOKEN_UNARY_NEGATION:
     case NJS_TOKEN_LOGICAL_NOT:
     case NJS_TOKEN_BITWISE_NOT:
         return njs_generate_2addr_operation(vm, parser, node);
 
+    case NJS_TOKEN_TYPEOF:
+        return njs_generate_typeof_operation(vm, parser, node);
+
     case NJS_TOKEN_INCREMENT:
     case NJS_TOKEN_DECREMENT:
         return njs_generate_inc_dec_operation(vm, parser, node, 0);
@@ -336,9 +344,15 @@ njs_generator(njs_vm_t *vm, njs_parser_t
 static nxt_int_t
 njs_generate_name(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node)
 {
+    njs_variable_t            *var;
     njs_vmcode_object_copy_t  *copy;
 
-    if (node->u.variable->function) {
+    var = njs_variable_get(vm, node, NJS_NAME_REFERENCE);
+    if (nxt_slow_path(var == NULL)) {
+        return NXT_ERROR;
+    }
+
+    if (var->type == NJS_VARIABLE_FUNCTION) {
 
         node->index = njs_generator_dest_index(vm, parser, node);
         if (nxt_slow_path(node->index == NJS_INDEX_ERROR)) {
@@ -350,12 +364,12 @@ njs_generate_name(njs_vm_t *vm, njs_pars
         copy->code.operands = NJS_VMCODE_2OPERANDS;
         copy->code.retval = NJS_VMCODE_RETVAL;
         copy->retval = node->index;
-        copy->object = node->u.variable->index;
+        copy->object = var->index;
 
         return NXT_OK;
     }
 
-    return njs_generate_variable(parser, node);
+    return njs_generate_variable(vm, parser, node);
 }
 
 
@@ -366,7 +380,10 @@ njs_generate_builtin_object(njs_vm_t *vm
     njs_index_t               index;
     njs_vmcode_object_copy_t  *copy;
 
-    index = node->index;
+    index = njs_variable_index(vm, node, NJS_NAME_REFERENCE);
+    if (nxt_slow_path(index == NJS_INDEX_ERROR)) {
+        return NXT_ERROR;
+    }
 
     node->index = njs_generator_dest_index(vm, parser, node);
     if (nxt_slow_path(node->index == NJS_INDEX_ERROR)) {
@@ -385,26 +402,70 @@ njs_generate_builtin_object(njs_vm_t *vm
 
 
 static nxt_int_t
-njs_generate_variable(njs_parser_t *parser, njs_parser_node_t *node)
+njs_generate_variable(njs_vm_t *vm, njs_parser_t *parser,
+    njs_parser_node_t *node)
 {
-    njs_value_t            *value;
-    njs_vmcode_validate_t  *validate;
-
-    node->index = node->u.variable->index;
-
-    if (node->state == NJS_VARIABLE_NORMAL
-        && node->u.variable->state < NJS_VARIABLE_SET)
-    {
-        njs_generate_code(parser, njs_vmcode_validate_t, validate);
-        validate->code.operation = njs_vmcode_validate;
-        validate->code.operands = NJS_VMCODE_NO_OPERAND;
-        validate->code.retval = NJS_VMCODE_NO_RETVAL;
-        validate->index = node->index;
-
-        value = njs_variable_value(parser, node->index);
-        njs_set_invalid(value);
+    njs_index_t  index;
+
+    index = njs_variable_index(vm, node, NJS_NAME_REFERENCE);
+    if (nxt_slow_path(index == NJS_INDEX_ERROR)) {
+        return NXT_ERROR;
     }
 
+    node->index = index;
+
+    return NXT_OK;
+}
+
+
+static nxt_int_t
+njs_generate_var_statement(njs_vm_t *vm, njs_parser_t *parser,
+    njs_parser_node_t *node)
+{
+    nxt_int_t          ret;
+    njs_index_t        index;
+    njs_parser_node_t  *lvalue, *expr;
+    njs_vmcode_move_t  *move;
+
+    lvalue = node->left;
+
+    index = njs_variable_index(vm, lvalue, NJS_NAME_DECLARATION);
+    if (nxt_slow_path(index == NJS_INDEX_ERROR)) {
+        return NXT_ERROR;
+    }
+
+    lvalue->index = index;
+
+    expr = node->right;
+
+    if (expr == NULL) {
+        /* Variable is only declared. */
+        return NXT_OK;
+    }
+
+    expr->dest = lvalue;
+
+    ret = njs_generator(vm, parser, expr);
+    if (nxt_slow_path(ret != NXT_OK)) {
+        return ret;
+    }
+
+    /*
+     * lvalue and expression indexes are equal if the expression is an
+     * empty object or expression result is stored directly in variable.
+     */
+    if (lvalue->index != expr->index) {
+        njs_generate_code(parser, njs_vmcode_move_t, move);
+        move->code.operation = njs_vmcode_move;
+        move->code.operands = NJS_VMCODE_2OPERANDS;
+        move->code.retval = NJS_VMCODE_RETVAL;
+        move->dst = lvalue->index;
+        move->src = expr->index;
+    }
+
+    node->index = expr->index;
+    node->temporary = expr->temporary;
+
     return NXT_OK;
 }
 
@@ -602,7 +663,10 @@ njs_generate_switch_statement(njs_vm_t *
     index = expr->index;
 
     if (!expr->temporary) {
-        index = njs_generator_temp_index_get(parser);
+        index = njs_generator_temp_index_get(vm, parser, swtch);
+        if (nxt_slow_path(index == NJS_INDEX_ERROR)) {
+            return NXT_ERROR;
+        }
 
         njs_generate_code(parser, njs_vmcode_move_t, move);
         move->code.operation = njs_vmcode_move;
@@ -953,7 +1017,11 @@ njs_generate_for_in_statement(njs_vm_t *
     prop_foreach->code.retval = NJS_VMCODE_RETVAL;
     prop_foreach->object = foreach->right->index;
 
-    index = njs_generator_temp_index_get(parser);
+    index = njs_generator_temp_index_get(vm, parser, foreach->right);
+    if (nxt_slow_path(index == NJS_INDEX_ERROR)) {
+        return NXT_ERROR;
+    }
+
     prop_foreach->next = index;
 
     /* The loop body. */
@@ -1236,11 +1304,11 @@ static nxt_int_t
 njs_generate_assignment(njs_vm_t *vm, njs_parser_t *parser,
     njs_parser_node_t *node)
 {
-    nxt_int_t                   ret;
-    njs_value_t                 *value;
-    njs_parser_node_t           *lvalue, *expr, *object, *property;
-    njs_vmcode_move_t           *move;
-    njs_vmcode_prop_set_t       *prop_set;
+    nxt_int_t              ret;
+    njs_index_t            index;
+    njs_parser_node_t      *lvalue, *expr, *object, *property;
+    njs_vmcode_move_t      *move;
+    njs_vmcode_prop_set_t  *prop_set;
 
     lvalue = node->left;
     expr = node->right;
@@ -1248,26 +1316,13 @@ njs_generate_assignment(njs_vm_t *vm, nj
 
     if (lvalue->token == NJS_TOKEN_NAME) {
 
-        lvalue->index = lvalue->u.variable->index;
-
-        /* Use a constant value is stored as variable initial value. */
-
-        if (njs_generator_is_constant(expr)) {
-
-            ret = njs_generator(vm, parser, expr);
-            if (nxt_slow_path(ret != NXT_OK)) {
-                return ret;
-            }
-
-            if (lvalue->state == NJS_VARIABLE_FIRST_ASSIGNMENT) {
-                value = njs_variable_value(parser, lvalue->index);
-                *value = expr->u.value;
-                node->index = expr->index;
-
-                return NXT_OK;
-            }
+        index = njs_variable_index(vm, lvalue, NJS_NAME_REFERENCE);
+        if (nxt_slow_path(index == NJS_INDEX_ERROR)) {
+            return NXT_ERROR;
         }
 
+        lvalue->index = index;
+
         expr->dest = lvalue;
 
         ret = njs_generator(vm, parser, expr);
@@ -1325,7 +1380,13 @@ njs_generate_assignment(njs_vm_t *vm, nj
             move->code.operands = NJS_VMCODE_2OPERANDS;
             move->code.retval = NJS_VMCODE_RETVAL;
             move->src = object->index;
-            move->dst = njs_generator_node_temp_index_get(parser, object);
+
+            index = njs_generator_node_temp_index_get(vm, parser, object);
+            if (nxt_slow_path(index == NJS_INDEX_ERROR)) {
+                return NXT_ERROR;
+            }
+
+            move->dst = index;
         }
 
         if (property->token == NJS_TOKEN_NAME) {
@@ -1334,7 +1395,13 @@ njs_generate_assignment(njs_vm_t *vm, nj
             move->code.operands = NJS_VMCODE_2OPERANDS;
             move->code.retval = NJS_VMCODE_RETVAL;
             move->src = property->index;
-            move->dst = njs_generator_node_temp_index_get(parser, property);
+
+            index = njs_generator_node_temp_index_get(vm, parser, property);
+            if (nxt_slow_path(index == NJS_INDEX_ERROR)) {
+                return NXT_ERROR;
+            }
+
+            move->dst = index;
         }
     }
 
@@ -1373,7 +1440,7 @@ njs_generate_operation_assignment(njs_vm
     lvalue = node->left;
 
     if (lvalue->token == NJS_TOKEN_NAME) {
-        ret = njs_generate_variable(parser, lvalue);
+        ret = njs_generate_variable(vm, parser, lvalue);
         if (nxt_slow_path(ret != NXT_OK)) {
             return ret;
         }
@@ -1390,7 +1457,11 @@ njs_generate_operation_assignment(njs_vm
             move->code.retval = NJS_VMCODE_RETVAL;
             move->src = lvalue->index;
 
-            index = njs_generator_temp_index_get(parser);
+            index = njs_generator_temp_index_get(vm, parser, expr);
+            if (nxt_slow_path(index == NJS_INDEX_ERROR)) {
+                return NXT_ERROR;
+            }
+
             move->dst = index;
         }
 
@@ -1439,11 +1510,16 @@ njs_generate_operation_assignment(njs_vm
         return ret;
     }
 
+    index = njs_generator_node_temp_index_get(vm, parser, node);
+    if (nxt_slow_path(index == NJS_INDEX_ERROR)) {
+        return NXT_ERROR;
+    }
+
     njs_generate_code(parser, njs_vmcode_prop_get_t, prop_get);
     prop_get->code.operation = njs_vmcode_property_get;
     prop_get->code.operands = NJS_VMCODE_3OPERANDS;
     prop_get->code.retval = NJS_VMCODE_RETVAL;
-    prop_get->value = njs_generator_node_temp_index_get(parser, node);
+    prop_get->value = index;
     prop_get->object = object->index;
     prop_get->property = property->index;
 
@@ -1484,7 +1560,10 @@ njs_generate_object(njs_vm_t *vm, njs_pa
 {
     njs_vmcode_object_t  *object;
 
-    node->index = njs_generator_object_dest_index(parser, node);
+    node->index = njs_generator_object_dest_index(vm, parser, node);
+    if (nxt_slow_path(node->index == NJS_INDEX_ERROR)) {
+        return NXT_ERROR;
+    }
 
     njs_generate_code(parser, njs_vmcode_object_t, object);
     object->code.operation = njs_vmcode_object;
@@ -1492,12 +1571,7 @@ njs_generate_object(njs_vm_t *vm, njs_pa
     object->code.retval = NJS_VMCODE_RETVAL;
     object->retval = node->index;
 
-    if (node->left == NULL) {
-        return NXT_OK;
-    }
-
     /* Initialize object. */
-
     return njs_generator(vm, parser, node->left);
 }
 
@@ -1507,7 +1581,10 @@ njs_generate_array(njs_vm_t *vm, njs_par
 {
     njs_vmcode_array_t  *array;
 
-    node->index = njs_generator_object_dest_index(parser, node);
+    node->index = njs_generator_object_dest_index(vm, parser, node);
+    if (nxt_slow_path(node->index == NJS_INDEX_ERROR)) {
+        return NXT_ERROR;
+    }
 
     njs_generate_code(parser, njs_vmcode_array_t, array);
     array->code.operation = njs_vmcode_array;
@@ -1534,18 +1611,24 @@ njs_generate_function(njs_vm_t *vm, njs_
 
     ret = njs_generate_function_scope(vm, lambda, node);
 
-    if (nxt_fast_path(ret == NXT_OK)) {
-        njs_generate_code(parser, njs_vmcode_function_t, function);
-        function->code.operation = njs_vmcode_function;
-        function->code.operands = NJS_VMCODE_1OPERAND;
-        function->code.retval = NJS_VMCODE_RETVAL;
-        function->lambda = lambda;
-
-        node->index = njs_generator_object_dest_index(parser, node);
-        function->retval = node->index;
+    if (nxt_slow_path(ret != NXT_OK)) {
+        return ret;
     }
 
-    return ret;
+    njs_generate_code(parser, njs_vmcode_function_t, function);
+    function->code.operation = njs_vmcode_function;
+    function->code.operands = NJS_VMCODE_1OPERAND;
+    function->code.retval = NJS_VMCODE_RETVAL;
+    function->lambda = lambda;
+
+    node->index = njs_generator_object_dest_index(vm, parser, node);
+    if (nxt_slow_path(node->index == NJS_INDEX_ERROR)) {
+        return NXT_ERROR;
+    }
+
+    function->retval = node->index;
+
+    return NXT_OK;
 }
 
 
@@ -1554,7 +1637,10 @@ njs_generate_regexp(njs_vm_t *vm, njs_pa
 {
     njs_vmcode_regexp_t  *regexp;
 
-    node->index = njs_generator_object_dest_index(parser, node);
+    node->index = njs_generator_object_dest_index(vm, parser, node);
+    if (nxt_slow_path(node->index == NJS_INDEX_ERROR)) {
+        return NXT_ERROR;
+    }
 
     njs_generate_code(parser, njs_vmcode_regexp_t, regexp);
     regexp->code.operation = njs_vmcode_regexp;
@@ -1624,6 +1710,7 @@ njs_generate_3addr_operation(njs_vm_t *v
     njs_parser_node_t *node)
 {
     nxt_int_t           ret;
+    njs_index_t         index;
     njs_parser_node_t   *left, *right;
     njs_vmcode_move_t   *move;
     njs_vmcode_3addr_t  *code;
@@ -1645,7 +1732,13 @@ njs_generate_3addr_operation(njs_vm_t *v
             move->code.operands = NJS_VMCODE_2OPERANDS;
             move->code.retval = NJS_VMCODE_RETVAL;
             move->src = left->index;
-            move->dst = njs_generator_node_temp_index_get(parser, left);
+
+            index = njs_generator_node_temp_index_get(vm, parser, left);
+            if (nxt_slow_path(index == NJS_INDEX_ERROR)) {
+                return NXT_ERROR;
+            }
+
+            move->dst = index;
         }
     }
 
@@ -1711,6 +1804,51 @@ njs_generate_2addr_operation(njs_vm_t *v
 
 
 static nxt_int_t
+njs_generate_typeof_operation(njs_vm_t *vm, njs_parser_t *parser,
+    njs_parser_node_t *node)
+{
+    nxt_int_t           ret;
+    njs_index_t         index;
+    njs_parser_node_t   *expr;
+    njs_vmcode_2addr_t  *code;
+
+    expr = node->left;
+
+    if (expr->token == NJS_TOKEN_NAME) {
+        index = njs_variable_index(vm, expr, NJS_NAME_TYPEOF);
+        if (nxt_slow_path(index == NJS_INDEX_ERROR)) {
+            return NXT_ERROR;
+        }
+
+        expr->index = index;
+
+    } else {
+        ret = njs_generator(vm, parser, node->left);
+        if (nxt_slow_path(ret != NXT_OK)) {
+            return ret;
+        }
+    }
+
+    njs_generate_code(parser, njs_vmcode_2addr_t, code);
+    code->code.operation = node->u.operation;
+    code->code.operands = NJS_VMCODE_2OPERANDS;
+    code->code.retval = NJS_VMCODE_RETVAL;
+    code->src = node->left->index;
+
+    node->index = njs_generator_dest_index(vm, parser, node);
+    if (nxt_slow_path(node->index == NJS_INDEX_ERROR)) {
+        return node->index;
+    }
+
+    code->dst = node->index;
+
+    nxt_thread_log_debug("CODE2  %p, %p", code->dst, code->src);
+
+    return NXT_OK;
+}
+
+
+static nxt_int_t
 njs_generate_inc_dec_operation(njs_vm_t *vm, njs_parser_t *parser,
     njs_parser_node_t *node, nxt_bool_t post)
 {
@@ -1725,7 +1863,7 @@ njs_generate_inc_dec_operation(njs_vm_t 
 
     if (lvalue->token == NJS_TOKEN_NAME) {
 
-        ret = njs_generate_variable(parser, lvalue);
+        ret = njs_generate_variable(vm, parser, lvalue);
         if (nxt_slow_path(ret != NXT_OK)) {
             return ret;
         }
@@ -1776,11 +1914,15 @@ njs_generate_inc_dec_operation(njs_vm_t 
         }
     }
 
-    dest_index = njs_generator_node_temp_index_get(parser, node);
+    dest_index = njs_generator_node_temp_index_get(vm, parser, node);
 
 found:
 
-    index = post ? njs_generator_temp_index_get(parser) : dest_index;
+    index = post ? njs_generator_temp_index_get(vm, parser, node) : dest_index;
+
+    if (nxt_slow_path(index == NJS_INDEX_ERROR)) {
+        return NXT_ERROR;
+    }
 
     njs_generate_code(parser, njs_vmcode_prop_get_t, prop_get);
     prop_get->code.operation = njs_vmcode_property_get;
@@ -1821,19 +1963,11 @@ static nxt_int_t
 njs_generate_function_declaration(njs_vm_t *vm, njs_parser_t *parser,
     njs_parser_node_t *node)
 {
-    nxt_int_t    ret;
-    njs_value_t  *value;
-
-    value = njs_variable_value(parser, node->index);
-
-    ret = njs_generate_function_scope(vm, value->data.u.function->u.lambda,
-                                      node);
-
-    if (nxt_fast_path(ret == NXT_OK)) {
-        node->u.value = *value;
-    }
-
-    return ret;
+    njs_function_lambda_t  *lambda;
+
+    lambda = node->u.value.data.u.function->u.lambda;
+
+    return njs_generate_function_scope(vm, lambda, node);
 }
 
 
@@ -1858,12 +1992,13 @@ njs_generate_function_scope(njs_vm_t *vm
 nxt_int_t
 njs_generate_scope(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node)
 {
-    u_char         *p;
-    size_t         code_size, size;
-    uintptr_t      scope_size;
-    nxt_uint_t     n;
-    njs_value_t    *value;
-    njs_vm_code_t  *code;
+    u_char              *p;
+    size_t              code_size, size;
+    uintptr_t           scope_size;
+    nxt_uint_t          n;
+    njs_value_t         *value;
+    njs_vm_code_t       *code;
+    njs_parser_scope_t  *scope;
 
     p = nxt_mem_cache_alloc(vm->mem_cache_pool, parser->code_size);
     if (nxt_slow_path(p == NULL)) {
@@ -1877,6 +2012,8 @@ njs_generate_scope(njs_vm_t *vm, njs_par
         return NXT_ERROR;
     }
 
+    scope = node->scope;
+
     code_size = parser->code_end - parser->code_start;
 
     nxt_thread_log_debug("SCOPE CODE SIZE: %uz %uz",
@@ -1887,8 +2024,11 @@ njs_generate_scope(njs_vm_t *vm, njs_par
         return NXT_ERROR;
     }
 
-    scope_size = parser->index[parser->scope - NJS_INDEX_CACHE]
-                 - parser->scope_offset;
+    scope_size = njs_offset(scope->next_index);
+
+    if (scope->type == NJS_SCOPE_GLOBAL) {
+        scope_size -= NJS_INDEX_GLOBAL_OFFSET;
+    }
 
     parser->local_scope = nxt_mem_cache_alloc(vm->mem_cache_pool, scope_size);
     if (nxt_slow_path(parser->local_scope == NULL)) {
@@ -1897,11 +2037,11 @@ njs_generate_scope(njs_vm_t *vm, njs_par
 
     parser->scope_size = scope_size;
 
-    size = parser->scope_values->items * sizeof(njs_value_t);
+    size = scope->values->items * sizeof(njs_value_t);
 
     nxt_thread_log_debug("SCOPE SIZE: %uz %uz", size, scope_size);
 
-    p = memcpy(parser->local_scope, parser->scope_values->start, size);
+    p = memcpy(parser->local_scope, scope->values->start, size);
     value = (njs_value_t *) (p + size);
 
     for (n = scope_size - size; n != 0; n -= sizeof(njs_value_t)) {
@@ -1963,7 +2103,7 @@ static nxt_int_t
 njs_generate_function_call(njs_vm_t *vm, njs_parser_t *parser,
     njs_parser_node_t *node)
 {
-    nxt_int_t                    ret;
+    njs_ret_t                    ret;
     njs_parser_node_t            *name;
     njs_vmcode_function_frame_t  *func;
 
@@ -1977,8 +2117,10 @@ njs_generate_function_call(njs_vm_t *vm,
         name = node->left;
 
     } else {
-        /* njs_generate_variable() always returns NXT_OK. */
-        (void) njs_generate_variable(parser, node);
+        ret = njs_generate_variable(vm, parser, node);
+        if (nxt_slow_path(ret != NXT_OK)) {
+            return ret;
+        }
         name = node;
     }
 
@@ -2100,7 +2242,7 @@ njs_generate_try_statement(njs_vm_t *vm,
     njs_parser_node_t *node)
 {
     nxt_int_t               ret;
-    njs_index_t             index;
+    njs_index_t             index, catch_index;
     njs_vmcode_catch_t      *catch;
     njs_vmcode_finally_t    *finally;
     njs_vmcode_try_end_t    *try_end, *catch_end;
@@ -2111,7 +2253,11 @@ njs_generate_try_statement(njs_vm_t *vm,
     try_start->code.operands = NJS_VMCODE_2OPERANDS;
     try_start->code.retval = NJS_VMCODE_NO_RETVAL;
 
-    index = njs_generator_temp_index_get(parser);
+    index = njs_generator_temp_index_get(vm, parser, node);
+    if (nxt_slow_path(index == NJS_INDEX_ERROR)) {
+        return NXT_ERROR;
+    }
+
     try_start->value = index;
 
     ret = njs_generator(vm, parser, node->left);
@@ -2131,9 +2277,9 @@ njs_generate_try_statement(njs_vm_t *vm,
     if (node->token == NJS_TOKEN_CATCH) {
         /* A "try/catch" case. */
 
-        ret = njs_generator(vm, parser, node->left);
-        if (nxt_slow_path(ret != NXT_OK)) {
-            return ret;
+        catch_index = njs_variable_index(vm, node->left, NJS_NAME_DECLARATION);
+        if (nxt_slow_path(catch_index == NJS_INDEX_ERROR)) {
+            return NXT_ERROR;
         }
 
         njs_generate_code(parser, njs_vmcode_catch_t, catch);
@@ -2141,7 +2287,7 @@ njs_generate_try_statement(njs_vm_t *vm,
         catch->code.operands = NJS_VMCODE_2OPERANDS;
         catch->code.retval = NJS_VMCODE_NO_RETVAL;
         catch->offset = sizeof(njs_vmcode_catch_t);
-        catch->exception = node->left->index;
+        catch->exception = catch_index;
 
         ret = njs_generator(vm, parser, node->right);
         if (nxt_slow_path(ret != NXT_OK)) {
@@ -2156,16 +2302,17 @@ njs_generate_try_statement(njs_vm_t *vm,
         if (node->left != NULL) {
             /* A try/catch/finally case. */
 
-            ret = njs_generator(vm, parser, node->left->left);
-            if (nxt_slow_path(ret != NXT_OK)) {
-                return ret;
+            catch_index = njs_variable_index(vm, node->left->left,
+                                             NJS_NAME_DECLARATION);
+            if (nxt_slow_path(catch_index == NJS_INDEX_ERROR)) {
+                return NXT_ERROR;
             }
 
             njs_generate_code(parser, njs_vmcode_catch_t, catch);
             catch->code.operation = njs_vmcode_catch;
             catch->code.operands = NJS_VMCODE_2OPERANDS;
             catch->code.retval = NJS_VMCODE_NO_RETVAL;
-            catch->exception = node->left->left->index;
+            catch->exception = catch_index;
 
             ret = njs_generator(vm, parser, node->left->right);
             if (nxt_slow_path(ret != NXT_OK)) {
@@ -2260,12 +2407,13 @@ njs_generator_dest_index(njs_vm_t *vm, n
         return dest->index;
     }
 
-    return njs_generator_node_temp_index_get(parser, node);
+    return njs_generator_node_temp_index_get(vm, parser, node);
 }
 
 
 static nxt_noinline njs_index_t
-njs_generator_object_dest_index(njs_parser_t *parser, njs_parser_node_t *node)
+njs_generator_object_dest_index(njs_vm_t *vm, njs_parser_t *parser,
+    njs_parser_node_t *node)
 {
     njs_index_t        index;
     njs_parser_node_t  *dest;
@@ -2286,27 +2434,30 @@ njs_generator_object_dest_index(njs_pars
         }
     }
 
-    return njs_generator_node_temp_index_get(parser, node);
+    return njs_generator_node_temp_index_get(vm, parser, node);
 }
 
 
 static njs_index_t
-njs_generator_node_temp_index_get(njs_parser_t *parser, njs_parser_node_t *node)
+njs_generator_node_temp_index_get(njs_vm_t *vm, njs_parser_t *parser,
+    njs_parser_node_t *node)
 {
     node->temporary = 1;
 
-    node->index = njs_generator_temp_index_get(parser);
+    node->index = njs_generator_temp_index_get(vm, parser, node);
 
     return node->index;
 }
 
 
 static nxt_noinline njs_index_t
-njs_generator_temp_index_get(njs_parser_t *parser)
+njs_generator_temp_index_get(njs_vm_t *vm, njs_parser_t *parser,
+    njs_parser_node_t *node)
 {
-    nxt_uint_t   n;
-    njs_index_t  index, *last;
-    nxt_array_t  *cache;
+    nxt_array_t         *cache;
+    njs_value_t         *value;
+    njs_index_t         index, *last;
+    njs_parser_scope_t  *scope;
 
     cache = parser->index_cache;
 
@@ -2318,15 +2469,22 @@ njs_generator_temp_index_get(njs_parser_
         return *last;
     }
 
-    /* Skip absolute and propery scopes. */
-    n = parser->scope - NJS_INDEX_CACHE;
-
-    index = parser->index[n];
-    parser->index[n] += sizeof(njs_value_t);
-
-    index |= parser->scope;
-
-    nxt_thread_log_debug("GET %p", index);
+    scope = node->scope;
+
+    while (scope->type == NJS_SCOPE_BLOCK) {
+         scope = scope->parent;
+    }
+
+    value = nxt_array_add(scope->values, &njs_array_mem_proto,
+                          vm->mem_cache_pool);
+    if (nxt_slow_path(value == NULL)) {
+        return NJS_INDEX_ERROR;
+    }
+
+    *value = njs_value_invalid;
+
+    index = scope->next_index;
+    scope->next_index += sizeof(njs_value_t);
 
     return index;
 }
@@ -2389,11 +2547,3 @@ njs_generator_index_release(njs_vm_t *vm
 
     return NXT_ERROR;
 }
-
-
-nxt_inline nxt_bool_t
-njs_generator_is_constant(njs_parser_node_t *node)
-{
-    return (node->token >= NJS_TOKEN_FIRST_CONST
-            && node->token <= NJS_TOKEN_LAST_CONST);
-}
diff -r 2d9ccf739861 -r 4337ed48d6d6 njs/njs_parser.c
--- a/njs/njs_parser.c	Sun Jan 01 20:45:59 2017 +0300
+++ b/njs/njs_parser.c	Mon Jan 02 22:59:24 2017 +0300
@@ -38,11 +38,15 @@
  * is treated as a single expiression.
  */
 
+static njs_ret_t njs_parser_scope_begin(njs_vm_t *vm, njs_parser_t *parser,
+    njs_scope_t type);
+static void njs_parser_scope_end(njs_vm_t *vm, njs_parser_t *parser);
 static njs_token_t njs_parser_statement_chain(njs_vm_t *vm,
     njs_parser_t *parser, njs_token_t token);
 static njs_token_t njs_parser_statement(njs_vm_t *vm, njs_parser_t *parser,
     njs_token_t token);
-static njs_token_t njs_parser_block(njs_vm_t *vm, njs_parser_t *parser);
+static njs_token_t njs_parser_block_statement(njs_vm_t *vm,
+    njs_parser_t *parser);
 static njs_token_t njs_parser_function_declaration(njs_vm_t *vm,
     njs_parser_t *parser);
 static njs_parser_t *njs_parser_function_create(njs_vm_t *vm,
@@ -89,9 +93,15 @@ static njs_token_t njs_parser_unexpected
 njs_parser_node_t *
 njs_parser(njs_vm_t *vm, njs_parser_t *parser)
 {
+    njs_ret_t          ret;
     njs_token_t        token;
     njs_parser_node_t  *node;
 
+    ret = njs_parser_scope_begin(vm, parser, NJS_SCOPE_GLOBAL);
+    if (nxt_slow_path(ret != NXT_OK)) {
+        return NULL;
+    }
+
     token = njs_parser_token(parser);
 
     while (token != NJS_TOKEN_END) {
@@ -112,6 +122,7 @@ njs_parser(njs_vm_t *vm, njs_parser_t *p
     if (node != NULL && node->right != NULL) {
         if (node->right->token == NJS_TOKEN_FUNCTION) {
             node->token = NJS_TOKEN_CALL;
+            node->scope = parser->scope;
             return node;
         }
 
@@ -125,11 +136,83 @@ njs_parser(njs_vm_t *vm, njs_parser_t *p
     }
 
     node->token = NJS_TOKEN_END;
+    node->scope = parser->scope;
 
     return node;
 }
 
 
+static njs_ret_t
+njs_parser_scope_begin(njs_vm_t *vm, njs_parser_t *parser, njs_scope_t type)
+{
+    nxt_array_t         *values;
+    njs_parser_scope_t  *scope, *parent;
+
+    scope = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_parser_scope_t));
+    if (nxt_slow_path(scope == NULL)) {
+        return NXT_ERROR;
+    }
+
+    scope->type = type;
+
+    if (type == NJS_SCOPE_GLOBAL) {
+        type += NJS_INDEX_GLOBAL_OFFSET;
+    }
+
+    scope->next_index = type;
+
+    scope->inclusive = 0;
+    nxt_lvlhsh_init(&scope->variables);
+
+    values = NULL;
+
+    if (scope->type < NJS_SCOPE_BLOCK) {
+        values = nxt_array_create(4, sizeof(njs_value_t), &njs_array_mem_proto,
+                                  vm->mem_cache_pool);
+        if (nxt_slow_path(values == NULL)) {
+            return NXT_ERROR;
+        }
+    }
+
+    scope->values = values;
+
+    parent = parser->scope;
+
+    if (parent != NULL) {
+        parent->inclusive++;
+    }
+
+    scope->parent = parent;
+    parser->scope = scope;
+
+    return NXT_OK;
+}
+
+
+static void
+njs_parser_scope_end(njs_vm_t *vm, njs_parser_t *parser)
+{
+    njs_parser_scope_t  *scope, *parent;
+
+    scope = parser->scope;
+
+    parent = scope->parent;
+
+#if 0
+    if (scope->inclusive == 0
+        && scope->type == NJS_SCOPE_BLOCK
+        && nxt_lvlhsh_is_empty(&scope->variables))
+    {
+        parent->inclusive--;
+
+        nxt_mem_cache_free(vm->mem_cache_pool, scope);
+    }
+#endif
+
+    parser->scope = parent;
+}
+
+
 static njs_token_t
 njs_parser_statement_chain(njs_vm_t *vm, njs_parser_t *parser,
     njs_token_t token)
@@ -213,7 +296,7 @@ njs_parser_statement(njs_vm_t *vm, njs_p
         return njs_parser_token(parser);
 
     case NJS_TOKEN_OPEN_BRACE:
-        return njs_parser_block(vm, parser);
+        return njs_parser_block_statement(vm, parser);
 
     case NJS_TOKEN_CLOSE_BRACE:
         parser->node = NULL;
@@ -251,8 +334,9 @@ njs_parser_statement(njs_vm_t *vm, njs_p
 
 
 static njs_token_t


More information about the nginx-devel mailing list