From e0e6363f85f7e12f87ea546b8b6632376cd7c238 Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Fri, 19 Oct 2018 13:49:41 +0200 Subject: [PATCH] Fix object initializer prescanning issues. (#2563) This patch fixes incorrect syntax errors reported by the prescanner for ES5.1 getter/setter property initializers and ES2015 computed properties. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- jerry-core/parser/js/js-lexer.c | 3 + jerry-core/parser/js/js-parser-scanner.c | 64 ++++++++++++++++++- .../es2015/object-computed-prescanner.js | 52 +++++++++++++++ tests/jerry/object-literal-prescanner.js | 43 +++++++++++++ 4 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 tests/jerry/es2015/object-computed-prescanner.js create mode 100644 tests/jerry/object-literal-prescanner.js diff --git a/jerry-core/parser/js/js-lexer.c b/jerry-core/parser/js/js-lexer.c index 9745ee7f4..6fb91c200 100644 --- a/jerry-core/parser/js/js-lexer.c +++ b/jerry-core/parser/js/js-lexer.c @@ -2427,6 +2427,9 @@ lexer_scan_identifier (parser_context_t *context_p, /**< context */ lexer_next_token (context_p); if (context_p->token.type == LEXER_LITERAL +#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER + || context_p->token.type == LEXER_LEFT_SQUARE +#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */ || context_p->token.type == LEXER_RIGHT_BRACE) { return; diff --git a/jerry-core/parser/js/js-parser-scanner.c b/jerry-core/parser/js/js-parser-scanner.c index 3352c03d1..9d9a70460 100644 --- a/jerry-core/parser/js/js-parser-scanner.c +++ b/jerry-core/parser/js/js-parser-scanner.c @@ -67,6 +67,9 @@ typedef enum SCAN_STACK_BLOCK_STATEMENT, /**< block statement group */ SCAN_STACK_BLOCK_EXPRESSION, /**< block expression group */ SCAN_STACK_BLOCK_PROPERTY, /**< block property group */ +#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER + SCAN_STACK_COMPUTED_PROPERTY, /**< computed property name */ +#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */ #ifndef CONFIG_DISABLE_ES2015_TEMPLATE_STRINGS SCAN_STACK_TEMPLATE_STRING, /**< template string */ #endif /* !CONFIG_DISABLE_ES2015_TEMPLATE_STRINGS */ @@ -372,9 +375,41 @@ parser_scan_primary_expression_end (parser_context_t *context_p, /**< context */ return false; } +#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER + if (context_p->token.type == LEXER_RIGHT_SQUARE && stack_top == SCAN_STACK_COMPUTED_PROPERTY) + { + lexer_next_token (context_p); + + parser_stack_pop_uint8 (context_p); + stack_top = (scan_stack_modes_t) context_p->stack_top_uint8; + + if (stack_top == SCAN_STACK_BLOCK_PROPERTY) + { + if (context_p->token.type != LEXER_LEFT_PAREN) + { + parser_raise_error (context_p, PARSER_ERR_ARGUMENT_LIST_EXPECTED); + } + + *mode = SCAN_MODE_FUNCTION_ARGUMENTS; + return true; + } + + JERRY_ASSERT (stack_top == SCAN_STACK_OBJECT_LITERAL); + + if (context_p->token.type != LEXER_COLON) + { + parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED); + } + + *mode = SCAN_MODE_PRIMARY_EXPRESSION; + return false; + } +#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */ + /* Check whether we can enter to statement mode. */ if (stack_top != SCAN_STACK_BLOCK_STATEMENT && stack_top != SCAN_STACK_BLOCK_EXPRESSION + && stack_top != SCAN_STACK_BLOCK_PROPERTY #ifndef CONFIG_DISABLE_ES2015_CLASS && stack_top != SCAN_STACK_CLASS #endif /* !CONFIG_DISABLE_ES2015_CLASS */ @@ -776,6 +811,7 @@ parser_scan_until (parser_context_t *context_p, /**< context */ if (context_p->token.type == LEXER_LITERAL && (context_p->token.lit_location.type == LEXER_IDENT_LITERAL + || context_p->token.lit_location.type == LEXER_STRING_LITERAL || context_p->token.lit_location.type == LEXER_NUMBER_LITERAL)) { lexer_next_token (context_p); @@ -826,6 +862,15 @@ parser_scan_until (parser_context_t *context_p, /**< context */ lexer_scan_identifier (context_p, true); +#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER + if (context_p->token.type == LEXER_LEFT_SQUARE) + { + parser_stack_push_uint8 (context_p, SCAN_STACK_COMPUTED_PROPERTY); + mode = SCAN_MODE_PRIMARY_EXPRESSION; + break; + } +#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */ + if (context_p->token.type == LEXER_RIGHT_BRACE) { parser_stack_pop_uint8 (context_p); @@ -836,9 +881,26 @@ parser_scan_until (parser_context_t *context_p, /**< context */ if (context_p->token.type == LEXER_PROPERTY_GETTER || context_p->token.type == LEXER_PROPERTY_SETTER) { + lexer_next_token (context_p); + parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_PROPERTY); + +#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER + if (context_p->token.type == LEXER_LEFT_SQUARE) + { + parser_stack_push_uint8 (context_p, SCAN_STACK_COMPUTED_PROPERTY); + mode = SCAN_MODE_PRIMARY_EXPRESSION; + break; + } +#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */ + + if (context_p->token.type != LEXER_LITERAL) + { + parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED); + } + mode = SCAN_MODE_FUNCTION_ARGUMENTS; - break; + continue; } lexer_next_token (context_p); diff --git a/tests/jerry/es2015/object-computed-prescanner.js b/tests/jerry/es2015/object-computed-prescanner.js new file mode 100644 index 000000000..4b315d6e5 --- /dev/null +++ b/tests/jerry/es2015/object-computed-prescanner.js @@ -0,0 +1,52 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function member_str() { + return "member"; +} + +switch (true) { +default: + var obj = { + ["val" + "ue"]: 0, + set[member_str()](x) { + // Multiple statements. + this.value = x + 4; + this.value += 2; + }, + get[member_str() ? member_str() : ""]() { + // Multiple statements. + this.value = this.value + 1; + return this.value; + }, + get + [1 + 2] + () + { + return 3; + }, + [false ? member_str() + : ""] + :8 + } +} + +obj["member"] = 10; +assert(obj.member === 17); +assert(obj.member === 18); + +assert(obj[3] === 3); +assert(obj["3"] === 3); + +assert(obj[""] === 8); diff --git a/tests/jerry/object-literal-prescanner.js b/tests/jerry/object-literal-prescanner.js new file mode 100644 index 000000000..38333bd6f --- /dev/null +++ b/tests/jerry/object-literal-prescanner.js @@ -0,0 +1,43 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +switch (true) { +default: + var obj = { + value: 0, + set + member + (x) + { + // Multiple statements. + this.value = x + 4; + this.value += 2; + }, + get"member"() { + // Multiple statements. + this.value = this.value + 1; + return this.value; + }, + get 3() { + return 3; + } + } +} + +obj["member"] = 10; +assert(obj.member === 17); +assert(obj.member === 18); + +assert(obj[3] === 3); +assert(obj["3"] === 3);