diff --git a/jerry-core/parser/js/js-scanner.c b/jerry-core/parser/js/js-scanner.c index ba7608a03..6db07cc06 100644 --- a/jerry-core/parser/js/js-scanner.c +++ b/jerry-core/parser/js/js-scanner.c @@ -64,6 +64,9 @@ typedef enum SCAN_STACK_FUNCTION_STATEMENT, /**< function statement */ SCAN_STACK_FUNCTION_EXPRESSION, /**< function expression */ SCAN_STACK_FUNCTION_PROPERTY, /**< function expression in an object literal or class */ +#if ENABLED (JERRY_ES2015) + SCAN_STACK_FUNCTION_ARROW, /**< arrow function expression */ +#endif /* ENABLED (JERRY_ES2015) */ SCAN_STACK_SWITCH_BLOCK, /**< block part of "switch" statement */ SCAN_STACK_IF_STATEMENT, /**< statement part of "if" statements */ SCAN_STACK_WITH_STATEMENT, /**< statement part of "with" statements */ @@ -162,7 +165,7 @@ scanner_check_arrow_body (parser_context_t *context_p, /**< context */ lexer_next_token (context_p); scanner_context_p->mode = SCAN_MODE_STATEMENT_OR_TERMINATOR; - parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_EXPRESSION); + parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_ARROW); } /* scanner_check_arrow_body */ /** @@ -674,7 +677,8 @@ scanner_scan_primary_expression (parser_context_t *context_p, /**< context */ static bool scanner_scan_post_primary_expression (parser_context_t *context_p, /**< context */ scanner_context_t *scanner_context_p, /**< scanner context */ - lexer_token_type_t type) /**< current token type */ + lexer_token_type_t type, /**< current token type */ + scan_stack_modes_t stack_top) /**< current stack top */ { switch (type) { @@ -705,12 +709,13 @@ scanner_scan_post_primary_expression (parser_context_t *context_p, /**< context case LEXER_INCREASE: case LEXER_DECREASE: { - if (!(context_p->token.flags & LEXER_WAS_NEWLINE)) - { - scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END; - return true; - } - /* FALLTHRU */ + return !(context_p->token.flags & LEXER_WAS_NEWLINE); + } + case LEXER_QUESTION_MARK: + { + parser_stack_push_uint8 (context_p, SCAN_STACK_COLON_EXPRESSION); + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + return true; } default: { @@ -718,6 +723,13 @@ scanner_scan_post_primary_expression (parser_context_t *context_p, /**< context } } + if (LEXER_IS_BINARY_OP_TOKEN (type) + && (type != LEXER_KEYW_IN || !SCANNER_IS_FOR_START (stack_top))) + { + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + return true; + } + return false; } /* scanner_scan_post_primary_expression */ @@ -732,95 +744,74 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * lexer_token_type_t type, /**< current token type */ scan_stack_modes_t stack_top) /**< current stack top */ { - switch (type) + if (type == LEXER_COMMA) { - case LEXER_QUESTION_MARK: + switch (stack_top) { - parser_stack_push_uint8 (context_p, SCAN_STACK_COLON_EXPRESSION); - scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; - return SCAN_NEXT_TOKEN; - } - case LEXER_COMMA: - { - switch (stack_top) + case SCAN_STACK_VAR: +#if ENABLED (JERRY_ES2015) + case SCAN_STACK_LET: + case SCAN_STACK_CONST: +#endif /* ENABLED (JERRY_ES2015) */ + case SCAN_STACK_FOR_VAR_START: +#if ENABLED (JERRY_ES2015) + case SCAN_STACK_FOR_LET_START: + case SCAN_STACK_FOR_CONST_START: +#endif /* ENABLED (JERRY_ES2015) */ { - case SCAN_STACK_VAR: -#if ENABLED (JERRY_ES2015) - case SCAN_STACK_LET: - case SCAN_STACK_CONST: -#endif /* ENABLED (JERRY_ES2015) */ - case SCAN_STACK_FOR_VAR_START: -#if ENABLED (JERRY_ES2015) - case SCAN_STACK_FOR_LET_START: - case SCAN_STACK_FOR_CONST_START: -#endif /* ENABLED (JERRY_ES2015) */ - { - scanner_context_p->mode = SCAN_MODE_VAR_STATEMENT; - return SCAN_NEXT_TOKEN; - } - case SCAN_STACK_COLON_EXPRESSION: - { - scanner_raise_error (context_p); - break; - } -#if ENABLED (JERRY_ES2015) - case SCAN_STACK_BINDING_INIT: - case SCAN_STACK_BINDING_LIST_INIT: - { - break; - } - case SCAN_STACK_ARROW_ARGUMENTS: - { - lexer_next_token (context_p); - scanner_process_arrow_arg (context_p, scanner_context_p); - return SCAN_KEEP_TOKEN; - } - case SCAN_STACK_ARROW_EXPRESSION: - { - break; - } - case SCAN_STACK_FUNCTION_PARAMETERS: - { - scanner_context_p->mode = SCAN_MODE_CONTINUE_FUNCTION_ARGUMENTS; - parser_stack_pop_uint8 (context_p); - return SCAN_NEXT_TOKEN; - } - case SCAN_STACK_ARRAY_LITERAL: - { - scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; - - if (scanner_context_p->binding_type != SCANNER_BINDING_NONE) - { - scanner_context_p->mode = SCAN_MODE_BINDING; - } - - return SCAN_NEXT_TOKEN; - } -#endif /* ENABLED (JERRY_ES2015) */ - case SCAN_STACK_OBJECT_LITERAL: - { - scanner_context_p->mode = SCAN_MODE_PROPERTY_NAME; - return SCAN_KEEP_TOKEN; - } - default: - { - scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; - return SCAN_NEXT_TOKEN; - } + scanner_context_p->mode = SCAN_MODE_VAR_STATEMENT; + return SCAN_NEXT_TOKEN; } - break; - } - default: - { - break; - } - } + case SCAN_STACK_COLON_EXPRESSION: + { + scanner_raise_error (context_p); + break; + } +#if ENABLED (JERRY_ES2015) + case SCAN_STACK_BINDING_INIT: + case SCAN_STACK_BINDING_LIST_INIT: + { + break; + } + case SCAN_STACK_ARROW_ARGUMENTS: + { + lexer_next_token (context_p); + scanner_process_arrow_arg (context_p, scanner_context_p); + return SCAN_KEEP_TOKEN; + } + case SCAN_STACK_ARROW_EXPRESSION: + { + break; + } + case SCAN_STACK_FUNCTION_PARAMETERS: + { + scanner_context_p->mode = SCAN_MODE_CONTINUE_FUNCTION_ARGUMENTS; + parser_stack_pop_uint8 (context_p); + return SCAN_NEXT_TOKEN; + } + case SCAN_STACK_ARRAY_LITERAL: + { + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; - if (LEXER_IS_BINARY_OP_TOKEN (type) - && (type != LEXER_KEYW_IN || !SCANNER_IS_FOR_START (stack_top))) - { - scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; - return SCAN_NEXT_TOKEN; + if (scanner_context_p->binding_type != SCANNER_BINDING_NONE) + { + scanner_context_p->mode = SCAN_MODE_BINDING; + } + + return SCAN_NEXT_TOKEN; + } +#endif /* ENABLED (JERRY_ES2015) */ + case SCAN_STACK_OBJECT_LITERAL: + { + scanner_context_p->mode = SCAN_MODE_PROPERTY_NAME; + return SCAN_KEEP_TOKEN; + } + default: + { + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + return SCAN_NEXT_TOKEN; + } + } } switch (stack_top) @@ -2203,15 +2194,24 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */ continue; } case SCAN_STACK_FUNCTION_EXPRESSION: +#if ENABLED (JERRY_ES2015) + case SCAN_STACK_FUNCTION_ARROW: +#endif /* ENABLED (JERRY_ES2015) */ { if (type != LEXER_RIGHT_BRACE) { break; } - scanner_pop_literal_pool (context_p, scanner_context_p); - scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; +#if ENABLED (JERRY_ES2015) + if (context_p->stack_top_uint8 == SCAN_STACK_FUNCTION_ARROW) + { + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END; + } +#endif /* ENABLED (JERRY_ES2015) */ + + scanner_pop_literal_pool (context_p, scanner_context_p); parser_stack_pop_uint8 (context_p); return SCAN_NEXT_TOKEN; } @@ -2634,7 +2634,7 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ #endif /* ENABLED (JERRY_ES2015) */ case SCAN_MODE_POST_PRIMARY_EXPRESSION: { - if (scanner_scan_post_primary_expression (context_p, &scanner_context, type)) + if (scanner_scan_post_primary_expression (context_p, &scanner_context, type, stack_top)) { break; } diff --git a/tests/jerry/es2015/arrow-assignment.js b/tests/jerry/es2015/arrow-assignment.js new file mode 100644 index 000000000..5abadc8b5 --- /dev/null +++ b/tests/jerry/es2015/arrow-assignment.js @@ -0,0 +1,46 @@ +/* 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. + */ + +var y = 0 +var prot = Object.getPrototypeOf(/ /) + +prot.setY = function (v) { y = v } + +assert(y === 0) +// Since arrow function is an assignment expression, this affects certain constructs +var f = x => {} +/ /.setY(5) +assert(y === 5) + +var s +// This is not a function call +assert(eval("s = x => { return 1 }\n(3)") === 3) +assert(typeof s === "function") + +// This is a function call +assert(eval("s = function () { return 1 }\n(3)") === 1) +assert(s === 1) + +var f = 5 ? x => 1 : x => 2 +assert(f() === 1) + +var f = [x => 2][0] +assert(f() === 2) + +var f = 123; f += x => y +assert(typeof f === "string") + +// Comma operator +assert(eval("x => {}, 5") === 5) diff --git a/tests/jerry/es2015/arrow-function.js b/tests/jerry/es2015/arrow-function.js index a2bdbd133..e93a80531 100644 --- a/tests/jerry/es2015/arrow-function.js +++ b/tests/jerry/es2015/arrow-function.js @@ -153,6 +153,7 @@ must_throw ("x => {} (4)"); must_throw ("!x => 4"); must_throw ("x => {} = 1"); must_throw ("x => {} a = 1"); +must_throw ("x => {} ? 1 : 0"); must_throw_strict ("(package) => 0"); must_throw_strict ("(package) => { return 5 }"); must_throw_strict ("(x,x,x) => 0"); @@ -181,21 +182,3 @@ assert(f()()() === 7); var f = (((a=1,b=2) => ((x => (((a) => 8)))))); assert(f()()() === 8); - -var s; -// This is not a function call -assert(eval("s = x => { return 1 }\n(3)") === 3); -assert(typeof s === "function") - -// This is a function call -assert(eval("s = function () { return 1 }\n(3)") === 1); -assert(s === 1) - -var f = 5 ? x => 1 : x => 2 -assert(f() === 1) - -var f = [x => 2][0] -assert(f() === 2) - -var f = 123; f += x => y; -assert(typeof f === "string"); diff --git a/tests/jerry/es2015/regression-test-issue-3355.js b/tests/jerry/es2015/regression-test-issue-3355.js new file mode 100644 index 000000000..dc847e8ff --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-3355.js @@ -0,0 +1,16 @@ +// 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. + +var $ = $ => { } +/ /