[njs] Inclusive "new" operators and "new" operator calls without

Igor Sysoev igor at sysoev.ru
Mon Oct 3 10:33:37 UTC 2016


details:   http://hg.nginx.org/njs/rev/8c2cea409034
branches:  
changeset: 187:8c2cea409034
user:      Igor Sysoev <igor at sysoev.ru>
date:      Fri Sep 30 22:07:07 2016 +0300
description:
Inclusive "new" operators and "new" operator calls without
parenthesis are supported.

diffstat:

 njs/njs_parser_expression.c |  135 +++++++++++++++++++++++++++++++++++--------
 njs/test/njs_unit_test.c    |  101 ++++++++++++++++++++++++++++++++
 2 files changed, 211 insertions(+), 25 deletions(-)

diffs (378 lines):

diff -r b3e83fa52345 -r 8c2cea409034 njs/njs_parser_expression.c
--- a/njs/njs_parser_expression.c	Fri Sep 30 14:11:27 2016 +0300
+++ b/njs/njs_parser_expression.c	Fri Sep 30 22:07:07 2016 +0300
@@ -70,6 +70,8 @@ static njs_token_t njs_parser_post_inc_d
     njs_parser_t *parser, njs_token_t token);
 static njs_token_t njs_parser_call_expression(njs_vm_t *vm,
     njs_parser_t *parser, njs_token_t token);
+static njs_token_t njs_parser_new_expression(njs_vm_t *vm,
+    njs_parser_t *parser, njs_token_t token);
 static njs_token_t njs_parser_property_expression(njs_vm_t *vm,
     njs_parser_t *parser, njs_token_t token);
 static njs_token_t njs_parser_property_brackets(njs_vm_t *vm,
@@ -894,27 +896,20 @@ static njs_token_t
 njs_parser_call_expression(njs_vm_t *vm, njs_parser_t *parser,
     njs_token_t token)
 {
-    nxt_bool_t         ctor;
     njs_parser_node_t  *func, *node;
 
-    ctor = 0;
-
     if (token == NJS_TOKEN_NEW) {
-        token = njs_parser_token(parser);
-        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
-            return token;
-        }
+        token = njs_parser_new_expression(vm, parser, token);
 
-        ctor = 1;
+    } else {
+        token = njs_parser_terminal(vm, parser, token);
     }
 
-    token = njs_parser_terminal(vm, parser, token);
     if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
         return token;
     }
 
     for ( ;; ) {
-
         token = njs_parser_property_expression(vm, parser, token);
         if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
             return token;
@@ -923,8 +918,6 @@ njs_parser_call_expression(njs_vm_t *vm,
         node = parser->node;
 
         if (token != NJS_TOKEN_OPEN_PARENTHESIS) {
-            /* TODO: var o = new Object; */
-            node->ctor = ctor;
             return token;
         }
 
@@ -937,19 +930,6 @@ njs_parser_call_expression(njs_vm_t *vm,
                                  + sizeof(njs_vmcode_function_call_t);
             break;
 
-        case NJS_TOKEN_FUNCTION_EXPRESSION:
-            func = njs_parser_node_alloc(vm);
-            if (nxt_slow_path(func == NULL)) {
-                return NJS_TOKEN_ERROR;
-            }
-
-            func->token = NJS_TOKEN_FUNCTION_CALL;
-            func->left = node;
-            func->index = node->index;
-            parser->code_size += sizeof(njs_vmcode_function_frame_t)
-                                 + sizeof(njs_vmcode_function_call_t);
-            break;
-
         case NJS_TOKEN_PROPERTY:
             func = njs_parser_node_alloc(vm);
             if (nxt_slow_path(func == NULL)) {
@@ -964,6 +944,9 @@ njs_parser_call_expression(njs_vm_t *vm,
 
         default:
             /*
+             * NJS_TOKEN_METHOD_CALL,
+             * NJS_TOKEN_FUNCTION_CALL,
+             * NJS_TOKEN_FUNCTION_EXPRESSION,
              * NJS_TOKEN_OPEN_PARENTHESIS,
              * NJS_TOKEN_OBJECT_CONSTRUCTOR,
              * NJS_TOKEN_ARRAY_CONSTRUCTOR,
@@ -986,6 +969,13 @@ njs_parser_call_expression(njs_vm_t *vm,
             break;
         }
 
+        func->ctor = 0;
+
+        if (token != NJS_TOKEN_OPEN_PARENTHESIS) {
+            parser->node = func;
+            return token;
+        }
+
         token = njs_parser_arguments(vm, parser, func);
         if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
             return token;
@@ -1002,6 +992,101 @@ njs_parser_call_expression(njs_vm_t *vm,
 
 
 static njs_token_t
+njs_parser_new_expression(njs_vm_t *vm, njs_parser_t *parser,
+    njs_token_t token)
+{
+    njs_parser_node_t  *func, *node;
+
+    token = njs_parser_token(parser);
+    if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+        return token;
+    }
+
+    if (token == NJS_TOKEN_NEW) {
+        token = njs_parser_new_expression(vm, parser, token);
+
+    } else {
+        token = njs_parser_terminal(vm, parser, token);
+        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+            return token;
+        }
+
+        token = njs_parser_property_expression(vm, parser, token);
+    }
+
+    if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+        return token;
+    }
+
+    node = parser->node;
+
+    switch (node->token) {
+
+    case NJS_TOKEN_NAME:
+        func = node;
+        func->token = NJS_TOKEN_FUNCTION_CALL;
+        parser->code_size += sizeof(njs_vmcode_function_frame_t)
+                             + sizeof(njs_vmcode_function_call_t);
+        break;
+
+    case NJS_TOKEN_PROPERTY:
+        func = njs_parser_node_alloc(vm);
+        if (nxt_slow_path(func == NULL)) {
+            return NJS_TOKEN_ERROR;
+        }
+
+        func->token = NJS_TOKEN_METHOD_CALL;
+        func->left = node;
+        parser->code_size += sizeof(njs_vmcode_method_frame_t)
+                             + sizeof(njs_vmcode_function_call_t);
+        break;
+
+    default:
+        /*
+         * NJS_TOKEN_METHOD_CALL,
+         * NJS_TOKEN_FUNCTION_CALL,
+         * NJS_TOKEN_FUNCTION_EXPRESSION,
+         * NJS_TOKEN_OPEN_PARENTHESIS,
+         * NJS_TOKEN_OBJECT_CONSTRUCTOR,
+         * NJS_TOKEN_ARRAY_CONSTRUCTOR,
+         * NJS_TOKEN_BOOLEAN_CONSTRUCTOR,
+         * NJS_TOKEN_NUMBER_CONSTRUCTOR,
+         * NJS_TOKEN_STRING_CONSTRUCTOR,
+         * NJS_TOKEN_FUNCTION_CONSTRUCTOR,
+         * NJS_TOKEN_REGEXP_CONSTRUCTOR,
+         * NJS_TOKEN_EVAL.
+         */
+        func = njs_parser_node_alloc(vm);
+        if (nxt_slow_path(func == NULL)) {
+            return NJS_TOKEN_ERROR;
+        }
+
+        func->token = NJS_TOKEN_FUNCTION_CALL;
+        func->left = node;
+        parser->code_size += sizeof(njs_vmcode_function_frame_t)
+                             + sizeof(njs_vmcode_function_call_t);
+        break;
+    }
+
+    func->ctor = 1;
+
+    if (token != NJS_TOKEN_OPEN_PARENTHESIS) {
+        parser->node = func;
+        return token;
+    }
+
+    token = njs_parser_arguments(vm, parser, func);
+    if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+        return token;
+    }
+
+    parser->node = func;
+
+    return njs_parser_token(parser);
+}
+
+
+static njs_token_t
 njs_parser_property_expression(njs_vm_t *vm, njs_parser_t *parser,
     njs_token_t token)
 {
diff -r b3e83fa52345 -r 8c2cea409034 njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c	Fri Sep 30 14:11:27 2016 +0300
+++ b/njs/test/njs_unit_test.c	Fri Sep 30 22:07:07 2016 +0300
@@ -3631,6 +3631,9 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("(function(x) { return x + 1 }(2))"),
       nxt_string("3") },
 
+    { nxt_string("a = function() { return 1 }(); a"),
+      nxt_string("1") },
+
     { nxt_string("a = (function() { return 1 })(); a"),
       nxt_string("1") },
 
@@ -3777,6 +3780,12 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("function f() {}; f = f + 1; f"),
       nxt_string("[object Function]1") },
 
+    { nxt_string("function a() { return 1 }"
+                 "function b() { return a }"
+                 "function c() { return b }"
+                 "c()()()"),
+      nxt_string("1") },
+
 #if 0
     { nxt_string("function f() {}; f += 1; f"),
       nxt_string("[object Function]1") },
@@ -3884,6 +3893,56 @@ static njs_unit_test_t  njs_test[] =
                  "o.constructor === F"),
       nxt_string("true") },
 
+    { nxt_string("function F() { return Number }"
+                 "var o = new (F())(5);"
+                 "typeof o +' '+ o"),
+      nxt_string("object 5") },
+
+    { nxt_string("function F() { return Number }"
+                 "var o = new (F());"
+                 "typeof o +' '+ o"),
+      nxt_string("object 0") },
+
+    { nxt_string("var o = new function F() { return Number }()(5);"
+                 "typeof o +' '+ o"),
+      nxt_string("number 5") },
+
+    { nxt_string("var o = new (function F() { return Number }())(5);"
+                 "typeof o +' '+ o"),
+      nxt_string("object 5") },
+
+    { nxt_string("var o = new (new function F() { return Number }())(5);"
+                 "typeof o +' '+ o"),
+      nxt_string("object 5") },
+
+    { nxt_string("var o = new new function F() { return Number }()(5);"
+                 "typeof o +' '+ o"),
+      nxt_string("object 5") },
+
+    { nxt_string("var b; function F(x) { return {a:x} }"
+                 "function G(y) { b = y; return F }"
+                 "var o = new G(3)(5);"
+                 "b + ' ' + o.a"),
+      nxt_string("3 5") },
+
+    { nxt_string("var b; function F(x) { return {a:x} }"
+                 "function G(y) { b = y; return F }"
+                 "var o = new (new G(3))(5);"
+                 "b + ' ' + o.a"),
+      nxt_string("3 5") },
+
+    { nxt_string("var b; function F(x) { return {a:x} }"
+                 "function G(y) { b = y; return F }"
+                 "var o = new new G(3)(5);"
+                 "b + ' ' + o.a"),
+      nxt_string("3 5") },
+
+    { nxt_string("var b; function F(x) { return {a:x} }"
+                 "var g = { G: function (y) { b = y; return F } };"
+                 "var o = new new g.G(3)(5);"
+                 "b + ' ' + o.a"),
+      nxt_string("3 5") },
+
     { nxt_string("function a() { return function(x) { return x + 1 } }"
                  "b = a(); b(2)"),
       nxt_string("3") },
@@ -4282,6 +4341,12 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("Boolean()"),
       nxt_string("false") },
 
+    { nxt_string("new Boolean()"),
+      nxt_string("false") },
+
+    { nxt_string("new Boolean"),
+      nxt_string("false") },
+
     { nxt_string("Boolean(0)"),
       nxt_string("false") },
 
@@ -4306,6 +4371,9 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("typeof new Boolean(1)"),
       nxt_string("object") },
 
+    { nxt_string("typeof new Boolean"),
+      nxt_string("object") },
+
     { nxt_string("Boolean.name"),
       nxt_string("Boolean") },
 
@@ -4345,6 +4413,12 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("Number()"),
       nxt_string("0") },
 
+    { nxt_string("new Number()"),
+      nxt_string("0") },
+
+    { nxt_string("new Number"),
+      nxt_string("0") },
+
     { nxt_string("Number(123)"),
       nxt_string("123") },
 
@@ -4365,6 +4439,9 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("typeof new Number(1)"),
       nxt_string("object") },
 
+    { nxt_string("typeof new Number"),
+      nxt_string("object") },
+
     { nxt_string("Number.name"),
       nxt_string("Number") },
 
@@ -4401,12 +4478,24 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("String()"),
       nxt_string("") },
 
+    { nxt_string("new String()"),
+      nxt_string("") },
+
+    { nxt_string("new String"),
+      nxt_string("") },
+
     { nxt_string("String(123)"),
       nxt_string("123") },
 
     { nxt_string("new String(123)"),
       nxt_string("123") },
 
+    { nxt_string("new String(123).length"),
+      nxt_string("3") },
+
+    { nxt_string("new String(123).toString()"),
+      nxt_string("123") },
+
     { nxt_string("String([1,2,3])"),
       nxt_string("1,2,3") },
 
@@ -4427,6 +4516,9 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("typeof new String('abc')"),
       nxt_string("object") },
 
+    { nxt_string("typeof new String"),
+      nxt_string("object") },
+
     { nxt_string("String.name"),
       nxt_string("String") },
 
@@ -4926,6 +5018,15 @@ static njs_unit_test_t  njs_test[] =
                  "Date.prototype.toJSON.call(o, 1)"),
       nxt_string("OK") },
 
+    { nxt_string("var d = new Date; d.__proto__"),
+      nxt_string("Invalid Date") },
+
+    { nxt_string("var d = new Date(); d.__proto__"),
+      nxt_string("Invalid Date") },
+
+    { nxt_string("var d = new Date(); d.__proto__ === Date.prototype"),
+      nxt_string("true") },
+
     { nxt_string("Date.name"),
       nxt_string("Date") },
 



More information about the nginx-devel mailing list