From 74f3ea7bdb06bbae4e903f63f269f0213e0c1857 Mon Sep 17 00:00:00 2001 From: hongzhidao Date: Tue, 2 Jul 2019 22:24:11 -0400 Subject: [PATCH] Added Object shorthand methods and computed property names. This closes #182 issue on Github. --- njs/njs_parser.c | 4 +-- njs/njs_parser.h | 2 ++ njs/njs_parser_terminal.c | 57 ++++++++++++++++++++++++++++++++++----- njs/njs_vm.c | 5 +--- njs/test/njs_unit_test.c | 36 +++++++++++++++++++++++-- 5 files changed, 89 insertions(+), 15 deletions(-) diff --git a/njs/njs_parser.c b/njs/njs_parser.c index 1f86dbc8..eaaa4299 100644 --- a/njs/njs_parser.c +++ b/njs/njs_parser.c @@ -24,8 +24,6 @@ static njs_token_t njs_parser_labelled_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_token_t njs_parser_function_lambda(njs_vm_t *vm, - njs_parser_t *parser, njs_function_lambda_t *lambda, njs_token_t token); static njs_token_t njs_parser_lambda_arguments(njs_vm_t *vm, njs_parser_t *parser, njs_function_lambda_t *lambda, njs_index_t index, njs_token_t token); @@ -757,7 +755,7 @@ njs_parser_function_expression(njs_vm_t *vm, njs_parser_t *parser) } -static njs_token_t +njs_token_t njs_parser_function_lambda(njs_vm_t *vm, njs_parser_t *parser, njs_function_lambda_t *lambda, njs_token_t token) { diff --git a/njs/njs_parser.h b/njs/njs_parser.h index b4677a8b..e754d6d5 100644 --- a/njs/njs_parser.h +++ b/njs/njs_parser.h @@ -95,6 +95,8 @@ njs_token_t njs_parser_template_literal(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *njs_parser_argument(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *expr, njs_index_t index); nxt_int_t njs_parser_string_create(njs_vm_t *vm, njs_value_t *value); +njs_token_t njs_parser_function_lambda(njs_vm_t *vm, njs_parser_t *parser, + njs_function_lambda_t *lambda, njs_token_t token); njs_token_t njs_parser_lambda_statements(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token); njs_variable_t *njs_variable_resolve(njs_vm_t *vm, njs_parser_node_t *node); diff --git a/njs/njs_parser_terminal.c b/njs/njs_parser_terminal.c index b25cdfc8..37b87d2a 100644 --- a/njs/njs_parser_terminal.c +++ b/njs/njs_parser_terminal.c @@ -480,12 +480,13 @@ njs_parser_builtin(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node, static njs_token_t njs_parser_object(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *obj) { - uint32_t hash, token_line; - nxt_int_t ret; - nxt_str_t name; - njs_token_t token, prop_token; - njs_lexer_t *lexer; - njs_parser_node_t *object, *property, *expression; + uint32_t hash, token_line; + nxt_int_t ret; + nxt_str_t name; + njs_token_t token, prop_token; + njs_lexer_t *lexer; + njs_parser_node_t *object, *property, *expression; + njs_function_lambda_t *lambda; lexer = parser->lexer; @@ -513,6 +514,26 @@ njs_parser_object(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *obj) case NJS_TOKEN_CLOSE_BRACE: goto done; + case NJS_TOKEN_OPEN_BRACKET: + token = njs_parser_token(vm, parser); + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { + return token; + } + + if (token == NJS_TOKEN_CLOSE_BRACKET) { + return NJS_TOKEN_ILLEGAL; + } + + token = njs_parser_assignment_expression(vm, parser, token); + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { + return token; + } + + property = parser->node; + + token = njs_parser_match(vm, parser, token, NJS_TOKEN_CLOSE_BRACKET); + break; + case NJS_TOKEN_NUMBER: case NJS_TOKEN_STRING: case NJS_TOKEN_ESCAPE_STRING: @@ -576,6 +597,30 @@ njs_parser_object(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *obj) expression = parser->node; break; + case NJS_TOKEN_OPEN_PARENTHESIS: + expression = njs_parser_node_new(vm, parser, + NJS_TOKEN_FUNCTION_EXPRESSION); + if (nxt_slow_path(expression == NULL)) { + return NJS_TOKEN_ERROR; + } + + expression->token_line = njs_parser_token_line(parser); + parser->node = expression; + + lambda = njs_function_lambda_alloc(vm, 0); + if (nxt_slow_path(lambda == NULL)) { + return NJS_TOKEN_ERROR; + } + + expression->u.value.data.u.lambda = lambda; + + token = njs_parser_function_lambda(vm, parser, lambda, token); + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { + return token; + } + + break; + default: return NJS_TOKEN_ILLEGAL; } diff --git a/njs/njs_vm.c b/njs/njs_vm.c index c47be87c..cb1979b9 100644 --- a/njs/njs_vm.c +++ b/njs/njs_vm.c @@ -478,11 +478,8 @@ njs_vmcode_property_init(njs_vm_t *vm, njs_value_t *object, break; case NJS_OBJECT: - ret = njs_primitive_value_to_string(vm, &name, property); + ret = njs_value_to_string(vm, &name, property); if (nxt_slow_path(ret != NXT_OK)) { - njs_internal_error(vm, "failed conversion of type \"%s\" " - "to string while property initialization", - njs_type_string(property->type)); return NXT_ERROR; } diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c index 1caac8b8..9b922bd4 100644 --- a/njs/test/njs_unit_test.c +++ b/njs/test/njs_unit_test.c @@ -3126,7 +3126,7 @@ static njs_unit_test_t njs_test[] = { nxt_string("var x = { a: 1 }, b = delete x.a; x.a +' '+ b"), nxt_string("undefined true") }, - /* Shorthand Object literals. */ + /* Object shorthand property. */ { nxt_string("var a = 1; njs.dump({a})"), nxt_string("{a:1}") }, @@ -3173,6 +3173,38 @@ static njs_unit_test_t njs_test[] = { nxt_string("delete undefined"), nxt_string("SyntaxError: Delete of an unqualified identifier in 1") }, + /* Object shorthand methods. */ + + { nxt_string("var o = {m(){}}; new o.m();"), + nxt_string("TypeError: function is not a constructor") }, + + { nxt_string("var o = {sum(a, b){return a + b;}}; o.sum(1, 2)"), + nxt_string("3") }, + + /* Object computed property. */ + + { nxt_string("var o = { [0]: 1, [-0]: 2 }; o[0];"), + nxt_string("2") }, + + { nxt_string("var k = 'abc'.split('');var o = {[k[0]]: 'baz'}; o.a"), + nxt_string("baz") }, + + { nxt_string("var k = {}; var o = {[k]() {return 'baz'}}; o[k]()"), + nxt_string("baz") }, + + { nxt_string("njs.dump({[{toString(){return 'xx'}}]:1})"), + nxt_string("{xx:1}") }, + + { nxt_string("var o = {}; Object.defineProperty(o, 'toString', {value:()=>'xx'});" + "njs.dump({[o]:1})"), + nxt_string("{xx:1}") }, + + { nxt_string("({[{toString(){return {}}}]:1})"), + nxt_string("TypeError: Cannot convert object to primitive value") }, + + { nxt_string("var o = { [new Number(12345)]: 1000 }; o[12345]"), + nxt_string("1000") }, + /* ES5FIX: "SyntaxError". */ { nxt_string("delete NaN"), @@ -3248,7 +3280,7 @@ static njs_unit_test_t njs_test[] = nxt_string("4") }, { nxt_string("({[]:1})"), - nxt_string("SyntaxError: Unexpected token \"[\" in 1") }, + nxt_string("SyntaxError: Unexpected token \"]\" in 1") }, { nxt_string("({'AB\\ncd':1})['AB\\ncd']"), nxt_string("1") }, -- 2.47.3