diff --git a/jerry-core/parser/js/js-parser-expr.c b/jerry-core/parser/js/js-parser-expr.c index 255c375f2..6effd20a6 100644 --- a/jerry-core/parser/js/js-parser-expr.c +++ b/jerry-core/parser/js/js-parser-expr.c @@ -1819,6 +1819,109 @@ parser_process_unary_expression (parser_context_t *context_p, /**< context */ } } /* parser_process_unary_expression */ +/** + * Append a binary '=' token. + */ +static void +parser_append_binary_single_assignment_token (parser_context_t *context_p, /**< context */ + uint8_t assign_ident_opcode) /**< assign ident opcode */ +{ + JERRY_ASSERT (assign_ident_opcode == CBC_ASSIGN_SET_IDENT + || assign_ident_opcode == CBC_ASSIGN_LET_CONST); + + /* Unlike other tokens, the whole byte code is saved for binary + * assignment, since it has multiple forms depending on the + * previous instruction. */ + + if (PARSER_IS_PUSH_LITERAL (context_p->last_cbc_opcode) + && context_p->last_cbc.literal_type == LEXER_IDENT_LITERAL) + { + JERRY_ASSERT (CBC_SAME_ARGS (CBC_PUSH_LITERAL, assign_ident_opcode)); + + parser_check_invalid_assign (context_p); + + uint16_t literal_index; + + if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL) + { + literal_index = context_p->last_cbc.literal_index; + context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE; + } + else if (context_p->last_cbc_opcode == CBC_PUSH_TWO_LITERALS) + { + literal_index = context_p->last_cbc.value; + context_p->last_cbc_opcode = CBC_PUSH_LITERAL; + } + else + { + JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_THREE_LITERALS); + literal_index = context_p->last_cbc.third_literal_index; + context_p->last_cbc_opcode = CBC_PUSH_TWO_LITERALS; + } + + parser_stack_push_uint16 (context_p, literal_index); + parser_stack_push_uint8 (context_p, assign_ident_opcode); + } + else if (context_p->last_cbc_opcode == CBC_PUSH_PROP) + { + JERRY_ASSERT (CBC_SAME_ARGS (CBC_PUSH_PROP, CBC_ASSIGN)); + parser_stack_push_uint8 (context_p, CBC_ASSIGN); + context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE; + } + else if (context_p->last_cbc_opcode == CBC_PUSH_PROP_LITERAL) + { + if (context_p->last_cbc.literal_type != LEXER_IDENT_LITERAL) + { + JERRY_ASSERT (CBC_SAME_ARGS (CBC_PUSH_PROP_LITERAL, CBC_ASSIGN_PROP_LITERAL)); + parser_stack_push_uint16 (context_p, context_p->last_cbc.literal_index); + parser_stack_push_uint8 (context_p, CBC_ASSIGN_PROP_LITERAL); + context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE; +#if ENABLED (JERRY_ES2015) + if (context_p->status_flags & PARSER_CLASS_SUPER_PROP_REFERENCE) + { + parser_emit_cbc_ext (context_p, CBC_EXT_SUPER_PROP_ASSIGN); + parser_flush_cbc (context_p); + } + context_p->status_flags &= (uint32_t) ~PARSER_CLASS_SUPER_PROP_REFERENCE; +#endif /* ENABLED (JERRY_ES2015) */ + } + else + { + context_p->last_cbc_opcode = CBC_PUSH_LITERAL; + parser_stack_push_uint8 (context_p, CBC_ASSIGN); + } + } + else if (context_p->last_cbc_opcode == CBC_PUSH_PROP_LITERAL_LITERAL) + { + JERRY_ASSERT (CBC_SAME_ARGS (CBC_PUSH_PROP_LITERAL_LITERAL, CBC_PUSH_TWO_LITERALS)); + context_p->last_cbc_opcode = CBC_PUSH_TWO_LITERALS; + parser_stack_push_uint8 (context_p, CBC_ASSIGN); + } + else if (context_p->last_cbc_opcode == CBC_PUSH_PROP_THIS_LITERAL) + { + if (context_p->last_cbc.literal_type != LEXER_IDENT_LITERAL) + { + JERRY_ASSERT (CBC_SAME_ARGS (CBC_PUSH_PROP_THIS_LITERAL, CBC_ASSIGN_PROP_THIS_LITERAL)); + parser_stack_push_uint16 (context_p, context_p->last_cbc.literal_index); + parser_stack_push_uint8 (context_p, CBC_ASSIGN_PROP_THIS_LITERAL); + context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE; + } + else + { + context_p->last_cbc_opcode = CBC_PUSH_THIS_LITERAL; + parser_stack_push_uint8 (context_p, CBC_ASSIGN); + } + } + else + { + /* Invalid LeftHandSide expression. */ + parser_emit_cbc_ext (context_p, CBC_EXT_THROW_REFERENCE_ERROR); + parser_stack_push_uint8 (context_p, CBC_ASSIGN); + } + + parser_stack_push_uint8 (context_p, LEXER_ASSIGN); +} /* parser_append_binary_single_assignment_token */ + /** * Append a binary token. */ @@ -1831,97 +1934,11 @@ parser_append_binary_token (parser_context_t *context_p) /**< context */ if (context_p->token.type == LEXER_ASSIGN) { - /* Unlike other tokens, the whole byte code is saved for binary - * assignment, since it has multiple forms depending on the - * previous instruction. */ - - if (PARSER_IS_PUSH_LITERAL (context_p->last_cbc_opcode) - && context_p->last_cbc.literal_type == LEXER_IDENT_LITERAL) - { - JERRY_ASSERT (CBC_SAME_ARGS (CBC_PUSH_LITERAL, CBC_ASSIGN_SET_IDENT)); - - parser_check_invalid_assign (context_p); - - uint16_t literal_index; - - if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL) - { - literal_index = context_p->last_cbc.literal_index; - context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE; - } - else if (context_p->last_cbc_opcode == CBC_PUSH_TWO_LITERALS) - { - literal_index = context_p->last_cbc.value; - context_p->last_cbc_opcode = CBC_PUSH_LITERAL; - } - else - { - JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_THREE_LITERALS); - literal_index = context_p->last_cbc.third_literal_index; - context_p->last_cbc_opcode = CBC_PUSH_TWO_LITERALS; - } - - parser_stack_push_uint16 (context_p, literal_index); - parser_stack_push_uint8 (context_p, CBC_ASSIGN_SET_IDENT); - } - else if (context_p->last_cbc_opcode == CBC_PUSH_PROP) - { - JERRY_ASSERT (CBC_SAME_ARGS (CBC_PUSH_PROP, CBC_ASSIGN)); - parser_stack_push_uint8 (context_p, CBC_ASSIGN); - context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE; - } - else if (context_p->last_cbc_opcode == CBC_PUSH_PROP_LITERAL) - { - if (context_p->last_cbc.literal_type != LEXER_IDENT_LITERAL) - { - JERRY_ASSERT (CBC_SAME_ARGS (CBC_PUSH_PROP_LITERAL, CBC_ASSIGN_PROP_LITERAL)); - parser_stack_push_uint16 (context_p, context_p->last_cbc.literal_index); - parser_stack_push_uint8 (context_p, CBC_ASSIGN_PROP_LITERAL); - context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE; -#if ENABLED (JERRY_ES2015) - if (context_p->status_flags & PARSER_CLASS_SUPER_PROP_REFERENCE) - { - parser_emit_cbc_ext (context_p, CBC_EXT_SUPER_PROP_ASSIGN); - parser_flush_cbc (context_p); - } - context_p->status_flags &= (uint32_t) ~PARSER_CLASS_SUPER_PROP_REFERENCE; -#endif /* ENABLED (JERRY_ES2015) */ - } - else - { - context_p->last_cbc_opcode = CBC_PUSH_LITERAL; - parser_stack_push_uint8 (context_p, CBC_ASSIGN); - } - } - else if (context_p->last_cbc_opcode == CBC_PUSH_PROP_LITERAL_LITERAL) - { - JERRY_ASSERT (CBC_SAME_ARGS (CBC_PUSH_PROP_LITERAL_LITERAL, CBC_PUSH_TWO_LITERALS)); - context_p->last_cbc_opcode = CBC_PUSH_TWO_LITERALS; - parser_stack_push_uint8 (context_p, CBC_ASSIGN); - } - else if (context_p->last_cbc_opcode == CBC_PUSH_PROP_THIS_LITERAL) - { - if (context_p->last_cbc.literal_type != LEXER_IDENT_LITERAL) - { - JERRY_ASSERT (CBC_SAME_ARGS (CBC_PUSH_PROP_THIS_LITERAL, CBC_ASSIGN_PROP_THIS_LITERAL)); - parser_stack_push_uint16 (context_p, context_p->last_cbc.literal_index); - parser_stack_push_uint8 (context_p, CBC_ASSIGN_PROP_THIS_LITERAL); - context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE; - } - else - { - context_p->last_cbc_opcode = CBC_PUSH_THIS_LITERAL; - parser_stack_push_uint8 (context_p, CBC_ASSIGN); - } - } - else - { - /* Invalid LeftHandSide expression. */ - parser_emit_cbc_ext (context_p, CBC_EXT_THROW_REFERENCE_ERROR); - parser_stack_push_uint8 (context_p, CBC_ASSIGN); - } + parser_append_binary_single_assignment_token (context_p, CBC_ASSIGN_SET_IDENT); + return; } - else if (LEXER_IS_BINARY_LVALUE_TOKEN (context_p->token.type)) + + if (LEXER_IS_BINARY_LVALUE_TOKEN (context_p->token.type)) { if (PARSER_IS_PUSH_LITERAL (context_p->last_cbc_opcode) && context_p->last_cbc.literal_type == LEXER_IDENT_LITERAL) @@ -2073,6 +2090,11 @@ typedef struct lexer_token_t token; /**< token at the end position */ } parser_pattern_end_marker_t; +/** + * Literal index should not be emitted while processing rhs target value + */ +#define PARSER_PATTERN_RHS_NO_LIT UINT16_MAX + /** * Process the target of an initializer pattern. */ @@ -2097,7 +2119,8 @@ parser_pattern_get_target (parser_context_t *context_p, /**< context */ scanner_location_t start_location; if (context_p->next_scanner_info_p->source_p != context_p->source_p - || context_p->next_scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED) + || context_p->next_scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED + || (flags & PARSER_PATTERN_REST_ELEMENT)) { /* Found invalid pattern, push null value to fake the rhs target. */ parser_emit_cbc (context_p, CBC_PUSH_NULL); @@ -2148,9 +2171,14 @@ parser_pattern_finalize (parser_context_t *context_p, /**< context */ scanner_set_location (context_p, &(end_marker_p->location)); context_p->token = end_marker_p->token; } + else + { + JERRY_ASSERT (!(flags & PARSER_PATTERN_TARGET_DEFAULT)); + lexer_next_token (context_p); + } if ((flags & PARSER_PATTERN_BINDING) - && !(flags & PARSER_PATTERN_INNER_PATTERN)) + && !(flags & PARSER_PATTERN_NESTED_PATTERN)) { /* Pop the result of the expression. */ parser_emit_cbc (context_p, CBC_POP); @@ -2167,7 +2195,7 @@ parser_pattern_emit_rhs (parser_context_t *context_p, /**< context */ uint16_t rhs_opcode, /**< opcode to process the rhs value */ uint16_t literal_index) /**< literal index for object pattern */ { - if (literal_index != UINT16_MAX) + if (literal_index != PARSER_PATTERN_RHS_NO_LIT) { parser_emit_cbc_ext_literal (context_p, rhs_opcode, literal_index); } @@ -2182,21 +2210,27 @@ parser_pattern_emit_rhs (parser_context_t *context_p, /**< context */ */ static void parser_pattern_form_assignment (parser_context_t *context_p, /**< context */ + parser_pattern_flags_t flags, /**< flags */ uint16_t rhs_opcode, /**< opcode to process the rhs value */ uint16_t literal_index, /**< literal index for object pattern */ parser_line_counter_t ident_line_counter) /**< identifier line counter */ { JERRY_UNUSED (ident_line_counter); - parser_stack_push_uint8 (context_p, LEXER_EXPRESSION_START); - lexer_token_type_t current_token_type = context_p->token.type; + uint8_t assign_opcode = CBC_ASSIGN_SET_IDENT; - context_p->token.type = LEXER_ASSIGN; - parser_append_binary_token (context_p); + if (flags & PARSER_PATTERN_LEXICAL + && context_p->lit_object.index < PARSER_REGISTER_START) + { + assign_opcode = CBC_ASSIGN_LET_CONST; + } + + parser_stack_push_uint8 (context_p, LEXER_EXPRESSION_START); + parser_append_binary_single_assignment_token (context_p, assign_opcode); parser_pattern_emit_rhs (context_p, rhs_opcode, literal_index); - if (current_token_type == LEXER_ASSIGN) + if (context_p->token.type == LEXER_ASSIGN) { parser_branch_t skip_init; lexer_next_token (context_p); @@ -2206,10 +2240,6 @@ parser_pattern_form_assignment (parser_context_t *context_p, /**< context */ parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA | PARSE_EXPR_LEFT_HAND_SIDE); parser_set_branch_to_current_position (context_p, &skip_init); } - else - { - context_p->token.type = current_token_type; - } parser_process_binary_opcodes (context_p, 0); @@ -2241,23 +2271,21 @@ parser_pattern_form_assignment (parser_context_t *context_p, /**< context */ * Parse pattern inside a pattern. */ static void -parser_pattern_process_inner_pattern (parser_context_t *context_p, /**< context */ - parser_pattern_flags_t flags, /**< flags */ - uint16_t rhs_opcode, /**< opcode to process the rhs value */ - uint16_t literal_index) /**< literal index for object pattern */ +parser_pattern_process_nested_pattern (parser_context_t *context_p, /**< context */ + parser_pattern_flags_t flags, /**< flags */ + uint16_t rhs_opcode, /**< opcode to process the rhs value */ + uint16_t literal_index) /**< literal index for object pattern */ { JERRY_ASSERT (context_p->token.type == LEXER_LEFT_BRACE || context_p->token.type == LEXER_LEFT_SQUARE); - parser_pattern_flags_t options = (PARSER_PATTERN_INNER_PATTERN + parser_pattern_flags_t options = (PARSER_PATTERN_NESTED_PATTERN | PARSER_PATTERN_TARGET_ON_STACK - | (flags & PARSER_PATTERN_BINDING)); + | (flags & (PARSER_PATTERN_BINDING + | PARSER_PATTERN_LEXICAL + | PARSER_PATTERN_REST_ELEMENT))); if (context_p->next_scanner_info_p->source_p == context_p->source_p) { - if (rhs_opcode == CBC_EXT_REST_INITIALIZER) - { - parser_raise_error (context_p, PARSER_ERR_INVALID_DESTRUCTURING_PATTERN); - } options |= PARSER_PATTERN_TARGET_DEFAULT; } @@ -2272,13 +2300,77 @@ parser_pattern_process_inner_pattern (parser_context_t *context_p, /**< context parser_parse_array_initializer (context_p, options); } - if (!(options & PARSER_PATTERN_TARGET_DEFAULT)) + parser_emit_cbc (context_p, CBC_POP); +} /* parser_pattern_process_nested_pattern */ + +/** + * Process the current {Binding, Assignment}Property + */ +static void +parser_pattern_process_assignment (parser_context_t *context_p, /**< context */ + parser_pattern_flags_t flags, /**< flags */ + uint16_t rhs_opcode, /**< opcode to process the rhs value */ + uint16_t literal_index, /**< literal index for object pattern */ + lexer_token_type_t end_type) /**< end type token */ +{ + if (context_p->token.type == LEXER_LEFT_BRACE || context_p->token.type == LEXER_LEFT_SQUARE) { - lexer_next_token (context_p); + parser_pattern_process_nested_pattern (context_p, flags, rhs_opcode, literal_index); + return; } - parser_emit_cbc (context_p, CBC_POP); -} /* parser_pattern_process_inner_pattern */ + parser_line_counter_t ident_line_counter = context_p->token.line; + + if (flags & PARSER_PATTERN_BINDING) + { + if (context_p->token.type != LEXER_LITERAL || context_p->token.lit_location.type != LEXER_IDENT_LITERAL) + { + parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED); + } + + lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_IDENT_LITERAL); + + if (context_p->next_scanner_info_p->source_p == context_p->source_p) + { + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED); + parser_raise_error (context_p, PARSER_ERR_VARIABLE_REDECLARED); + } + +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + parser_module_append_export_name (context_p); +#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ + + parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL); + lexer_next_token (context_p); + + if (context_p->token.type != end_type + && context_p->token.type != LEXER_ASSIGN + && context_p->token.type != LEXER_COMMA) + { + parser_raise_error (context_p, PARSER_ERR_ILLEGAL_PROPERTY_IN_DECLARATION); + } + } + else + { + parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA | PARSE_EXPR_LEFT_HAND_SIDE); + + if (!PARSER_IS_PUSH_LITERAL (context_p->last_cbc_opcode)) + { + if (!PARSER_IS_PUSH_PROP (context_p->last_cbc_opcode) + && context_p->last_cbc_opcode != CBC_EXT_PUSH_CONSTRUCTOR_SUPER_PROP) + { + parser_raise_error (context_p, PARSER_ERR_INVALID_DESTRUCTURING_PATTERN); + } + + if (end_type == LEXER_RIGHT_SQUARE) + { + PARSER_PLUS_EQUAL_U16 (rhs_opcode, 1); + } + } + } + + parser_pattern_form_assignment (context_p, flags, rhs_opcode, literal_index, ident_line_counter); +} /* parser_pattern_process_assignment */ /** * Parse array initializer. @@ -2295,82 +2387,28 @@ parser_parse_array_initializer (parser_context_t *context_p, /**< context */ while (context_p->token.type != LEXER_RIGHT_SQUARE) { - uint16_t step_opcode = CBC_EXT_ITERATOR_STEP; + uint16_t rhs_opcode = CBC_EXT_ITERATOR_STEP; if (context_p->token.type == LEXER_COMMA) { - parser_emit_cbc_ext (context_p, step_opcode); + parser_emit_cbc_ext (context_p, rhs_opcode); parser_emit_cbc (context_p, CBC_POP); lexer_next_token (context_p); continue; } + parser_pattern_flags_t options = flags; + if (context_p->token.type == LEXER_THREE_DOTS) { lexer_next_token (context_p); - step_opcode = CBC_EXT_REST_INITIALIZER; + rhs_opcode = CBC_EXT_REST_INITIALIZER; + options |= PARSER_PATTERN_REST_ELEMENT; } - if (context_p->token.type == LEXER_LEFT_BRACE || context_p->token.type == LEXER_LEFT_SQUARE) - { - parser_pattern_process_inner_pattern (context_p, flags, step_opcode, UINT16_MAX); + parser_pattern_process_assignment (context_p, options, rhs_opcode, PARSER_PATTERN_RHS_NO_LIT, LEXER_RIGHT_SQUARE); - if (step_opcode == CBC_EXT_REST_INITIALIZER) - { - break; - } - } - else - { - parser_line_counter_t ident_line_counter = context_p->token.line; - - if (flags & PARSER_PATTERN_BINDING) - { - if (context_p->token.type != LEXER_LITERAL || context_p->token.lit_location.type != LEXER_IDENT_LITERAL) - { - parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED); - } - - lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_IDENT_LITERAL); - - if (context_p->next_scanner_info_p->source_p == context_p->source_p) - { - JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED); - parser_raise_error (context_p, PARSER_ERR_VARIABLE_REDECLARED); - } - -#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) - parser_module_append_export_name (context_p); -#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ - - parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL); - lexer_next_token (context_p); - } - else - { - parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA | PARSE_EXPR_LEFT_HAND_SIDE); - - if (!PARSER_IS_PUSH_LITERAL (context_p->last_cbc_opcode)) - { - if (!PARSER_IS_PUSH_PROP (context_p->last_cbc_opcode) - && context_p->last_cbc_opcode != CBC_EXT_PUSH_CONSTRUCTOR_SUPER_PROP) - { - parser_raise_error (context_p, PARSER_ERR_INVALID_DESTRUCTURING_PATTERN); - } - PARSER_PLUS_EQUAL_U16 (step_opcode, 1); - } - } - - if (step_opcode == CBC_EXT_REST_INITIALIZER - && context_p->token.type != LEXER_RIGHT_SQUARE) - { - parser_raise_error (context_p, PARSER_ERR_INVALID_DESTRUCTURING_PATTERN); - } - - parser_pattern_form_assignment (context_p, step_opcode, UINT16_MAX, ident_line_counter); - } - - if (context_p->token.type == LEXER_COMMA) + if (context_p->token.type == LEXER_COMMA && rhs_opcode != CBC_EXT_REST_INITIALIZER) { lexer_next_token (context_p); } @@ -2411,7 +2449,7 @@ parser_parse_object_initializer (parser_context_t *context_p, /**< context */ } else if (context_p->token.type == LEXER_RIGHT_SQUARE) { - prop_index = UINT16_MAX; + prop_index = PARSER_PATTERN_RHS_NO_LIT; push_prop_opcode = CBC_EXT_INITIALIZER_PUSH_PROP; } @@ -2432,36 +2470,19 @@ parser_parse_object_initializer (parser_context_t *context_p, /**< context */ lexer_next_token (context_p); } - bool is_inner_pattern = false; if (context_p->token.type == LEXER_COLON) { lexer_next_token (context_p); - - if (context_p->token.type == LEXER_LEFT_BRACE || context_p->token.type == LEXER_LEFT_SQUARE) - { - parser_pattern_process_inner_pattern (context_p, flags, push_prop_opcode, prop_index); - is_inner_pattern = true; - } - else - { - if (context_p->token.type != LEXER_LITERAL || context_p->token.lit_location.type != LEXER_IDENT_LITERAL) - { - parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED); - } - - lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_IDENT_LITERAL); - lexer_next_token (context_p); - } + parser_pattern_process_assignment (context_p, flags, push_prop_opcode, prop_index, LEXER_RIGHT_BRACE); } - - if (!is_inner_pattern) + else { #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) parser_module_append_export_name (context_p); #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL); - parser_pattern_form_assignment (context_p, push_prop_opcode, prop_index, start_line); + parser_pattern_form_assignment (context_p, flags, push_prop_opcode, prop_index, start_line); } if (context_p->token.type == LEXER_RIGHT_BRACE) diff --git a/jerry-core/parser/js/js-parser-internal.h b/jerry-core/parser/js/js-parser-internal.h index 46f36f924..d4432f3e6 100644 --- a/jerry-core/parser/js/js-parser-internal.h +++ b/jerry-core/parser/js/js-parser-internal.h @@ -104,11 +104,13 @@ typedef enum */ typedef enum { - PARSER_PATTERN_NO_OPTS = 0, /**< parse the expression after '=' */ - PARSER_PATTERN_BINDING = (1u << 0), /**< parse BindingPattern */ - PARSER_PATTERN_TARGET_ON_STACK = (1u << 1), /**< assignment target is the topmost element on the stack */ - PARSER_PATTERN_TARGET_DEFAULT = (1u << 2), /**< perform default value comparison for assignment target */ - PARSER_PATTERN_INNER_PATTERN = (1u << 3), /**< parse patter inside a pattern */ + PARSER_PATTERN_NO_OPTS = 0, /**< parse the expression after '=' */ + PARSER_PATTERN_BINDING = (1u << 0), /**< parse BindingPattern */ + PARSER_PATTERN_TARGET_ON_STACK = (1u << 1), /**< assignment target is the topmost element on the stack */ + PARSER_PATTERN_TARGET_DEFAULT = (1u << 3), /**< perform default value comparison for assignment target */ + PARSER_PATTERN_NESTED_PATTERN = (1u << 4), /**< parse patter inside a pattern */ + PARSER_PATTERN_LEXICAL = (1u << 5), /**< pattern is a lexical (let/const) declaration */ + PARSER_PATTERN_REST_ELEMENT = (1u << 6), /**< parse rest array initializer */ } parser_pattern_flags_t; /** diff --git a/jerry-core/parser/js/js-parser-statm.c b/jerry-core/parser/js/js-parser-statm.c index 528d06ba1..cddcae38d 100644 --- a/jerry-core/parser/js/js-parser-statm.c +++ b/jerry-core/parser/js/js-parser-statm.c @@ -451,7 +451,13 @@ parser_parse_var_statement (parser_context_t *context_p) /**< context */ || lexer_check_next_character (context_p, LIT_CHAR_LEFT_SQUARE)) { lexer_next_token (context_p); - parser_parse_initializer (context_p, PARSER_PATTERN_BINDING); + parser_pattern_flags_t options = PARSER_PATTERN_BINDING; + + if (declaration_type != LEXER_KEYW_VAR) + { + options |= PARSER_PATTERN_LEXICAL; + } + parser_parse_initializer (context_p, options); } else { diff --git a/jerry-core/parser/js/js-parser-util.c b/jerry-core/parser/js/js-parser-util.c index d41bb671b..a2128f615 100644 --- a/jerry-core/parser/js/js-parser-util.c +++ b/jerry-core/parser/js/js-parser-util.c @@ -1125,6 +1125,10 @@ parser_error_to_string (parser_error_t error) /**< error code */ { return "Invalid destructuring assignment target."; } + case PARSER_ERR_ILLEGAL_PROPERTY_IN_DECLARATION: + { + return "Illegal property in declaration context."; + } case PARSER_ERR_FORMAL_PARAM_AFTER_REST_PARAMETER: { return "Rest parameter must be the last formal parameter."; diff --git a/jerry-core/parser/js/js-parser.h b/jerry-core/parser/js/js-parser.h index 2787c2a6a..ae4feeff5 100644 --- a/jerry-core/parser/js/js-parser.h +++ b/jerry-core/parser/js/js-parser.h @@ -129,6 +129,7 @@ typedef enum PARSER_ERR_REST_PARAMETER_DEFAULT_INITIALIZER, /**< rest parameter default initializer */ PARSER_ERR_DUPLICATED_ARGUMENT_NAMES, /**< duplicated argument names */ PARSER_ERR_INVALID_DESTRUCTURING_PATTERN, /**< invalid destructuring pattern */ + PARSER_ERR_ILLEGAL_PROPERTY_IN_DECLARATION, /**< illegal property in declaration context */ #endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) PARSER_ERR_FILE_NOT_FOUND, /**< file not found*/ diff --git a/jerry-core/parser/js/js-scanner.c b/jerry-core/parser/js/js-scanner.c index 1a98d9a5d..dbbf00eab 100644 --- a/jerry-core/parser/js/js-scanner.c +++ b/jerry-core/parser/js/js-scanner.c @@ -432,6 +432,13 @@ scanner_scan_primary_expression (parser_context_t *context_p, /**< context */ scanner_raise_error (context_p); } scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + +#if ENABLED (JERRY_ES2015) + if (scanner_context_p->binding_type != SCANNER_BINDING_NONE) + { + scanner_context_p->mode = SCAN_MODE_BINDING; + } +#endif /* ENABLED (JERRY_ES2015) */ break; } case LEXER_RIGHT_PAREN: diff --git a/tests/jerry/es2015/array-pattern.js b/tests/jerry/es2015/array-pattern.js index be0400049..12093f776 100644 --- a/tests/jerry/es2015/array-pattern.js +++ b/tests/jerry/es2015/array-pattern.js @@ -58,6 +58,8 @@ checkSyntax ("[super] = []"); checkSyntax ("[this] = []"); checkSyntax ("[()] = []"); checkSyntax ("try { let [$] = $;"); +checkSyntax ("let a, [ b.c ] = [6];"); +checkSyntax ("let [(a)] = [1]"); mustThrow ("var [a] = 4"); mustThrow ("var [a] = 5"); @@ -222,3 +224,26 @@ mustThrow ("var [a] = { [Symbol.iterator] () { return { next () { return { get d assert (a === 1); assert (b === 2); }) (); + +// Force the creation of lexical environment I. +(function () { + const [a] = [1]; + eval(); + + assert (a === 1); +}) (); + +// Force the creation of lexical environment II. +(function () { + let [a] = [1]; + eval(); + + assert (a === 1); +}) (); + +// Check the parsing of AssignmentElement +(function () { + var a = 6; + [((a))] = [7]; + assert (a === 7); +}) (); diff --git a/tests/jerry/es2015/object-pattern.js b/tests/jerry/es2015/object-pattern.js index f0f71a459..73f32cf18 100644 --- a/tests/jerry/es2015/object-pattern.js +++ b/tests/jerry/es2015/object-pattern.js @@ -48,6 +48,9 @@ checkSyntax ("let {a : b, b} = []"); checkSyntax ("const {a,a} = []"); checkSyntax ("const {a : b, b} = []"); checkSyntax ("try { let {$} = $;"); +checkSyntax ("let a, { 'x': a } = {x : 4};"); +checkSyntax ("let a, { x: b.c } = {x : 6};"); +checkSyntax ("let {a:(a)} = {a:1}"); mustThrow ("var {a} = null"); mustThrow ("var {a} = undefined"); @@ -197,3 +200,26 @@ mustThrow ("var {a} = undefined"); assert (a === 1); assert (b === 2); }) (); + +// Force the creation of lexical environment I. +(function () { + const {a} = {a : 1}; + eval(); + + assert (a === 1); +}) (); + +// Force the creation of lexical environment II. +(function () { + let {a} = {a : 1}; + eval(); + + assert (a === 1); +}) (); + +// Check the parsing of AssignmentElement +(function () { + var a = 6; + ({"a": ((a)) } = {a : 7}); + assert (a === 7); +}) ();