diff --git a/jerry-core/parser/js/byte-code.h b/jerry-core/parser/js/byte-code.h index 506f2c30f..aaa693c0c 100644 --- a/jerry-core/parser/js/byte-code.h +++ b/jerry-core/parser/js/byte-code.h @@ -302,13 +302,13 @@ VM_OC_NEW | VM_OC_PUT_STACK) \ CBC_OPCODE (CBC_EVAL, CBC_NO_FLAG, 0, \ VM_OC_EVAL) \ - CBC_OPCODE (CBC_CREATE_LOCAL, CBC_HAS_LITERAL_ARG, 0, \ + CBC_OPCODE (CBC_CREATE_VAR, CBC_HAS_LITERAL_ARG, 0, \ VM_OC_INIT_LOCALS) \ CBC_OPCODE (CBC_CREATE_LET, CBC_HAS_LITERAL_ARG, 0, \ VM_OC_INIT_LOCALS) \ CBC_OPCODE (CBC_CREATE_CONST, CBC_HAS_LITERAL_ARG, 0, \ VM_OC_INIT_LOCALS) \ - CBC_OPCODE (CBC_CREATE_DESTRUCTURED_ARG, CBC_HAS_LITERAL_ARG, 0, \ + CBC_OPCODE (CBC_CREATE_LOCAL, CBC_HAS_LITERAL_ARG, 0, \ VM_OC_NONE) \ CBC_OPCODE (CBC_INIT_LOCAL, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \ VM_OC_INIT_LOCALS) \ diff --git a/jerry-core/parser/js/js-parser-expr.c b/jerry-core/parser/js/js-parser-expr.c index b5b8b3fb8..be3233b46 100644 --- a/jerry-core/parser/js/js-parser-expr.c +++ b/jerry-core/parser/js/js-parser-expr.c @@ -2516,7 +2516,6 @@ static void parser_parse_array_initializer (parser_context_t *context_p, /**< context */ parser_pattern_flags_t flags) /**< flags */ { - JERRY_ASSERT (context_p->token.type == LEXER_LEFT_SQUARE); parser_pattern_end_marker_t end_pos = parser_pattern_get_target (context_p, flags); lexer_next_token (context_p); @@ -2568,7 +2567,6 @@ static void parser_parse_object_initializer (parser_context_t *context_p, /**< context */ parser_pattern_flags_t flags) /**< flags */ { - JERRY_ASSERT (context_p->token.type == LEXER_LEFT_BRACE); parser_pattern_end_marker_t end_pos = parser_pattern_get_target (context_p, flags); while (true) @@ -2646,7 +2644,6 @@ parser_parse_object_initializer (parser_context_t *context_p, /**< context */ /** * Parse an initializer. - * */ void parser_parse_initializer (parser_context_t *context_p, /**< context */ @@ -2662,6 +2659,26 @@ parser_parse_initializer (parser_context_t *context_p, /**< context */ parser_parse_array_initializer (context_p, flags); } } /* parser_parse_initializer */ + +/** + * Parse an initializer using the next character. + */ +void +parser_parse_initializer_by_next_char (parser_context_t *context_p, /**< context */ + parser_pattern_flags_t flags) /**< flags */ +{ + JERRY_ASSERT (lexer_check_next_characters (context_p, LIT_CHAR_LEFT_SQUARE, LIT_CHAR_LEFT_BRACE)); + + if (lexer_consume_next_character (context_p) == LIT_CHAR_LEFT_BRACE) + { + parser_parse_object_initializer (context_p, flags); + } + else + { + parser_parse_array_initializer (context_p, flags); + } +} /* parser_parse_initializer_by_next_char */ + #endif /* ENABLED (JERRY_ES2015) */ /** diff --git a/jerry-core/parser/js/js-parser-internal.h b/jerry-core/parser/js/js-parser-internal.h index 4aac02c04..43c532464 100644 --- a/jerry-core/parser/js/js-parser-internal.h +++ b/jerry-core/parser/js/js-parser-internal.h @@ -669,6 +669,7 @@ void parser_parse_class (parser_context_t *context_p, bool is_statement); void parser_parse_super_class_context_start (parser_context_t *context_p); void parser_parse_super_class_context_end (parser_context_t *context_p); void parser_parse_initializer (parser_context_t *context_p, parser_pattern_flags_t flags); +void parser_parse_initializer_by_next_char (parser_context_t *context_p, parser_pattern_flags_t flags); #endif /* ENABLED (JERRY_ES2015) */ /** diff --git a/jerry-core/parser/js/js-parser-statm.c b/jerry-core/parser/js/js-parser-statm.c index ea5df5cc9..1d70133a0 100644 --- a/jerry-core/parser/js/js-parser-statm.c +++ b/jerry-core/parser/js/js-parser-statm.c @@ -518,14 +518,13 @@ parser_parse_var_statement (parser_context_t *context_p) /**< context */ #if ENABLED (JERRY_ES2015) if (lexer_check_next_characters (context_p, LIT_CHAR_LEFT_SQUARE, LIT_CHAR_LEFT_BRACE)) { - lexer_next_token (context_p); - parser_pattern_flags_t options = PARSER_PATTERN_BINDING; + parser_pattern_flags_t flags = PARSER_PATTERN_BINDING; if (declaration_type != LEXER_KEYW_VAR) { - options |= PARSER_PATTERN_LEXICAL; + flags |= PARSER_PATTERN_LEXICAL; } - parser_parse_initializer (context_p, options); + parser_parse_initializer_by_next_char (context_p, flags); } else { @@ -1248,8 +1247,6 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */ { bool is_lexical = (context_p->token.type != LEXER_KEYW_VAR); - lexer_next_token (context_p); - parser_emit_cbc_ext (context_p, is_for_in ? CBC_EXT_FOR_IN_GET_NEXT : CBC_EXT_FOR_OF_GET_NEXT); @@ -1260,14 +1257,14 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */ scanner_release_next (context_p, sizeof (scanner_location_info_t)); } - uint32_t flags = (PARSER_PATTERN_BINDING | PARSER_PATTERN_TARGET_ON_STACK); + parser_pattern_flags_t flags = (PARSER_PATTERN_BINDING | PARSER_PATTERN_TARGET_ON_STACK); if (is_lexical) { flags |= PARSER_PATTERN_LEXICAL; } - parser_parse_initializer (context_p, (parser_pattern_flags_t) flags); + parser_parse_initializer_by_next_char (context_p, flags); break; } #endif /* ENABLED (JERRY_ES2015) */ @@ -1813,8 +1810,6 @@ parser_parse_try_statement_end (parser_context_t *context_p) /**< context */ if (context_p->token.type == LEXER_KEYW_CATCH) { - uint16_t literal_index; - lexer_next_token (context_p); if (context_p->token.type != LEXER_LEFT_PAREN) @@ -1849,18 +1844,40 @@ parser_parse_try_statement_end (parser_context_t *context_p) /**< context */ scanner_create_variables (context_p, SCANNER_CREATE_VARS_NO_OPTS); } - lexer_expect_identifier (context_p, LEXER_IDENT_LITERAL); - JERRY_ASSERT (context_p->token.type == LEXER_LITERAL - && context_p->token.lit_location.type == LEXER_IDENT_LITERAL); +#if ENABLED (JERRY_ES2015) + if (lexer_check_next_characters (context_p, LIT_CHAR_LEFT_SQUARE, LIT_CHAR_LEFT_BRACE)) + { + parser_pattern_flags_t flags = (PARSER_PATTERN_BINDING + | PARSER_PATTERN_TARGET_ON_STACK + | PARSER_PATTERN_LEXICAL); + + parser_parse_initializer_by_next_char (context_p, flags); + } + else + { +#endif /* ENABLED (JERRY_ES2015) */ + lexer_expect_identifier (context_p, LEXER_IDENT_LITERAL); + JERRY_ASSERT (context_p->token.type == LEXER_LITERAL + && context_p->token.lit_location.type == LEXER_IDENT_LITERAL); + +#if ENABLED (JERRY_ES2015) + uint16_t literal_index = context_p->lit_object.index; + parser_emit_cbc_literal (context_p, + (literal_index >= PARSER_REGISTER_START) ? CBC_ASSIGN_SET_IDENT : CBC_ASSIGN_LET_CONST, + literal_index); +#else /* !ENABLED (JERRY_ES2015) */ + parser_emit_cbc_literal (context_p, CBC_ASSIGN_SET_IDENT, context_p->lit_object.index); +#endif /* ENABLED (JERRY_ES2015) */ + + lexer_next_token (context_p); +#if ENABLED (JERRY_ES2015) + } +#endif /* ENABLED (JERRY_ES2015) */ #ifndef JERRY_NDEBUG JERRY_ASSERT (block_found); #endif /* !JERRY_NDEBUG */ - literal_index = context_p->lit_object.index; - - lexer_next_token (context_p); - if (context_p->token.type != LEXER_RIGHT_PAREN) { parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED); @@ -1873,7 +1890,6 @@ parser_parse_try_statement_end (parser_context_t *context_p) /**< context */ parser_raise_error (context_p, PARSER_ERR_LEFT_BRACE_EXPECTED); } - parser_emit_cbc_literal (context_p, CBC_ASSIGN_SET_IDENT, literal_index); parser_flush_cbc (context_p); } else diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index de18f0c37..b08976868 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -1701,7 +1701,7 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */ flags |= PARSER_PATTERN_TARGET_DEFAULT; } - parser_parse_initializer (context_p, (parser_pattern_flags_t) flags); + parser_parse_initializer (context_p, flags); context_p->argument_count++; if (context_p->argument_count >= PARSER_MAXIMUM_NUMBER_OF_REGISTERS) diff --git a/jerry-core/parser/js/js-scanner-internal.h b/jerry-core/parser/js/js-scanner-internal.h index fee847e42..ba79f7c3f 100644 --- a/jerry-core/parser/js/js-scanner-internal.h +++ b/jerry-core/parser/js/js-scanner-internal.h @@ -131,6 +131,7 @@ typedef enum SCANNER_BINDING_CONST, /**< destructuring const binding */ SCANNER_BINDING_ARG, /**< destructuring arg binding */ SCANNER_BINDING_ARROW_ARG, /**< possible destructuring arg binding of an arrow function */ + SCANNER_BINDING_CATCH, /**< destructuring catch binding */ } scanner_binding_type_t; /** diff --git a/jerry-core/parser/js/js-scanner-util.c b/jerry-core/parser/js/js-scanner-util.c index c8c3e6b6c..8fc42b2d3 100644 --- a/jerry-core/parser/js/js-scanner-util.c +++ b/jerry-core/parser/js/js-scanner-util.c @@ -141,6 +141,7 @@ scanner_get_stream_size (scanner_info_t *info_p, /**< scanner info block */ #if ENABLED (JERRY_ES2015) case SCANNER_STREAM_TYPE_LET: case SCANNER_STREAM_TYPE_CONST: + case SCANNER_STREAM_TYPE_LOCAL: case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG: #endif /* ENABLED (JERRY_ES2015) */ case SCANNER_STREAM_TYPE_ARG: @@ -718,6 +719,10 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */ type = SCANNER_STREAM_TYPE_IMPORT; } #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ + else + { + type = SCANNER_STREAM_TYPE_LOCAL; + } } else if (literal_p->type & SCANNER_LITERAL_IS_CONST) { @@ -1546,6 +1551,7 @@ scanner_is_context_needed (parser_context_t *context_p) /**< context */ JERRY_ASSERT (type == SCANNER_STREAM_TYPE_VAR || type == SCANNER_STREAM_TYPE_LET || type == SCANNER_STREAM_TYPE_CONST + || type == SCANNER_STREAM_TYPE_LOCAL || type == SCANNER_STREAM_TYPE_FUNC || type == SCANNER_STREAM_TYPE_FUNC_LOCAL); #else /* !ENABLED (JERRY_ES2015) */ @@ -1950,6 +1956,7 @@ scanner_create_variables (parser_context_t *context_p, /**< context */ #if ENABLED (JERRY_ES2015) case SCANNER_STREAM_TYPE_LET: case SCANNER_STREAM_TYPE_CONST: + case SCANNER_STREAM_TYPE_LOCAL: case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG: case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_FUNC: #endif /* ENABLED (JERRY_ES2015) */ @@ -1958,7 +1965,7 @@ scanner_create_variables (parser_context_t *context_p, /**< context */ context_p->scope_stack_top = (uint16_t) (scope_stack_p - context_p->scope_stack_p); #endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ - uint16_t opcode = CBC_CREATE_LOCAL; + uint16_t opcode = CBC_CREATE_VAR; if (option_flags & SCANNER_CREATE_VARS_IS_EVAL) { @@ -1978,10 +1985,11 @@ scanner_create_variables (parser_context_t *context_p, /**< context */ opcode = CBC_CREATE_CONST; break; } + case SCANNER_STREAM_TYPE_LOCAL: case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG: case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_FUNC: { - opcode = CBC_CREATE_DESTRUCTURED_ARG; + opcode = CBC_CREATE_LOCAL; break; } } diff --git a/jerry-core/parser/js/js-scanner.c b/jerry-core/parser/js/js-scanner.c index 6db07cc06..e2cfb5fe8 100644 --- a/jerry-core/parser/js/js-scanner.c +++ b/jerry-core/parser/js/js-scanner.c @@ -1192,6 +1192,28 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * lexer_next_token (context_p); + if (binding_type == SCANNER_BINDING_CATCH) + { + JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_CATCH_STATEMENT); + + scanner_pop_binding_list (scanner_context_p); + + if (context_p->token.type != LEXER_RIGHT_PAREN) + { + scanner_raise_error (context_p); + } + + lexer_next_token (context_p); + + if (context_p->token.type != LEXER_LEFT_BRACE) + { + scanner_raise_error (context_p); + } + + scanner_context_p->mode = SCAN_MODE_STATEMENT_OR_TERMINATOR; + return SCAN_NEXT_TOKEN; + } + if (context_p->token.type != LEXER_ASSIGN) { if (SCANNER_NEEDS_BINDING_LIST (binding_type)) @@ -2401,9 +2423,30 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */ scanner_raise_error (context_p); } - const uint8_t *source_p = context_p->source_p; + scanner_literal_pool_t *literal_pool_p; + literal_pool_p = scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_BLOCK); + literal_pool_p->source_p = context_p->source_p; lexer_next_token (context_p); + parser_stack_push_uint8 (context_p, SCAN_STACK_CATCH_STATEMENT); + +#if ENABLED (JERRY_ES2015) + if (context_p->token.type == LEXER_LEFT_SQUARE || context_p->token.type == LEXER_LEFT_BRACE) + { + scanner_push_destructuring_pattern (context_p, scanner_context_p, SCANNER_BINDING_CATCH, false); + + if (context_p->token.type == LEXER_LEFT_SQUARE) + { + parser_stack_push_uint8 (context_p, SCAN_STACK_ARRAY_LITERAL); + scanner_context_p->mode = SCAN_MODE_BINDING; + return SCAN_NEXT_TOKEN; + } + + parser_stack_push_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL); + scanner_context_p->mode = SCAN_MODE_PROPERTY_NAME; + return SCAN_KEEP_TOKEN; + } +#endif /* ENABLED (JERRY_ES2015) */ if (context_p->token.type != LEXER_LITERAL || context_p->token.lit_location.type != LEXER_IDENT_LITERAL) @@ -2411,10 +2454,6 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */ scanner_raise_error (context_p); } - scanner_literal_pool_t *literal_pool_p; - literal_pool_p = scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_BLOCK); - literal_pool_p->source_p = source_p; - lexer_lit_location_t *lit_location_p = scanner_add_literal (context_p, scanner_context_p); lit_location_p->type |= SCANNER_LITERAL_IS_LOCAL; @@ -2432,7 +2471,6 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */ scanner_raise_error (context_p); } - parser_stack_push_uint8 (context_p, SCAN_STACK_CATCH_STATEMENT); scanner_context_p->mode = SCAN_MODE_STATEMENT_OR_TERMINATOR; return SCAN_NEXT_TOKEN; } @@ -3099,7 +3137,8 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ || scanner_context.binding_type == SCANNER_BINDING_LET || scanner_context.binding_type == SCANNER_BINDING_CONST || scanner_context.binding_type == SCANNER_BINDING_ARG - || scanner_context.binding_type == SCANNER_BINDING_ARROW_ARG); + || scanner_context.binding_type == SCANNER_BINDING_ARROW_ARG + || scanner_context.binding_type == SCANNER_BINDING_CATCH); if (type == LEXER_THREE_DOTS) { @@ -3165,6 +3204,10 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ { literal_p->type |= SCANNER_LITERAL_IS_LET; } + else if (scanner_context.binding_type == SCANNER_BINDING_CATCH) + { + literal_p->type |= SCANNER_LITERAL_IS_LOCAL; + } else { literal_p->type |= SCANNER_LITERAL_IS_CONST; @@ -3339,6 +3382,11 @@ scan_completed: JERRY_DEBUG_MSG (" CONST "); break; } + case SCANNER_STREAM_TYPE_LOCAL: + { + JERRY_DEBUG_MSG (" LOCAL "); + break; + } case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG: { JERRY_DEBUG_MSG (" DESTRUCTURED_ARG "); diff --git a/jerry-core/parser/js/js-scanner.h b/jerry-core/parser/js/js-scanner.h index 06af684bb..166929794 100644 --- a/jerry-core/parser/js/js-scanner.h +++ b/jerry-core/parser/js/js-scanner.h @@ -145,6 +145,7 @@ typedef enum #if ENABLED (JERRY_ES2015) SCANNER_STREAM_TYPE_LET, /**< let declaration */ SCANNER_STREAM_TYPE_CONST, /**< const declaration */ + SCANNER_STREAM_TYPE_LOCAL, /**< local declaration (e.g. catch block) */ SCANNER_STREAM_TYPE_DESTRUCTURED_ARG, /**< destructuring argument declaration */ #endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index a5019733d..89e142ab5 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -918,11 +918,11 @@ vm_init_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ switch (type) { - case CBC_CREATE_LOCAL: + case CBC_CREATE_VAR: #if ENABLED (JERRY_ES2015) case CBC_CREATE_LET: case CBC_CREATE_CONST: - case CBC_CREATE_DESTRUCTURED_ARG: + case CBC_CREATE_LOCAL: #endif /* ENABLED (JERRY_ES2015) */ { uint32_t literal_index; @@ -950,7 +950,7 @@ vm_init_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ ecma_property_value_t *property_value_p; property_value_p = ecma_create_named_data_property (frame_ctx_p->lex_env_p, name_p, prop_attributes, NULL); - if (type != CBC_CREATE_LOCAL) + if (type != CBC_CREATE_VAR) { property_value_p->value = ECMA_VALUE_UNINITIALIZED; } diff --git a/tests/jerry/es2015/try-pattern.js b/tests/jerry/es2015/try-pattern.js new file mode 100644 index 000000000..035f69c1a --- /dev/null +++ b/tests/jerry/es2015/try-pattern.js @@ -0,0 +1,73 @@ +/* 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 check_syntax_error(code) +{ + try { + eval(code); + assert(false); + } catch (e) { + assert(e instanceof SyntaxError); + } +} + +check_syntax_error("try {} catch() {}"); +check_syntax_error("try {} catch([a] {}"); +check_syntax_error("try {} catch([a] = [1]) {}"); +check_syntax_error("try {} catch({a} = {a:1}) {}"); +check_syntax_error("try {} catch(a,) {}"); + +try { + throw [1,2] + assert(false) +} catch ([a, b]) { + assert(a === 1) + assert(b === 2) +} + +try { + throw { x:1, y:2 } + assert(false) +} catch ({x, 'y':b}) { + assert(x === 1) + assert(b === 2) +} + +try { + throw [1,2] + assert(false) +} catch ([a, b]) { + eval("assert(a === 1)") + eval("assert(b === 2)") +} + +try { + throw { x:1, y:2 } + assert(false) +} catch ({x, 'y':b}) { + eval("assert(x === 1)") + eval("assert(b === 2)") +} + +try { + try { + throw [] + assert(false) + } catch ([a = b, b]) { + assert(false) + } +} catch (e) { + assert(e instanceof ReferenceError) +}