[njs] Added arrow function support.
Dmitry Volyntsev
xeioex at nginx.com
Fri Apr 12 16:58:15 UTC 2019
details: https://hg.nginx.org/njs/rev/d7a0eb59a7e7
branches:
changeset: 888:d7a0eb59a7e7
user: hongzhidao <hongzhidao at gmail.com>
date: Sun Apr 07 14:26:13 2019 +0800
description:
Added arrow function support.
This closes #106 issue on Github.
In collaboration with Artem S. Povalyukhin.
diffstat:
njs/njs_builtin.c | 6 +
njs/njs_extern.c | 3 +-
njs/njs_function.c | 27 ++++++-
njs/njs_function.h | 2 +
njs/njs_lexer.c | 1 +
njs/njs_lexer.h | 1 +
njs/njs_object.c | 7 +-
njs/njs_parser.c | 166 +++++++++++++++++++++++++++++++++++++++++++
njs/njs_parser.h | 11 ++-
njs/njs_parser_terminal.c | 36 ++++-----
njs/njs_vm.h | 1 +
njs/test/njs_expect_test.exp | 2 +
njs/test/njs_unit_test.c | 144 +++++++++++++++++++++++++++++++++++++
13 files changed, 381 insertions(+), 26 deletions(-)
diffs (633 lines):
diff -r 070b635928a9 -r d7a0eb59a7e7 njs/njs_builtin.c
--- a/njs/njs_builtin.c Wed Apr 10 17:46:29 2019 +0300
+++ b/njs/njs_builtin.c Sun Apr 07 14:26:13 2019 +0800
@@ -257,6 +257,12 @@ njs_builtin_objects_create(njs_vm_t *vm)
return NXT_ERROR;
}
+ ret = njs_object_hash_init(vm, &shared->arrow_instance_hash,
+ &njs_arrow_instance_init);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return NXT_ERROR;
+ }
+
ret = njs_object_hash_init(vm, &shared->arguments_object_instance_hash,
&njs_arguments_object_instance_init);
if (nxt_slow_path(ret != NXT_OK)) {
diff -r 070b635928a9 -r d7a0eb59a7e7 njs/njs_extern.c
--- a/njs/njs_extern.c Wed Apr 10 17:46:29 2019 +0300
+++ b/njs/njs_extern.c Sun Apr 07 14:26:13 2019 +0800
@@ -105,11 +105,12 @@ njs_vm_external_add(njs_vm_t *vm, nxt_lv
* nxt_mp_zalloc() does also:
* nxt_lvlhsh_init(&function->object.hash);
* function->object.__proto__ = NULL;
+ * function->ctor = 0;
*/
function->object.__proto__ =
&vm->prototypes[NJS_CONSTRUCTOR_FUNCTION].object;
- function->object.shared_hash = vm->shared->function_instance_hash;
+ function->object.shared_hash = vm->shared->arrow_instance_hash;
function->object.type = NJS_FUNCTION;
function->object.shared = 1;
function->object.extensible = 1;
diff -r 070b635928a9 -r d7a0eb59a7e7 njs/njs_function.c
--- a/njs/njs_function.c Wed Apr 10 17:46:29 2019 +0300
+++ b/njs/njs_function.c Sun Apr 07 14:26:13 2019 +0800
@@ -38,11 +38,17 @@ njs_function_alloc(njs_vm_t *vm, njs_fun
* function->object.__proto__ = NULL;
*/
- function->ctor = 1;
+ function->ctor = !lambda->arrow;
function->args_offset = 1;
function->u.lambda = lambda;
- function->object.shared_hash = vm->shared->function_instance_hash;
+ if (lambda->arrow || !function->ctor) {
+ function->object.shared_hash = vm->shared->arrow_instance_hash;
+
+ } else {
+ function->object.shared_hash = vm->shared->function_instance_hash;
+ }
+
function->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_FUNCTION].object;
function->object.type = NJS_FUNCTION;
function->object.shared = shared;
@@ -1195,6 +1201,23 @@ const njs_object_init_t njs_function_in
};
+const njs_object_prop_t njs_arrow_instance_properties[] =
+{
+ {
+ .type = NJS_PROPERTY_HANDLER,
+ .name = njs_string("length"),
+ .value = njs_prop_handler(njs_function_instance_length),
+ },
+};
+
+
+const njs_object_init_t njs_arrow_instance_init = {
+ nxt_string("Arrow instance"),
+ njs_arrow_instance_properties,
+ nxt_nitems(njs_arrow_instance_properties),
+};
+
+
njs_ret_t
njs_eval_function(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
njs_index_t unused)
diff -r 070b635928a9 -r d7a0eb59a7e7 njs/njs_function.h
--- a/njs/njs_function.h Wed Apr 10 17:46:29 2019 +0300
+++ b/njs/njs_function.h Sun Apr 07 14:26:13 2019 +0800
@@ -30,6 +30,7 @@ struct njs_function_lambda_s {
/* Function internal block closures levels. */
uint8_t block_closures; /* 4 bits */
+ uint8_t arrow; /* 1 bit */
uint8_t rest_parameters; /* 1 bit */
/* Initial values of local scope. */
@@ -218,6 +219,7 @@ njs_function_previous_frame(njs_native_f
extern const njs_object_init_t njs_function_constructor_init;
extern const njs_object_init_t njs_function_prototype_init;
extern const njs_object_init_t njs_function_instance_init;
+extern const njs_object_init_t njs_arrow_instance_init;
extern const njs_object_init_t njs_arguments_object_instance_init;
njs_ret_t njs_eval_function(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
diff -r 070b635928a9 -r d7a0eb59a7e7 njs/njs_lexer.c
--- a/njs/njs_lexer.c Wed Apr 10 17:46:29 2019 +0300
+++ b/njs/njs_lexer.c Sun Apr 07 14:26:13 2019 +0800
@@ -278,6 +278,7 @@ static const njs_lexer_multi_t njs_grea
static const njs_lexer_multi_t njs_assignment_token[] = {
{ '=', NJS_TOKEN_EQUAL, 1, njs_strict_equal_token },
+ { '>', NJS_TOKEN_ARROW, 0, NULL },
};
diff -r 070b635928a9 -r d7a0eb59a7e7 njs/njs_lexer.h
--- a/njs/njs_lexer.h Wed Apr 10 17:46:29 2019 +0300
+++ b/njs/njs_lexer.h Sun Apr 07 14:26:13 2019 +0800
@@ -36,6 +36,7 @@ typedef enum {
NJS_TOKEN_CONDITIONAL,
NJS_TOKEN_ASSIGNMENT,
+ NJS_TOKEN_ARROW,
NJS_TOKEN_ADDITION_ASSIGNMENT,
NJS_TOKEN_SUBSTRACTION_ASSIGNMENT,
NJS_TOKEN_MULTIPLICATION_ASSIGNMENT,
diff -r 070b635928a9 -r d7a0eb59a7e7 njs/njs_object.c
--- a/njs/njs_object.c Wed Apr 10 17:46:29 2019 +0300
+++ b/njs/njs_object.c Sun Apr 07 14:26:13 2019 +0800
@@ -764,7 +764,12 @@ njs_method_private_copy(njs_vm_t *vm, nj
return NXT_ERROR;
}
- function->object.shared_hash = vm->shared->function_instance_hash;
+ if (function->ctor) {
+ function->object.shared_hash = vm->shared->function_instance_hash;
+
+ } else {
+ function->object.shared_hash = vm->shared->arrow_instance_hash;
+ }
pq->lhq.replace = 0;
pq->lhq.value = prop;
diff -r 070b635928a9 -r d7a0eb59a7e7 njs/njs_parser.c
--- a/njs/njs_parser.c Wed Apr 10 17:46:29 2019 +0300
+++ b/njs/njs_parser.c Sun Apr 07 14:26:13 2019 +0800
@@ -2103,6 +2103,172 @@ njs_parser_property_token(njs_vm_t *vm,
}
+nxt_int_t
+njs_parser_match_arrow_expression(njs_vm_t *vm, njs_parser_t *parser,
+ njs_token_t token)
+{
+ size_t offset;
+ nxt_bool_t rest_parameters;
+
+ if (token != NJS_TOKEN_OPEN_PARENTHESIS && token != NJS_TOKEN_NAME) {
+ return NXT_DECLINED;
+ }
+
+ offset = 0;
+
+ if (token == NJS_TOKEN_NAME) {
+ goto arrow;
+ }
+
+ token = njs_parser_peek_token(vm, parser, &offset);
+ if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+ return NXT_DECLINED;
+ }
+
+ rest_parameters = 0;
+
+ while (token != NJS_TOKEN_CLOSE_PARENTHESIS) {
+
+ if (rest_parameters) {
+ return NXT_DECLINED;
+ }
+
+ if (nxt_slow_path(token == NJS_TOKEN_ELLIPSIS)) {
+ rest_parameters = 1;
+
+ token = njs_parser_peek_token(vm, parser, &offset);
+ if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+ return NXT_DECLINED;
+ }
+ }
+
+ if (nxt_slow_path(token != NJS_TOKEN_NAME)) {
+ return NXT_DECLINED;
+ }
+
+ token = njs_parser_peek_token(vm, parser, &offset);
+ if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+ return token;
+ }
+
+ if (token == NJS_TOKEN_COMMA) {
+ token = njs_parser_peek_token(vm, parser, &offset);
+ if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+ return NXT_DECLINED;
+ }
+ }
+ }
+
+arrow:
+
+ token = njs_parser_peek_token(vm, parser, &offset);
+ if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+ return NXT_DECLINED;
+ }
+
+ if (parser->lexer->prev_token == NJS_TOKEN_LINE_END) {
+ return NXT_DECLINED;
+ }
+
+ if (nxt_slow_path(token != NJS_TOKEN_ARROW)) {
+ return NXT_DECLINED;
+ }
+
+ return NXT_OK;
+}
+
+
+njs_token_t
+njs_parser_arrow_expression(njs_vm_t *vm, njs_parser_t *parser,
+ njs_token_t token)
+{
+ njs_ret_t ret;
+ njs_index_t index;
+ njs_parser_node_t *node, *body, *parent;
+ njs_function_lambda_t *lambda;
+
+ node = njs_parser_node_new(vm, parser, NJS_TOKEN_FUNCTION_EXPRESSION);
+ if (nxt_slow_path(node == NULL)) {
+ return NJS_TOKEN_ERROR;
+ }
+
+ node->token_line = njs_parser_token_line(parser);
+ parser->node = node;
+
+ lambda = nxt_mp_zalloc(vm->mem_pool, sizeof(njs_function_lambda_t));
+ if (nxt_slow_path(lambda == NULL)) {
+ return NJS_TOKEN_ERROR;
+ }
+
+ lambda->arrow = 1;
+
+ node->u.value.data.u.lambda = lambda;
+
+ ret = njs_parser_scope_begin(vm, parser, NJS_SCOPE_FUNCTION);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return NJS_TOKEN_ERROR;
+ }
+
+ parser->scope->arrow_function = 1;
+
+ index = NJS_SCOPE_ARGUMENTS;
+
+ /* A "this" reservation. */
+ index += sizeof(njs_value_t);
+
+ if (token == NJS_TOKEN_OPEN_PARENTHESIS) {
+ token = njs_parser_lambda_arguments(vm, parser, lambda, index, token);
+ if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+ return token;
+ }
+
+ } else {
+ token = njs_parser_lambda_argument(vm, parser, index);
+ if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+ return token;
+ }
+
+ lambda->nargs = 1;
+ }
+
+ if (parser->lexer->prev_token == NJS_TOKEN_LINE_END) {
+ return NJS_TOKEN_ILLEGAL;
+ }
+
+ token = njs_parser_match(vm, parser, token, NJS_TOKEN_ARROW);
+ if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+ return token;
+ }
+
+ if (token == NJS_TOKEN_OPEN_BRACE) {
+ token = njs_parser_lambda_body(vm, parser, token);
+ if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+ return token;
+ }
+
+ } else {
+ parent = parser->node;
+
+ token = njs_parser_assignment_expression(vm, parser, token);
+ if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+ return token;
+ }
+
+ body = njs_parser_return_set(vm, parser, parser->node);
+ if (nxt_slow_path(body == NULL)) {
+ return NJS_TOKEN_ERROR;
+ }
+
+ parent->right = body;
+ parser->node = parent;
+ }
+
+ njs_parser_scope_end(vm, parser);
+
+ return token;
+}
+
+
nxt_bool_t
njs_parser_has_side_effect(njs_parser_node_t *node)
{
diff -r 070b635928a9 -r d7a0eb59a7e7 njs/njs_parser.h
--- a/njs/njs_parser.h Wed Apr 10 17:46:29 2019 +0300
+++ b/njs/njs_parser.h Sun Apr 07 14:26:13 2019 +0800
@@ -32,6 +32,7 @@ struct njs_parser_scope_s {
uint8_t nesting; /* 4 bits */
uint8_t argument_closures;
uint8_t module;
+ uint8_t arrow_function;
};
@@ -81,6 +82,10 @@ njs_token_t njs_parser_expression(njs_vm
njs_token_t njs_parser_assignment_expression(njs_vm_t *vm,
njs_parser_t *parser, njs_token_t token);
njs_token_t njs_parser_function_expression(njs_vm_t *vm, njs_parser_t *parser);
+nxt_int_t njs_parser_match_arrow_expression(njs_vm_t *vm, njs_parser_t *parser,
+ njs_token_t token);
+njs_token_t njs_parser_arrow_expression(njs_vm_t *vm, njs_parser_t *parser,
+ njs_token_t token);
njs_token_t njs_parser_module_lambda(njs_vm_t *vm, njs_parser_t *parser);
njs_token_t njs_parser_terminal(njs_vm_t *vm, njs_parser_t *parser,
njs_token_t token);
@@ -226,10 +231,12 @@ njs_parser_global_scope(njs_vm_t *vm)
nxt_inline njs_parser_scope_t *
-njs_function_scope(njs_parser_scope_t *scope)
+njs_function_scope(njs_parser_scope_t *scope, nxt_bool_t any)
{
while (scope->type != NJS_SCOPE_GLOBAL) {
- if (scope->type == NJS_SCOPE_FUNCTION) {
+ if (scope->type == NJS_SCOPE_FUNCTION
+ && (any || !scope->arrow_function))
+ {
return scope;
}
diff -r 070b635928a9 -r d7a0eb59a7e7 njs/njs_parser_terminal.c
--- a/njs/njs_parser_terminal.c Wed Apr 10 17:46:29 2019 +0300
+++ b/njs/njs_parser_terminal.c Sun Apr 07 14:26:13 2019 +0800
@@ -35,6 +35,11 @@ njs_parser_terminal(njs_vm_t *vm, njs_pa
njs_ret_t ret;
njs_parser_node_t *node;
+ ret = njs_parser_match_arrow_expression(vm, parser, token);
+ if (ret == NXT_OK) {
+ return njs_parser_arrow_expression(vm, parser, token);
+ }
+
if (token == NJS_TOKEN_OPEN_PARENTHESIS) {
token = njs_parser_token(vm, parser);
@@ -211,20 +216,10 @@ njs_parser_reference(njs_vm_t *vm, njs_p
case NJS_TOKEN_THIS:
nxt_thread_log_debug("JS: this");
- scope = parser->scope;
-
- while (scope->type != NJS_SCOPE_GLOBAL) {
- if (scope->type == NJS_SCOPE_FUNCTION) {
- break;
- }
+ scope = njs_function_scope(parser->scope, 0);
- scope = scope->parent;
- }
-
- if (scope->type != NJS_SCOPE_GLOBAL) {
- if (njs_function_scope(scope)
- == njs_function_scope(parser->scope))
- {
+ if (scope != NULL) {
+ if (scope == njs_function_scope(parser->scope, 1)) {
node->index = NJS_INDEX_THIS;
} else {
@@ -232,14 +227,13 @@ njs_parser_reference(njs_vm_t *vm, njs_p
node->token_line = token_line;
- ret = njs_variable_reference(vm, parser->scope, node, name,
- hash, NJS_REFERENCE);
+ ret = njs_variable_reference(vm, scope, node, name, hash,
+ NJS_REFERENCE);
if (nxt_slow_path(ret != NXT_OK)) {
return NULL;
}
- var = njs_variable_add(vm, parser->scope, name, hash,
- NJS_VARIABLE_VAR);
+ var = njs_variable_add(vm, scope, name, hash, NJS_VARIABLE_VAR);
if (nxt_slow_path(var == NULL)) {
return NULL;
}
@@ -361,7 +355,9 @@ njs_parser_reference(njs_vm_t *vm, njs_p
case NJS_TOKEN_ARGUMENTS:
nxt_thread_log_debug("JS: arguments");
- if (parser->scope->type <= NJS_SCOPE_GLOBAL) {
+ scope = njs_function_scope(parser->scope, 0);
+
+ if (scope == NULL) {
njs_parser_syntax_error(vm, parser, "\"%V\" object "
"in global scope", name);
@@ -370,13 +366,13 @@ njs_parser_reference(njs_vm_t *vm, njs_p
node->token_line = token_line;
- ret = njs_variable_reference(vm, parser->scope, node, name, hash,
+ ret = njs_variable_reference(vm, scope, node, name, hash,
NJS_REFERENCE);
if (nxt_slow_path(ret != NXT_OK)) {
return NULL;
}
- var = njs_variable_add(vm, parser->scope, name, hash, NJS_VARIABLE_VAR);
+ var = njs_variable_add(vm, scope, name, hash, NJS_VARIABLE_VAR);
if (nxt_slow_path(var == NULL)) {
return NULL;
}
diff -r 070b635928a9 -r d7a0eb59a7e7 njs/njs_vm.h
--- a/njs/njs_vm.h Wed Apr 10 17:46:29 2019 +0300
+++ b/njs/njs_vm.h Sun Apr 07 14:26:13 2019 +0800
@@ -1119,6 +1119,7 @@ struct njs_vm_shared_s {
nxt_lvlhsh_t array_instance_hash;
nxt_lvlhsh_t string_instance_hash;
nxt_lvlhsh_t function_instance_hash;
+ nxt_lvlhsh_t arrow_instance_hash;
nxt_lvlhsh_t arguments_object_instance_hash;
njs_object_t string_object;
diff -r 070b635928a9 -r d7a0eb59a7e7 njs/test/njs_expect_test.exp
--- a/njs/test/njs_expect_test.exp Wed Apr 10 17:46:29 2019 +0300
+++ b/njs/test/njs_expect_test.exp Sun Apr 07 14:26:13 2019 +0800
@@ -663,6 +663,8 @@ njs_test {
njs_test {
{"this\r\n"
"this\r\nundefined"}
+ {"(() => this)()\r\n"
+ "(() => this)()\r\nundefined"}
} "-t module"
njs_test {
diff -r 070b635928a9 -r d7a0eb59a7e7 njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c Wed Apr 10 17:46:29 2019 +0300
+++ b/njs/test/njs_unit_test.c Sun Apr 07 14:26:13 2019 +0800
@@ -6526,6 +6526,12 @@ static njs_unit_test_t njs_test[] =
/* arguments object. */
+ { nxt_string("arguments"),
+ nxt_string("SyntaxError: \"arguments\" object in global scope in 1") },
+
+ { nxt_string("{arguments}"),
+ nxt_string("SyntaxError: \"arguments\" object in global scope in 1") },
+
{ nxt_string("var arguments"),
nxt_string("SyntaxError: Identifier \"arguments\" is forbidden in var declaration in 1") },
@@ -6625,6 +6631,138 @@ static njs_unit_test_t njs_test[] =
"myFoo(1,2);" ),
nxt_string("") },
+ /* arrow functions. */
+
+ { nxt_string("()"),
+ nxt_string("SyntaxError: Unexpected token \")\" in 1") },
+
+ { nxt_string("() => "),
+ nxt_string("SyntaxError: Unexpected end of input in 1") },
+
+ { nxt_string("() => {"),
+ nxt_string("SyntaxError: Unexpected end of input in 1") },
+
+ { nxt_string("a\n => 1"),
+ nxt_string("SyntaxError: Unexpected token \"=>\" in 2") },
+
+ { nxt_string("new (()=>1)"),
+ nxt_string("TypeError: function is not a constructor")},
+
+ { nxt_string("(\n) => {}"),
+ nxt_string("[object Function]") },
+
+ { nxt_string("a => 1"),
+ nxt_string("[object Function]") },
+
+ { nxt_string("({f:()=>1, g:()=>2}).f()"),
+ nxt_string("1") },
+
+ { nxt_string("var f = f => {return 1;}; f()"),
+ nxt_string("1") },
+
+ { nxt_string("var f = (f) => {return 1;}; f()"),
+ nxt_string("1") },
+
+ { nxt_string("var f = (f, a, b) => {return 1;}; f()"),
+ nxt_string("1") },
+
+ { nxt_string("var f = () => {return 1;}; f()"),
+ nxt_string("1") },
+
+ { nxt_string("(f => {return 1;})()"),
+ nxt_string("1") },
+
+ { nxt_string("((f) => {return 1;})()"),
+ nxt_string("1") },
+
+ { nxt_string("(((f) => {return 1;}))()"),
+ nxt_string("1") },
+
+ { nxt_string("var f = f => 1; f()"),
+ nxt_string("1") },
+
+ { nxt_string("() => 1"),
+ nxt_string("[object Function]") },
+
+ { nxt_string("var f = ()=>{}; f()"),
+ nxt_string("undefined") },
+
+ { nxt_string("var f = ()=>({}); f()"),
+ nxt_string("[object Object]") },
+
+ { nxt_string("var materials = ['Hydrogen', 'Helium', 'Lithium', 'Beryllium'];"
+ "materials.map(material => { return material.length; });"),
+ nxt_string("8,6,7,9") },
+
+ { nxt_string("var materials = ['Hydrogen', 'Helium', 'Lithium', 'Beryllium'];"
+ "materials.map(material => material.length);"),
+ nxt_string("8,6,7,9") },
+
+ { nxt_string("var materials = ['Hydrogen', 'Helium', 'Lithium', 'Beryllium'];"
+ "materials.map(material => { material.length });"),
+ nxt_string(",,,") },
+
+ { nxt_string("function f(a, b, c) {a = 1; return () => { return arguments[1]; };};"
+ "f(1, 2, 3)('a', 'b');"),
+ nxt_string("2") },
+
+ { nxt_string("var f = (...c) => { return (function() { return arguments.length; }).bind(null, c); };"
+ "var x = f(1,'a',false, {}); x()"),
+ nxt_string("1") },
+
+ { nxt_string("var f = (...c) => { return (function() { return arguments.length; }).bind(null, c); };"
+ "var x = f(1,'a',false, {}); x(1,2,3)"),
+ nxt_string("4") },
+
+ { nxt_string("function Car(){ this.age = 0; (() => { this.age++;})();}"
+ "(new Car()).age"),
+ nxt_string("1") },
+
+ { nxt_string("function Car(){ this.age = 0; (function(){ this.age++;})();}"
+ "(new Car()).age"),
+ nxt_string("TypeError: cannot get property \"age\" of undefined") },
+
+ /* arrow functions + global this. */
+
+ { nxt_string("(() => this)()"),
+ nxt_string("[object Object]") },
+
+ { nxt_string("(() => this).call('abc')"),
+ nxt_string("[object Object]") },
+
+ { nxt_string("(() => this).apply('abc')"),
+ nxt_string("[object Object]") },
+
+ { nxt_string("(() => this).bind('abc')()"),
+ nxt_string("[object Object]") },
+
+ { nxt_string("(function() { return (() => this); })()()"),
+ nxt_string("undefined") },
+
+ { nxt_string("(function() { return (() => this); }).call('abc')()"),
+ nxt_string("abc") },
+
+ { nxt_string("(function() { return (() => this); }).bind('abc')()()"),
+ nxt_string("abc") },
+
+ { nxt_string("(function() { return (() => this); })"
+ ".call('abc').call('bca')"),
+ nxt_string("abc") },
+
+ { nxt_string("(function() { return (() => this); })"
+ ".call('abc').bind('bca')()"),
+ nxt_string("abc") },
+
+ { nxt_string("(function() { return function() { return () => this; }; })"
+ ".call('bca').call('abc')()"),
+ nxt_string("abc") },
+
+ { nxt_string("var f = () => 1; f.prototype"),
+ nxt_string("undefined") },
+
+ { nxt_string("var f = (a,b) => 0; f.length"),
+ nxt_string("2") },
+
/* Scopes. */
{ nxt_string("function f(x) { a = x } var a; f(5); a"),
@@ -7568,6 +7706,9 @@ static njs_unit_test_t njs_test[] =
{ nxt_string("this.NaN + 1"),
nxt_string("NaN") },
+ { nxt_string("{this}"),
+ nxt_string("undefined") },
+
{ nxt_string("if (1) {new this}"),
nxt_string("TypeError: object is not a function") },
@@ -7640,6 +7781,9 @@ static njs_unit_test_t njs_test[] =
{ nxt_string("Object.prototype"),
nxt_string("[object Object]") },
+ { nxt_string("Object.prototype.valueOf.prototype"),
+ nxt_string("undefined") },
+
{ nxt_string("Object.constructor === Function"),
nxt_string("true") },
More information about the nginx-devel
mailing list