From: Igor Sysoev Date: Fri, 30 Sep 2016 19:07:07 +0000 (+0300) Subject: Inclusive "new" operators and "new" operator calls without X-Git-Tag: 0.1.3~4 X-Git-Url: http://git.kaiwu.me/sitemap.xml?a=commitdiff_plain;h=c93ec1767e514efe2ca9622b9aa45072ea2e5bd0;p=njs.git Inclusive "new" operators and "new" operator calls without parenthesis are supported. --- diff --git a/njs/njs_parser_expression.c b/njs/njs_parser_expression.c index eebfa228..6e61e277 100644 --- a/njs/njs_parser_expression.c +++ b/njs/njs_parser_expression.c @@ -70,6 +70,8 @@ static njs_token_t njs_parser_post_inc_dec_expression(njs_vm_t *vm, 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, njs_parser_t *parser, 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, njs_parser_t *parser, + 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, njs_parser_t *parser, 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, njs_parser_t *parser, 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; @@ -1001,6 +991,101 @@ njs_parser_call_expression(njs_vm_t *vm, njs_parser_t *parser, } +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 --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c index a34fe5e7..4adf174b 100644 --- a/njs/test/njs_unit_test.c +++ b/njs/test/njs_unit_test.c @@ -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") },