[njs] For and for-in loops support variable declaration.

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


details:   http://hg.nginx.org/njs/rev/6c5bebb914ef
branches:  
changeset: 294:6c5bebb914ef
user:      Igor Sysoev <igor at sysoev.ru>
date:      Mon Jan 02 22:59:29 2017 +0300
description:
For and for-in loops support variable declaration.

diffstat:

 njs/njs_parser.c         |  218 +++++++++++++++++++++++++++++++++++++++++-----
 njs/test/njs_unit_test.c |   13 ++
 2 files changed, 205 insertions(+), 26 deletions(-)

diffs (272 lines):

diff -r 4337ed48d6d6 -r 6c5bebb914ef njs/njs_parser.c
--- a/njs/njs_parser.c	Mon Jan 02 22:59:24 2017 +0300
+++ b/njs/njs_parser.c	Mon Jan 02 22:59:29 2017 +0300
@@ -64,6 +64,10 @@ static njs_token_t njs_parser_while_stat
 static njs_token_t njs_parser_do_while_statement(njs_vm_t *vm,
     njs_parser_t *parser);
 static njs_token_t njs_parser_for_statement(njs_vm_t *vm, njs_parser_t *parser);
+static njs_token_t njs_parser_for_var_statement(njs_vm_t *vm,
+    njs_parser_t *parser);
+static njs_token_t njs_parser_for_var_in_statement(njs_vm_t *vm,
+    njs_parser_t *parser, njs_parser_node_t *name);
 static njs_token_t njs_parser_for_in_statement(njs_vm_t *vm,
     njs_parser_t *parser, nxt_str_t *name, njs_token_t token);
 static njs_token_t njs_parser_continue_statement(njs_vm_t *vm,
@@ -1122,17 +1126,34 @@ njs_parser_for_statement(njs_vm_t *vm, n
     }
 
     if (token != NJS_TOKEN_SEMICOLON) {
-        name = parser->lexer->text;
-
-        token = njs_parser_expression(vm, parser, token);
-        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
-            return token;
-        }
-
-        init = parser->node;
-
-        if (init->token == NJS_TOKEN_IN) {
-            return njs_parser_for_in_statement(vm, parser, &name, token);
+
+        if (token == NJS_TOKEN_VAR) {
+
+            token = njs_parser_for_var_statement(vm, parser);
+            if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+                return token;
+            }
+
+            init = parser->node;
+
+            if (init->token == NJS_TOKEN_FOR_IN) {
+                return token;
+            }
+
+        } else {
+
+            name = parser->lexer->text;
+
+            token = njs_parser_expression(vm, parser, token);
+            if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+                return token;
+            }
+
+            init = parser->node;
+
+            if (init->token == NJS_TOKEN_IN) {
+                return njs_parser_for_in_statement(vm, parser, &name, token);
+            }
         }
     }
 
@@ -1148,21 +1169,21 @@ njs_parser_for_statement(njs_vm_t *vm, n
             return token;
         }
 
-        condition = parser->node;
-    }
-
-    token = njs_parser_match(vm, parser, token, NJS_TOKEN_SEMICOLON);
-    if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
-        return token;
-    }
-
-    if (token != NJS_TOKEN_CLOSE_PARENTHESIS) {
-
-        token = njs_parser_expression(vm, parser, token);
-        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
-            return token;
-        }
-
+        condition = parser->node;
+    }
+
+    token = njs_parser_match(vm, parser, token, NJS_TOKEN_SEMICOLON);
+    if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+        return token;
+    }
+
+    if (token != NJS_TOKEN_CLOSE_PARENTHESIS) {
+
+        token = njs_parser_expression(vm, parser, token);
+        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+            return token;
+        }
+
         update = parser->node;
     }
 
@@ -1209,6 +1230,151 @@ njs_parser_for_statement(njs_vm_t *vm, n
 
 
 static njs_token_t
+njs_parser_for_var_statement(njs_vm_t *vm, njs_parser_t *parser)
+{
+    njs_ret_t          ret;
+    njs_token_t        token;
+    njs_variable_t     *var;
+    njs_parser_node_t  *left, *stmt, *name, *assign, *expr;
+
+    parser->node = NULL;
+    left = NULL;
+
+    do {
+        token = njs_parser_token(parser);
+        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+            return token;
+        }
+
+        if (token != NJS_TOKEN_NAME) {
+            return NJS_TOKEN_ILLEGAL;
+        }
+
+        var = njs_variable_add(vm, parser, NJS_VARIABLE_VAR);
+        if (nxt_slow_path(var == NULL)) {
+            return NJS_TOKEN_ERROR;
+        }
+
+        name = njs_parser_node_alloc(vm);
+        if (nxt_slow_path(name == NULL)) {
+            return NJS_TOKEN_ERROR;
+        }
+
+        name->token = NJS_TOKEN_NAME;
+
+        ret = njs_variable_reference(vm, parser, name);
+        if (nxt_slow_path(ret != NXT_OK)) {
+            return NJS_TOKEN_ERROR;
+        }
+
+        token = njs_parser_token(parser);
+        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+            return token;
+        }
+
+        if (token == NJS_TOKEN_IN) {
+            return njs_parser_for_var_in_statement(vm, parser, name);
+        }
+
+        expr = NULL;
+
+        if (token == NJS_TOKEN_ASSIGNMENT) {
+
+            token = njs_parser_token(parser);
+            if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+                return token;
+            }
+
+            token = njs_parser_var_expression(vm, parser, token);
+            if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+                return token;
+            }
+
+            expr = parser->node;
+        }
+
+        assign = njs_parser_node_alloc(vm);
+        if (nxt_slow_path(assign == NULL)) {
+            return NJS_TOKEN_ERROR;
+        }
+
+        assign->token = NJS_TOKEN_VAR;
+        assign->u.operation = njs_vmcode_move;
+        assign->left = name;
+        assign->right = expr;
+
+        stmt = njs_parser_node_alloc(vm);
+        if (nxt_slow_path(stmt == NULL)) {
+            return NJS_TOKEN_ERROR;
+        }
+
+        stmt->token = NJS_TOKEN_STATEMENT;
+        stmt->left = left;
+        stmt->right = assign;
+        parser->node = stmt;
+        parser->code_size += sizeof(njs_vmcode_2addr_t);
+
+        left = stmt;
+
+    } while (token == NJS_TOKEN_COMMA);
+
+    return token;
+}
+
+
+static njs_token_t
+njs_parser_for_var_in_statement(njs_vm_t *vm, njs_parser_t *parser,
+    njs_parser_node_t *name)
+{
+    njs_token_t        token;
+    njs_parser_node_t  *node, *foreach;
+
+    token = njs_parser_token(parser);
+    if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+        return token;
+    }
+
+    token = njs_parser_expression(vm, parser, token);
+    if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+        return token;
+    }
+
+    node = njs_parser_node_alloc(vm);
+    if (nxt_slow_path(node == NULL)) {
+        return NJS_TOKEN_ERROR;
+    }
+
+    node->token = NJS_TOKEN_IN;
+    node->left = name;
+    node->right = parser->node;
+
+    token = njs_parser_match(vm, parser, token, NJS_TOKEN_CLOSE_PARENTHESIS);
+    if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+        return token;
+    }
+
+    token = njs_parser_statement(vm, parser, token);
+    if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+        return token;
+    }
+
+    foreach = njs_parser_node_alloc(vm);
+    if (nxt_slow_path(foreach == NULL)) {
+        return NJS_TOKEN_ERROR;
+    }
+
+    foreach->token = NJS_TOKEN_FOR_IN;
+    foreach->left = node;
+    foreach->right = parser->node;
+
+    parser->node = foreach;
+    parser->code_size += sizeof(njs_vmcode_prop_foreach_t)
+                         + sizeof(njs_vmcode_prop_next_t);
+    return token;
+}
+
+
+static njs_token_t
 njs_parser_for_in_statement(njs_vm_t *vm, njs_parser_t *parser, nxt_str_t *name,
     njs_token_t token)
 {
diff -r 4337ed48d6d6 -r 6c5bebb914ef njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c	Mon Jan 02 22:59:24 2017 +0300
+++ b/njs/test/njs_unit_test.c	Mon Jan 02 22:59:29 2017 +0300
@@ -4506,6 +4506,19 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("function f(a) { return a } var a = '2'; a + f(5)"),
       nxt_string("25") },
 
+    { nxt_string("for (var i = 0; i < 5; i++); i"),
+      nxt_string("5") },
+
+    { nxt_string("for (var i = 0, j; i < 5; i++); j"),
+      nxt_string("undefined") },
+
+    { nxt_string("for (var i = 0, j, k = 3; i < 5; i++); k"),
+      nxt_string("3") },
+
+    { nxt_string("var o = { a: 1, b: 2, c: 3 }, s = ''; "
+                 "for (var i in o) { s += i }; s"),
+      nxt_string("abc") },
+
     /* RegExp. */
 
     { nxt_string("/./x"),


More information about the nginx-devel mailing list