diff --git a/jerry-core/parser/js/byte-code.c b/jerry-core/parser/js/byte-code.c index 8261055b5..e3a600c8f 100644 --- a/jerry-core/parser/js/byte-code.c +++ b/jerry-core/parser/js/byte-code.c @@ -27,7 +27,7 @@ JERRY_STATIC_ASSERT ((sizeof (cbc_uint16_arguments_t) % sizeof (jmem_cpointer_t) */ JERRY_STATIC_ASSERT (CBC_END == 238, number_of_cbc_opcodes_changed); -JERRY_STATIC_ASSERT (CBC_EXT_END == 145, +JERRY_STATIC_ASSERT (CBC_EXT_END == 149, number_of_cbc_ext_opcodes_changed); #if ENABLED (JERRY_PARSER) diff --git a/jerry-core/parser/js/byte-code.h b/jerry-core/parser/js/byte-code.h index 2aa743598..2df861152 100644 --- a/jerry-core/parser/js/byte-code.h +++ b/jerry-core/parser/js/byte-code.h @@ -763,6 +763,16 @@ CBC_OPCODE (CBC_EXT_ITERATOR_CLOSE, CBC_NO_FLAG, -1, \ VM_OC_ITERATOR_CLOSE | VM_OC_GET_STACK) \ \ + /* Object initializer related opcodes. */ \ + CBC_OPCODE (CBC_EXT_INITIALIZER_PUSH_LIST, CBC_NO_FLAG, 1, \ + VM_OC_INITIALIZER_PUSH_LIST) \ + CBC_OPCODE (CBC_EXT_INITIALIZER_PUSH_REST, CBC_NO_FLAG, 0, \ + VM_OC_INITIALIZER_PUSH_REST) \ + CBC_OPCODE (CBC_EXT_INITIALIZER_PUSH_NAME, CBC_NO_FLAG, 0, \ + VM_OC_INITIALIZER_PUSH_NAME | VM_OC_GET_STACK) \ + CBC_OPCODE (CBC_EXT_INITIALIZER_PUSH_NAME_LITERAL, CBC_HAS_LITERAL_ARG, 1, \ + VM_OC_INITIALIZER_PUSH_NAME | VM_OC_GET_LITERAL) \ + \ /* Executable object related opcodes. */ \ CBC_OPCODE (CBC_EXT_CREATE_GENERATOR, CBC_NO_FLAG, 1, \ VM_OC_CREATE_GENERATOR) \ diff --git a/jerry-core/parser/js/js-lexer.c b/jerry-core/parser/js/js-lexer.c index dd2b97da2..81ea37942 100644 --- a/jerry-core/parser/js/js-lexer.c +++ b/jerry-core/parser/js/js-lexer.c @@ -3334,7 +3334,7 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */ } case LIT_CHAR_DOT: { - if (ident_opts != LEXER_OBJ_IDENT_NO_OPTS + if ((ident_opts & ((uint32_t) ~LEXER_OBJ_IDENT_OBJECT_PATTERN)) || context_p->source_p + 2 >= context_p->source_end_p || context_p->source_p[1] != LIT_CHAR_DOT || context_p->source_p[2] != LIT_CHAR_DOT) diff --git a/jerry-core/parser/js/js-lexer.h b/jerry-core/parser/js/js-lexer.h index 67760ec98..da7b1420c 100644 --- a/jerry-core/parser/js/js-lexer.h +++ b/jerry-core/parser/js/js-lexer.h @@ -273,11 +273,11 @@ typedef enum */ typedef enum { - LEXER_OBJ_IDENT_NO_OPTS = (1u << 0), /**< no options */ - LEXER_OBJ_IDENT_ONLY_IDENTIFIERS = (1u << 1), /**< only identifiers are accepted */ - LEXER_OBJ_IDENT_CLASS_IDENTIFIER = (1u << 2), /**< expect identifier inside a class body */ - LEXER_OBJ_IDENT_CLASS_NO_STATIC = (1u << 3), /**< static keyword was not present before the identifier */ - LEXER_OBJ_IDENT_OBJECT_PATTERN = (1u << 4), /**< parse "get"/"set" as string literal in object pattern */ + LEXER_OBJ_IDENT_NO_OPTS = 0, /**< no options */ + LEXER_OBJ_IDENT_ONLY_IDENTIFIERS = (1u << 0), /**< only identifiers are accepted */ + LEXER_OBJ_IDENT_CLASS_IDENTIFIER = (1u << 1), /**< expect identifier inside a class body */ + LEXER_OBJ_IDENT_CLASS_NO_STATIC = (1u << 2), /**< static keyword was not present before the identifier */ + LEXER_OBJ_IDENT_OBJECT_PATTERN = (1u << 3), /**< parse "get"/"set" as string literal in object pattern */ } lexer_obj_ident_opts_t; /** diff --git a/jerry-core/parser/js/js-parser-expr.c b/jerry-core/parser/js/js-parser-expr.c index 938a5cf38..f7d3e2959 100644 --- a/jerry-core/parser/js/js-parser-expr.c +++ b/jerry-core/parser/js/js-parser-expr.c @@ -1146,10 +1146,15 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */ if (context_p->next_scanner_info_p->source_p == context_p->source_p) { - JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_OBJECT_LITERAL_WITH_SUPER); + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_LITERAL_FLAGS); + + if (context_p->next_scanner_info_p->u8_arg & SCANNER_LITERAL_OBJECT_HAS_SUPER) + { + parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_OBJECT_SUPER_ENVIRONMENT); + has_super_env = true; + } + scanner_release_next (context_p, sizeof (scanner_info_t)); - parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_OBJECT_SUPER_ENVIRONMENT); - has_super_env = true; } #endif /* ENABLED (JERRY_ESNEXT) */ @@ -2114,7 +2119,14 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ { if (parser_is_assignment_expr (context_p)) { - parser_parse_object_initializer (context_p, PARSER_PATTERN_NO_OPTS); + uint32_t flags = PARSER_PATTERN_NO_OPTS; + + if (context_p->next_scanner_info_p->u8_arg & SCANNER_LITERAL_OBJECT_HAS_REST) + { + flags |= PARSER_PATTERN_HAS_REST_ELEMENT; + } + + parser_parse_object_initializer (context_p, flags); return parser_abort_parsing_after_assignment_expression (context_p); } @@ -2130,15 +2142,23 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ #if ENABLED (JERRY_ESNEXT) if (context_p->next_scanner_info_p->source_p == context_p->source_p) { - JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_INITIALIZER); - - if (parser_is_assignment_expr (context_p)) + if (context_p->next_scanner_info_p->type == SCANNER_TYPE_INITIALIZER) { - parser_parse_array_initializer (context_p, PARSER_PATTERN_NO_OPTS); - return parser_abort_parsing_after_assignment_expression (context_p); - } + if (parser_is_assignment_expr (context_p)) + { + parser_parse_array_initializer (context_p, PARSER_PATTERN_NO_OPTS); + return parser_abort_parsing_after_assignment_expression (context_p); + } - scanner_release_next (context_p, sizeof (scanner_location_info_t)); + scanner_release_next (context_p, sizeof (scanner_location_info_t)); + } + else + { + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_LITERAL_FLAGS + && context_p->next_scanner_info_p->u8_arg == SCANNER_LITERAL_NO_DESTRUCTURING); + + scanner_release_next (context_p, sizeof (scanner_info_t)); + } } #endif /* ENABLED (JERRY_ESNEXT) */ @@ -3389,18 +3409,33 @@ parser_pattern_process_nested_pattern (parser_context_t *context_p, /**< context JERRY_ASSERT (context_p->next_scanner_info_p->source_p != context_p->source_p || context_p->next_scanner_info_p->type == SCANNER_TYPE_INITIALIZER - || context_p->next_scanner_info_p->type == SCANNER_TYPE_OBJECT_LITERAL_WITH_SUPER); + || context_p->next_scanner_info_p->type == SCANNER_TYPE_LITERAL_FLAGS); - if (context_p->next_scanner_info_p->source_p == context_p->source_p - && context_p->next_scanner_info_p->type == SCANNER_TYPE_INITIALIZER) + if (context_p->next_scanner_info_p->source_p == context_p->source_p) { - if (!(flags & PARSER_PATTERN_REST_ELEMENT)) + if (context_p->next_scanner_info_p->type == SCANNER_TYPE_INITIALIZER) { - options |= PARSER_PATTERN_TARGET_DEFAULT; + if (context_p->next_scanner_info_p->u8_arg & SCANNER_LITERAL_OBJECT_HAS_REST) + { + options |= PARSER_PATTERN_HAS_REST_ELEMENT; + } + + if (!(flags & PARSER_PATTERN_REST_ELEMENT)) + { + options |= PARSER_PATTERN_TARGET_DEFAULT; + } + else + { + scanner_release_next (context_p, sizeof (scanner_location_info_t)); + } } else { - scanner_release_next (context_p, sizeof (scanner_location_info_t)); + if (context_p->next_scanner_info_p->u8_arg & SCANNER_LITERAL_OBJECT_HAS_REST) + { + options |= PARSER_PATTERN_HAS_REST_ELEMENT; + } + scanner_release_next (context_p, sizeof (scanner_info_t)); } } @@ -3420,18 +3455,22 @@ parser_pattern_process_nested_pattern (parser_context_t *context_p, /**< context /** * Process the current {Binding, Assignment}Property + * + * @return true, if a nested pattern is processed, false otherwise */ -static void +static bool 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) + if ((context_p->token.type == LEXER_LEFT_BRACE || context_p->token.type == LEXER_LEFT_SQUARE) + && (context_p->next_scanner_info_p->source_p != context_p->source_p + || !(context_p->next_scanner_info_p->u8_arg & SCANNER_LITERAL_NO_DESTRUCTURING))) { parser_pattern_process_nested_pattern (context_p, flags, rhs_opcode, literal_index); - return; + return true; } parser_line_counter_t ident_line_counter = context_p->token.line; @@ -3497,6 +3536,7 @@ parser_pattern_process_assignment (parser_context_t *context_p, /**< context */ } parser_pattern_form_assignment (context_p, flags, rhs_opcode, literal_index, ident_line_counter); + return false; } /* parser_pattern_process_assignment */ /** @@ -3568,6 +3608,11 @@ parser_parse_object_initializer (parser_context_t *context_p, /**< context */ return; } + if (flags & PARSER_PATTERN_HAS_REST_ELEMENT) + { + parser_emit_cbc_ext (context_p, CBC_EXT_INITIALIZER_PUSH_LIST); + } + while (true) { lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_OBJECT_PATTERN); @@ -3581,10 +3626,41 @@ parser_parse_object_initializer (parser_context_t *context_p, /**< context */ { break; } - else if (context_p->token.type == LEXER_RIGHT_SQUARE) + + if (context_p->token.type == LEXER_THREE_DOTS) + { + lexer_next_token (context_p); + + flags |= PARSER_PATTERN_REST_ELEMENT; + + if (parser_pattern_process_assignment (context_p, + flags, + CBC_EXT_INITIALIZER_PUSH_REST, + PARSER_PATTERN_RHS_NO_LIT, + LEXER_RIGHT_BRACE)) + { + parser_raise_error (context_p, PARSER_ERR_INVALID_LHS_ASSIGNMENT); + } + + if (context_p->token.type != LEXER_RIGHT_BRACE) + { + parser_raise_error (context_p, PARSER_ERR_RIGHT_BRACE_EXPECTED); + } + + /* Checked at the end because there might be syntax errors before. */ + JERRY_ASSERT (flags & PARSER_PATTERN_HAS_REST_ELEMENT); + break; + } + + if (context_p->token.type == LEXER_RIGHT_SQUARE) { prop_index = PARSER_PATTERN_RHS_NO_LIT; - push_prop_opcode = CBC_EXT_INITIALIZER_PUSH_PROP; + push_prop_opcode = ((flags & PARSER_PATTERN_HAS_REST_ELEMENT) ? CBC_EXT_INITIALIZER_PUSH_NAME + : CBC_EXT_INITIALIZER_PUSH_PROP); + } + else if (flags & PARSER_PATTERN_HAS_REST_ELEMENT) + { + push_prop_opcode = CBC_EXT_INITIALIZER_PUSH_NAME_LITERAL; } if (context_p->next_scanner_info_p->source_p == context_p->source_p) @@ -3602,7 +3678,8 @@ parser_parse_object_initializer (parser_context_t *context_p, /**< context */ } else { - if (push_prop_opcode == CBC_EXT_INITIALIZER_PUSH_PROP) + if (push_prop_opcode == CBC_EXT_INITIALIZER_PUSH_NAME + || push_prop_opcode == CBC_EXT_INITIALIZER_PUSH_PROP) { parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED); } @@ -3681,6 +3758,22 @@ parser_parse_initializer_by_next_char (parser_context_t *context_p, /**< context if (lexer_consume_next_character (context_p) == LIT_CHAR_LEFT_BRACE) { + if (context_p->next_scanner_info_p->source_p == context_p->source_p) + { + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_INITIALIZER + || context_p->next_scanner_info_p->type == SCANNER_TYPE_LITERAL_FLAGS); + + if (context_p->next_scanner_info_p->u8_arg & SCANNER_LITERAL_OBJECT_HAS_REST) + { + flags |= PARSER_PATTERN_HAS_REST_ELEMENT; + } + + if (context_p->next_scanner_info_p->type == SCANNER_TYPE_LITERAL_FLAGS) + { + scanner_release_next (context_p, sizeof (scanner_info_t)); + } + } + parser_parse_object_initializer (context_p, flags); } else diff --git a/jerry-core/parser/js/js-parser-internal.h b/jerry-core/parser/js/js-parser-internal.h index 632473f33..b28323967 100644 --- a/jerry-core/parser/js/js-parser-internal.h +++ b/jerry-core/parser/js/js-parser-internal.h @@ -110,12 +110,13 @@ typedef enum 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_NESTED_PATTERN = (1u << 3), /**< parse patter inside a pattern */ + PARSER_PATTERN_NESTED_PATTERN = (1u << 3), /**< parse pattern inside a pattern */ PARSER_PATTERN_LET = (1u << 4), /**< pattern is a let declaration */ PARSER_PATTERN_CONST = (1u << 5), /**< pattern is a const declaration */ PARSER_PATTERN_LOCAL = (1u << 6), /**< pattern is a local (catch parameter) declaration */ - PARSER_PATTERN_REST_ELEMENT = (1u << 7), /**< parse rest array initializer */ - PARSER_PATTERN_ARGUMENTS = (1u << 8), /**< parse arguments binding */ + PARSER_PATTERN_REST_ELEMENT = (1u << 7), /**< parse rest array / object element */ + PARSER_PATTERN_HAS_REST_ELEMENT = (1u << 8), /**< object literal rest element will be present */ + PARSER_PATTERN_ARGUMENTS = (1u << 9), /**< parse arguments binding */ } parser_pattern_flags_t; /** @@ -668,6 +669,7 @@ void parser_stack_free (parser_context_t *context_p); void parser_stack_push_uint8 (parser_context_t *context_p, uint8_t uint8_value); void parser_stack_pop_uint8 (parser_context_t *context_p); void parser_stack_change_last_uint8 (parser_context_t *context_p, uint8_t new_value); +uint8_t *parser_stack_get_prev_uint8 (parser_context_t *context_p); void parser_stack_push_uint16 (parser_context_t *context_p, uint16_t uint16_value); uint16_t parser_stack_pop_uint16 (parser_context_t *context_p); void parser_stack_push (parser_context_t *context_p, const void *data_p, uint32_t length); diff --git a/jerry-core/parser/js/js-parser-mem.c b/jerry-core/parser/js/js-parser-mem.c index f999b53ff..dc03acd66 100644 --- a/jerry-core/parser/js/js-parser-mem.c +++ b/jerry-core/parser/js/js-parser-mem.c @@ -452,6 +452,26 @@ parser_stack_change_last_uint8 (parser_context_t *context_p, /**< context */ context_p->stack_top_uint8 = new_value; } /* parser_stack_change_last_uint8 */ +/** + * Get the uint8 value before the top of the stack. + * + * Pointer to the uint8 value + */ +uint8_t * +parser_stack_get_prev_uint8 (parser_context_t *context_p) /**< context */ +{ + parser_mem_page_t *page_p = context_p->stack.first_p; + + JERRY_ASSERT (page_p != NULL && (context_p->stack.last_position >= 2 || page_p->next_p != NULL)); + + if (context_p->stack.last_position >= 2) + { + return page_p->bytes + (context_p->stack.last_position - 2); + } + + return page_p->next_p->bytes + (PARSER_STACK_PAGE_SIZE - 1); +} /* parser_stack_get_prev_uint8 */ + /** * Pushes an uint16_t value onto the stack. */ diff --git a/jerry-core/parser/js/js-parser-statm.c b/jerry-core/parser/js/js-parser-statm.c index 4ba83fc8e..d2c6c6669 100644 --- a/jerry-core/parser/js/js-parser-statm.c +++ b/jerry-core/parser/js/js-parser-statm.c @@ -1430,13 +1430,21 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */ case LEXER_LEFT_SQUARE: { if (context_p->next_scanner_info_p->source_p == context_p->source_p - && context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR_PATTERN) + && context_p->next_scanner_info_p->type == SCANNER_TYPE_LITERAL_FLAGS + && (context_p->next_scanner_info_p->u8_arg & SCANNER_LITERAL_DESTRUCTURING_FOR)) { parser_emit_cbc_ext (context_p, is_for_in ? CBC_EXT_FOR_IN_GET_NEXT : CBC_EXT_FOR_OF_GET_NEXT); + uint32_t flags = PARSER_PATTERN_TARGET_ON_STACK; + + if (context_p->next_scanner_info_p->u8_arg & SCANNER_LITERAL_OBJECT_HAS_REST) + { + flags |= PARSER_PATTERN_HAS_REST_ELEMENT; + } + scanner_release_next (context_p, sizeof (scanner_info_t)); - parser_parse_initializer (context_p, PARSER_PATTERN_TARGET_ON_STACK); + parser_parse_initializer (context_p, flags); /* Pop the value returned by GET_NEXT. */ parser_emit_cbc (context_p, CBC_POP); break; diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index d33b37b14..29ba50bbd 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -1884,22 +1884,37 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */ if (context_p->next_scanner_info_p->source_p == context_p->source_p) { - if (context_p->next_scanner_info_p->type != SCANNER_TYPE_INITIALIZER) + if (context_p->next_scanner_info_p->type == SCANNER_TYPE_INITIALIZER) + { + if (context_p->next_scanner_info_p->u8_arg & SCANNER_LITERAL_OBJECT_HAS_REST) + { + flags |= PARSER_PATTERN_HAS_REST_ELEMENT; + } + + if (context_p->status_flags & PARSER_FUNCTION_HAS_REST_PARAM) + { + parser_raise_error (context_p, PARSER_ERR_REST_PARAMETER_DEFAULT_INITIALIZER); + } + + if (context_p->argument_length == UINT16_MAX) + { + context_p->argument_length = context_p->argument_count; + } + + flags |= PARSER_PATTERN_TARGET_DEFAULT; + } + else if (context_p->next_scanner_info_p->type == SCANNER_TYPE_LITERAL_FLAGS) + { + if (context_p->next_scanner_info_p->u8_arg & SCANNER_LITERAL_OBJECT_HAS_REST) + { + flags |= PARSER_PATTERN_HAS_REST_ELEMENT; + } + scanner_release_next (context_p, sizeof (scanner_info_t)); + } + else { parser_raise_error (context_p, PARSER_ERR_INVALID_DESTRUCTURING_PATTERN); } - - if (context_p->status_flags & PARSER_FUNCTION_HAS_REST_PARAM) - { - parser_raise_error (context_p, PARSER_ERR_REST_PARAMETER_DEFAULT_INITIALIZER); - } - - if (context_p->argument_length == UINT16_MAX) - { - context_p->argument_length = context_p->argument_count; - } - - flags |= PARSER_PATTERN_TARGET_DEFAULT; } parser_parse_initializer (context_p, flags); diff --git a/jerry-core/parser/js/js-scanner-internal.h b/jerry-core/parser/js/js-scanner-internal.h index ba8e4a00e..d27d791a9 100644 --- a/jerry-core/parser/js/js-scanner-internal.h +++ b/jerry-core/parser/js/js-scanner-internal.h @@ -118,7 +118,6 @@ typedef enum SCAN_STACK_FUNCTION_PARAMETERS, /**< function parameter initializer */ SCAN_STACK_FOR_START_PATTERN, /**< possible assignment pattern for "for" iterator */ SCAN_STACK_USE_ASYNC, /**< an "async" identifier is used */ - SCAN_STACK_OBJECT_LITERAL_WITH_SUPER, /**< object literal with inner super reference */ #endif /* ENABLED (JERRY_ESNEXT) */ } scan_stack_modes_t; diff --git a/jerry-core/parser/js/js-scanner-ops.c b/jerry-core/parser/js/js-scanner-ops.c index 38b048f39..a76f25b93 100644 --- a/jerry-core/parser/js/js-scanner-ops.c +++ b/jerry-core/parser/js/js-scanner-ops.c @@ -245,6 +245,9 @@ scanner_check_arrow_arg (parser_context_t *context_p, /**< context */ if (context_p->token.type == LEXER_LEFT_BRACE) { +#if ENABLED (JERRY_ESNEXT) + parser_stack_push_uint8 (context_p, 0); +#endif /* ENABLED (JERRY_ESNEXT) */ parser_stack_push_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL); scanner_context_p->mode = SCAN_MODE_PROPERTY_NAME; return; diff --git a/jerry-core/parser/js/js-scanner-util.c b/jerry-core/parser/js/js-scanner-util.c index 4d0d213e1..d3f7407c6 100644 --- a/jerry-core/parser/js/js-scanner-util.c +++ b/jerry-core/parser/js/js-scanner-util.c @@ -1916,10 +1916,9 @@ scanner_cleanup (parser_context_t *context_p) /**< context */ { #if ENABLED (JERRY_ESNEXT) JERRY_ASSERT (scanner_info_p->type == SCANNER_TYPE_END_ARGUMENTS - || scanner_info_p->type == SCANNER_TYPE_LET_EXPRESSION - || scanner_info_p->type == SCANNER_TYPE_FOR_PATTERN + || scanner_info_p->type == SCANNER_TYPE_LITERAL_FLAGS || scanner_info_p->type == SCANNER_TYPE_CLASS_CONSTRUCTOR - || scanner_info_p->type == SCANNER_TYPE_OBJECT_LITERAL_WITH_SUPER + || scanner_info_p->type == SCANNER_TYPE_LET_EXPRESSION || scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED || scanner_info_p->type == SCANNER_TYPE_ERR_ASYNC_FUNCTION || scanner_info_p->type == SCANNER_TYPE_EXPORT_MODULE_SPECIFIER); diff --git a/jerry-core/parser/js/js-scanner.c b/jerry-core/parser/js/js-scanner.c index d9d7177b4..18d4067e3 100644 --- a/jerry-core/parser/js/js-scanner.c +++ b/jerry-core/parser/js/js-scanner.c @@ -147,6 +147,7 @@ scanner_scan_primary_expression (parser_context_t *context_p, /**< context */ { #if ENABLED (JERRY_ESNEXT) scanner_push_destructuring_pattern (context_p, scanner_context_p, SCANNER_BINDING_NONE, false); + parser_stack_push_uint8 (context_p, 0); #endif /* ENABLED (JERRY_ESNEXT) */ parser_stack_push_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL); @@ -452,7 +453,6 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * return SCAN_NEXT_TOKEN; } - case SCAN_STACK_OBJECT_LITERAL_WITH_SUPER: #endif /* ENABLED (JERRY_ESNEXT) */ case SCAN_STACK_OBJECT_LITERAL: { @@ -566,7 +566,6 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_ARRAY_LITERAL || context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL - || context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL_WITH_SUPER || context_p->stack_top_uint8 == SCAN_STACK_LET || context_p->stack_top_uint8 == SCAN_STACK_CONST || context_p->stack_top_uint8 == SCAN_STACK_FOR_LET_START @@ -598,7 +597,6 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_ARRAY_LITERAL || context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL - || context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL_WITH_SUPER || context_p->stack_top_uint8 == SCAN_STACK_LET || context_p->stack_top_uint8 == SCAN_STACK_CONST || context_p->stack_top_uint8 == SCAN_STACK_FOR_LET_START @@ -607,9 +605,7 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * || context_p->stack_top_uint8 == SCAN_STACK_ARROW_ARGUMENTS); JERRY_ASSERT (SCANNER_NEEDS_BINDING_LIST (scanner_context_p->binding_type) - || (stack_top != SCAN_STACK_ARRAY_LITERAL - && stack_top != SCAN_STACK_OBJECT_LITERAL - && stack_top != SCAN_STACK_OBJECT_LITERAL_WITH_SUPER)); + || (stack_top != SCAN_STACK_ARRAY_LITERAL && stack_top != SCAN_STACK_OBJECT_LITERAL)); if (binding_literal.literal_p->type & SCANNER_LITERAL_IS_USED) { @@ -838,30 +834,46 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * #if ENABLED (JERRY_ESNEXT) case SCAN_STACK_ARRAY_LITERAL: case SCAN_STACK_OBJECT_LITERAL: - case SCAN_STACK_OBJECT_LITERAL_WITH_SUPER: { - bool is_array = stack_top == SCAN_STACK_ARRAY_LITERAL; - - if ((is_array && (type != LEXER_RIGHT_SQUARE)) - || (!is_array && (type != LEXER_RIGHT_BRACE))) + if ((stack_top == SCAN_STACK_ARRAY_LITERAL && type != LEXER_RIGHT_SQUARE) + || (stack_top == SCAN_STACK_OBJECT_LITERAL && type != LEXER_RIGHT_BRACE)) { break; } scanner_source_start_t source_start; uint8_t binding_type = scanner_context_p->binding_type; + uint8_t object_literal_flags = 0; parser_stack_pop_uint8 (context_p); + + if (stack_top == SCAN_STACK_OBJECT_LITERAL) + { + object_literal_flags = context_p->stack_top_uint8; + parser_stack_pop_uint8 (context_p); + } + scanner_context_p->binding_type = context_p->stack_top_uint8; parser_stack_pop_uint8 (context_p); parser_stack_pop (context_p, &source_start, sizeof (scanner_source_start_t)); lexer_next_token (context_p); - if (binding_type == SCANNER_BINDING_CATCH && context_p->stack_top_uint8 == SCAN_STACK_CATCH_STATEMENT) + stack_top = (scan_stack_modes_t) context_p->stack_top_uint8; + + if (binding_type == SCANNER_BINDING_CATCH && stack_top == SCAN_STACK_CATCH_STATEMENT) { scanner_pop_binding_list (scanner_context_p); +#if ENABLED (JERRY_ESNEXT) + if (object_literal_flags != 0) + { + scanner_info_t *info_p = scanner_insert_info (context_p, source_start.source_p, sizeof (scanner_info_t)); + info_p->type = SCANNER_TYPE_LITERAL_FLAGS; + info_p->u8_arg = object_literal_flags; + } +#endif /* ENABLED (JERRY_ESNEXT) */ + if (context_p->token.type != LEXER_RIGHT_PAREN) { scanner_raise_error (context_p); @@ -878,7 +890,7 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * return SCAN_NEXT_TOKEN; } - if (context_p->stack_top_uint8 == SCAN_STACK_FOR_START_PATTERN) + if (stack_top == SCAN_STACK_FOR_START_PATTERN) { JERRY_ASSERT (binding_type == SCANNER_BINDING_NONE); @@ -887,7 +899,8 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * if (context_p->token.type == LEXER_KEYW_IN || SCANNER_IDENTIFIER_IS_OF ()) { scanner_info_t *info_p = scanner_insert_info (context_p, source_start.source_p, sizeof (scanner_info_t)); - info_p->type = SCANNER_TYPE_FOR_PATTERN; + info_p->type = SCANNER_TYPE_LITERAL_FLAGS; + info_p->u8_arg = object_literal_flags | SCANNER_LITERAL_DESTRUCTURING_FOR; return SCAN_KEEP_TOKEN; } } @@ -900,12 +913,24 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * } #if ENABLED (JERRY_ESNEXT) - if (stack_top == SCAN_STACK_OBJECT_LITERAL_WITH_SUPER) + if ((stack_top == SCAN_STACK_ARRAY_LITERAL || stack_top == SCAN_STACK_OBJECT_LITERAL) + && (binding_type == SCANNER_BINDING_NONE || binding_type == SCANNER_BINDING_ARROW_ARG) + && context_p->token.type != LEXER_EOS + && context_p->token.type != LEXER_COMMA + && context_p->token.type != LEXER_RIGHT_BRACE + && context_p->token.type != LEXER_RIGHT_SQUARE) + { + object_literal_flags |= SCANNER_LITERAL_NO_DESTRUCTURING; + } + + if (object_literal_flags != 0) { scanner_info_t *info_p = scanner_insert_info (context_p, source_start.source_p, sizeof (scanner_info_t)); - info_p->type = SCANNER_TYPE_OBJECT_LITERAL_WITH_SUPER; + info_p->type = SCANNER_TYPE_LITERAL_FLAGS; + info_p->u8_arg = object_literal_flags; } #endif /* ENABLED (JERRY_ESNEXT) */ + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; return SCAN_KEEP_TOKEN; } @@ -915,6 +940,7 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * source_start.source_p, sizeof (scanner_location_info_t)); location_info_p->info.type = SCANNER_TYPE_INITIALIZER; + location_info_p->info.u8_arg = object_literal_flags; scanner_get_location (&location_info_p->location, context_p); scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; @@ -933,6 +959,17 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * return SCAN_NEXT_TOKEN; } #else /* !ENABLED (JERRY_ESNEXT) */ + case SCAN_STACK_OBJECT_LITERAL: + { + if (type != LEXER_RIGHT_BRACE) + { + break; + } + + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + parser_stack_pop_uint8 (context_p); + return SCAN_NEXT_TOKEN; + } case SCAN_STACK_ARRAY_LITERAL: #endif /* ENABLED (JERRY_ESNEXT) */ case SCAN_STACK_PROPERTY_ACCESSOR: @@ -946,19 +983,6 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * parser_stack_pop_uint8 (context_p); return SCAN_NEXT_TOKEN; } -#if !ENABLED (JERRY_ESNEXT) - case SCAN_STACK_OBJECT_LITERAL: - { - if (type != LEXER_RIGHT_BRACE) - { - break; - } - - scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; - parser_stack_pop_uint8 (context_p); - return SCAN_NEXT_TOKEN; - } -#endif /* !ENABLED (JERRY_ESNEXT) */ #if ENABLED (JERRY_ESNEXT) case SCAN_STACK_COMPUTED_PROPERTY: { @@ -1004,8 +1028,7 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * return SCAN_KEEP_TOKEN; } - JERRY_ASSERT (stack_top == SCAN_STACK_OBJECT_LITERAL - || stack_top == SCAN_STACK_OBJECT_LITERAL_WITH_SUPER); + JERRY_ASSERT (stack_top == SCAN_STACK_OBJECT_LITERAL); if (context_p->token.type == LEXER_LEFT_PAREN) { @@ -1042,7 +1065,6 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * parser_stack_pop_uint8 (context_p); JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL - || context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL_WITH_SUPER || context_p->stack_top_uint8 == SCAN_STACK_FUNCTION_PROPERTY); uint16_t status_flags = (uint16_t) (SCANNER_LITERAL_POOL_FUNCTION @@ -2149,7 +2171,7 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */ if (has_super_reference && context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL) { - parser_stack_change_last_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL_WITH_SUPER); + *parser_stack_get_prev_uint8 (context_p) |= SCANNER_LITERAL_OBJECT_HAS_SUPER; } #else /* ENABLED (JERRY_ESNEXT) */ JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL); @@ -2367,6 +2389,7 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */ return SCAN_NEXT_TOKEN; } + parser_stack_push_uint8 (context_p, 0); parser_stack_push_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL); scanner_context_p->mode = SCAN_MODE_PROPERTY_NAME; return SCAN_KEEP_TOKEN; @@ -2792,6 +2815,7 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ break; } + parser_stack_push_uint8 (context_p, 0); parser_stack_push_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL); scanner_context.mode = SCAN_MODE_PROPERTY_NAME; continue; @@ -2998,6 +3022,7 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ break; } + parser_stack_push_uint8 (context_p, 0); parser_stack_push_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL); scanner_context.mode = SCAN_MODE_PROPERTY_NAME; continue; @@ -3092,12 +3117,7 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ } case SCAN_MODE_PROPERTY_NAME: { -#if ENABLED (JERRY_ESNEXT) - JERRY_ASSERT (stack_top == SCAN_STACK_OBJECT_LITERAL - || stack_top == SCAN_STACK_OBJECT_LITERAL_WITH_SUPER); -#else /* !ENABLED (JERRY_ESNEXT) */ JERRY_ASSERT (stack_top == SCAN_STACK_OBJECT_LITERAL); -#endif /* ENABLED (JERRY_ESNEXT) */ if (lexer_scan_identifier (context_p)) { @@ -3114,6 +3134,7 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ if (context_p->token.type == LEXER_THREE_DOTS) { + *parser_stack_get_prev_uint8 (context_p) |= SCANNER_LITERAL_OBJECT_HAS_REST; scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION; if (scanner_context.binding_type != SCANNER_BINDING_NONE) @@ -3281,6 +3302,7 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ break; } + parser_stack_push_uint8 (context_p, 0); parser_stack_push_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL); scanner_context.mode = SCAN_MODE_PROPERTY_NAME; continue; @@ -3729,15 +3751,13 @@ scan_completed: #if ENABLED (JERRY_ESNEXT) case SCANNER_TYPE_INITIALIZER: { - name_p = "INITIALIZER"; - print_location = true; - break; - } - case SCANNER_TYPE_FOR_PATTERN: - { - JERRY_DEBUG_MSG (" SCANNER_TYPE_FOR_PATTERN: source:%d\n", - (int) (info_p->source_p - source_start_p)); - print_location = false; + scanner_location_info_t *location_info_p = (scanner_location_info_t *) info_p; + JERRY_DEBUG_MSG (" INITIALIZER: flags: 0x%x source:%d location:%d[%d:%d]\n", + (int) info_p->u8_arg, + (int) (location_info_p->info.source_p - source_start_p), + (int) (location_info_p->location.source_p - source_start_p), + (int) location_info_p->location.line, + (int) location_info_p->location.column); break; } case SCANNER_TYPE_CLASS_CONSTRUCTOR: @@ -3771,9 +3791,10 @@ scan_completed: (int) (info_p->source_p - source_start_p)); break; } - case SCANNER_TYPE_OBJECT_LITERAL_WITH_SUPER: + case SCANNER_TYPE_LITERAL_FLAGS: { - JERRY_DEBUG_MSG (" OBJECT_LITERAL_WITH_SUPER: source:%d\n", + JERRY_DEBUG_MSG (" SCANNER_TYPE_LITERAL_FLAGS: flags: 0x%x source:%d\n", + (int) info_p->u8_arg, (int) (info_p->source_p - source_start_p)); print_location = false; break; diff --git a/jerry-core/parser/js/js-scanner.h b/jerry-core/parser/js/js-scanner.h index 2d0b26a5d..91db12fb2 100644 --- a/jerry-core/parser/js/js-scanner.h +++ b/jerry-core/parser/js/js-scanner.h @@ -46,13 +46,12 @@ typedef enum SCANNER_TYPE_CASE, /**< case statement */ #if ENABLED (JERRY_ESNEXT) SCANNER_TYPE_INITIALIZER, /**< destructuring binding or assignment pattern with initializer */ - SCANNER_TYPE_FOR_PATTERN, /**< assignment pattern for for-in or for-of interators */ + SCANNER_TYPE_LITERAL_FLAGS, /**< object or array literal with non-zero flags (stored in u8_arg) */ SCANNER_TYPE_CLASS_CONSTRUCTOR, /**< class constructor */ SCANNER_TYPE_CLASS_FIELD_INITIALIZER_END, /**< class field initializer end */ SCANNER_TYPE_LET_EXPRESSION, /**< let expression */ SCANNER_TYPE_ERR_REDECLARED, /**< syntax error: a variable is redeclared */ SCANNER_TYPE_ERR_ASYNC_FUNCTION, /**< an invalid async function follows */ - SCANNER_TYPE_OBJECT_LITERAL_WITH_SUPER, /**< object literal with inner super reference */ SCANNER_TYPE_EXPORT_MODULE_SPECIFIER, /**< export with module specifier */ #endif /* ENABLED (JERRY_ESNEXT) */ } scanner_info_type_t; @@ -261,6 +260,23 @@ typedef enum SCANNER_FUNCTION_IS_STRICT = (1 << 5), /**< function is strict */ } scanner_function_flags_t; +#if ENABLED (JERRY_ESNEXT) + +/** + * Object or array literal constants for u8_arg flags in scanner_info_t. + */ +typedef enum +{ + /* These flags affects both array and object literals */ + SCANNER_LITERAL_DESTRUCTURING_FOR = (1 << 0), /**< for loop with destructuring pattern */ + SCANNER_LITERAL_NO_DESTRUCTURING = (1 << 1), /**< this literal cannot be a destructuring pattern */ + /* These flags affects only object literals */ + SCANNER_LITERAL_OBJECT_HAS_SUPER = (1 << 2), /**< super keyword is used in the object literal */ + SCANNER_LITERAL_OBJECT_HAS_REST = (1 << 3), /**< the object literal has a member prefixed with three dots */ +} scanner_literal_flags_t; + +#endif /* ENABLED (JERRY_ESNEXT) */ + /** * Option bits for scanner_create_variables function. */ diff --git a/jerry-core/vm/opcodes.c b/jerry-core/vm/opcodes.c index 13d14c1be..4613571ec 100644 --- a/jerry-core/vm/opcodes.c +++ b/jerry-core/vm/opcodes.c @@ -601,10 +601,7 @@ opfunc_append_array (ecma_value_t *stack_top_p, /**< current stack top */ { filled_holes++; - if (ecma_is_value_object (stack_top_p[i])) - { - ecma_deref_object (ecma_get_object_from_value (stack_top_p[i])); - } + ecma_deref_if_object (stack_top_p[i]); } } @@ -632,16 +629,10 @@ opfunc_append_array (ecma_value_t *stack_top_p, /**< current stack top */ ecma_deref_ecma_string (index_str_p); prop_value_p->value = stack_top_p[i]; - - if (ecma_is_value_object (stack_top_p[i])) - { - ecma_free_value (stack_top_p[i]); - } - + ecma_deref_if_object (stack_top_p[i]); } - - ext_array_obj_p->u.array.length = old_length + values_length; } + ext_array_obj_p->u.array.length = old_length + values_length; } return ECMA_VALUE_EMPTY; @@ -1687,6 +1678,137 @@ opfunc_assign_super_reference (ecma_value_t **vm_stack_top_p, /**< vm stack top return result; } /* opfunc_assign_super_reference */ + +/** + * Copy data properties of an object + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_EMPTY - otherwise + */ +ecma_value_t +opfunc_copy_data_properties (ecma_value_t target_object, /**< target object */ + ecma_value_t source_object, /**< source object */ + ecma_value_t filter_array) /**< filter array */ +{ + bool source_to_object = false; + + if (!ecma_is_value_object (source_object)) + { + source_object = ecma_op_to_object (source_object); + + if (ECMA_IS_VALUE_ERROR (source_object)) + { + return source_object; + } + + source_to_object = true; + } + + ecma_object_t *source_object_p = ecma_get_object_from_value (source_object); + ecma_collection_t *names_p = ecma_op_object_own_property_keys (source_object_p); + +#if ENABLED (JERRY_BUILTIN_PROXY) + if (names_p == NULL) + { + JERRY_ASSERT (!source_to_object); + return ECMA_VALUE_ERROR; + } +#endif /* ENABLED (JERRY_BUILTIN_PROXY) */ + + ecma_object_t *target_object_p = ecma_get_object_from_value (target_object); + ecma_value_t *buffer_p = names_p->buffer_p; + ecma_value_t *buffer_end_p = buffer_p + names_p->item_count; + ecma_value_t *filter_start_p = NULL; + ecma_value_t *filter_end_p = NULL; + ecma_value_t result = ECMA_VALUE_EMPTY; + + if (filter_array != ECMA_VALUE_UNDEFINED) + { + ecma_object_t *filter_array_p = ecma_get_object_from_value (filter_array); + + JERRY_ASSERT (ecma_get_object_type (filter_array_p) == ECMA_OBJECT_TYPE_ARRAY); + JERRY_ASSERT (ecma_op_object_is_fast_array (filter_array_p)); + + if (filter_array_p->u1.property_list_cp != JMEM_CP_NULL) + { + filter_start_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, filter_array_p->u1.property_list_cp); + filter_end_p = filter_start_p + ((ecma_extended_object_t *) filter_array_p)->u.array.length; + } + } + + while (buffer_p < buffer_end_p) + { + ecma_string_t *property_name_p = ecma_get_prop_name_from_value (*buffer_p++); + + if (filter_start_p != NULL) + { + ecma_value_t *filter_p = filter_start_p; + + do + { + if (ecma_compare_ecma_strings (property_name_p, ecma_get_prop_name_from_value (*filter_p))) + { + break; + } + } + while (++filter_p < filter_end_p); + + if (filter_p != filter_end_p) + { + continue; + } + } + + ecma_property_descriptor_t descriptor; + result = ecma_op_object_get_own_property_descriptor (source_object_p, property_name_p, &descriptor); + + if (ECMA_IS_VALUE_ERROR (result)) + { + break; + } + + if (result == ECMA_VALUE_FALSE) + { + continue; + } + + if (!(descriptor.flags & ECMA_PROP_IS_ENUMERABLE)) + { + ecma_free_property_descriptor (&descriptor); + continue; + } + + if ((descriptor.flags & ECMA_PROP_IS_VALUE_DEFINED) && !ECMA_OBJECT_IS_PROXY (source_object_p)) + { + result = descriptor.value; + } + else + { + ecma_free_property_descriptor (&descriptor); + + result = ecma_op_object_get (source_object_p, property_name_p); + + if (ECMA_IS_VALUE_ERROR (result)) + { + break; + } + } + + opfunc_set_data_property (target_object_p, property_name_p, result); + ecma_free_value (result); + + result = ECMA_VALUE_EMPTY; + } + + if (JERRY_UNLIKELY (source_to_object)) + { + ecma_deref_object (source_object_p); + } + + ecma_collection_free (names_p); + return result; +} /* opfunc_copy_data_properties */ + #endif /* ENABLED (JERRY_ESNEXT) */ /** diff --git a/jerry-core/vm/opcodes.h b/jerry-core/vm/opcodes.h index 97140cee4..70f114989 100644 --- a/jerry-core/vm/opcodes.h +++ b/jerry-core/vm/opcodes.h @@ -131,6 +131,7 @@ ecma_value_t opfunc_append_array (ecma_value_t *stack_top_p, uint16_t values_length); #if ENABLED (JERRY_ESNEXT) + vm_executable_object_t * opfunc_create_executable_object (vm_frame_ctx_t *frame_ctx_p, vm_create_executable_object_type_t type); @@ -179,6 +180,10 @@ opfunc_form_super_reference (ecma_value_t **vm_stack_top_p, vm_frame_ctx_t *fram ecma_value_t opfunc_assign_super_reference (ecma_value_t **vm_stack_top_p, vm_frame_ctx_t *frame_ctx_p, uint32_t opcode_data); + +ecma_value_t +opfunc_copy_data_properties (ecma_value_t target_object, ecma_value_t source_object, ecma_value_t filter_array); + #endif /* ENABLED (JERRY_ESNEXT) */ /** diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index 02d36729e..fdd37d07f 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -1887,61 +1887,21 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } case VM_OC_COPY_DATA_PROPERTIES: { - result = *(--stack_top_p); + left_value = *(--stack_top_p); - if (ecma_is_value_undefined (result) || ecma_is_value_null (result)) + if (ecma_is_value_undefined (left_value) || ecma_is_value_null (left_value)) { continue; } - if (!ecma_is_value_object (result)) + result = opfunc_copy_data_properties (stack_top_p[-1], left_value, ECMA_VALUE_UNDEFINED); + + if (ECMA_IS_VALUE_ERROR (result)) { - ecma_value_t value = result; - result = ecma_op_to_object (value); - ecma_free_value (value); - - if (ECMA_IS_VALUE_ERROR (result)) - { - goto error; - } - } - - ecma_object_t *object_p = ecma_get_object_from_value (result); - ecma_collection_t *names_p = ecma_op_object_get_enumerable_property_names (object_p, - ECMA_ENUMERABLE_PROPERTY_KEYS); - -#if ENABLED (JERRY_BUILTIN_PROXY) - if (names_p == NULL) - { - ecma_deref_object (object_p); - result = ECMA_VALUE_ERROR; goto error; } -#endif /* ENABLED (JERRY_BUILTIN_PROXY) */ - ecma_object_t *target_object_p = ecma_get_object_from_value (stack_top_p[-1]); - ecma_value_t *buffer_p = names_p->buffer_p; - ecma_value_t *buffer_end_p = buffer_p + names_p->item_count; - - while (buffer_p < buffer_end_p) - { - ecma_string_t *property_name_p = ecma_get_string_from_value (*buffer_p++); - result = ecma_op_object_get (object_p, property_name_p); - - if (ECMA_IS_VALUE_ERROR (result)) - { - ecma_collection_free (names_p); - ecma_deref_object (object_p); - goto error; - } - - opfunc_set_data_property (target_object_p, property_name_p, result); - ecma_free_value (result); - } - - ecma_collection_free (names_p); - ecma_deref_object (object_p); - continue; + goto free_left_value; } case VM_OC_SET_COMPUTED_PROPERTY: { @@ -2438,6 +2398,60 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ *stack_top_p++ = ecma_make_object_value (array_p); continue; } + case VM_OC_INITIALIZER_PUSH_LIST: + { + stack_top_p++; + stack_top_p[-1] = stack_top_p[-2]; + stack_top_p[-2] = ecma_make_object_value (ecma_op_new_array_object (0)); + continue; + } + case VM_OC_INITIALIZER_PUSH_REST: + { + if (!ecma_op_require_object_coercible (stack_top_p[-1])) + { + result = ECMA_VALUE_ERROR; + goto error; + } + + ecma_object_t *prototype_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE); + ecma_object_t *result_object_p = ecma_create_object (prototype_p, 0, ECMA_OBJECT_TYPE_GENERAL); + + left_value = ecma_make_object_value (result_object_p); + result = opfunc_copy_data_properties (left_value, stack_top_p[-1], stack_top_p[-2]); + + if (ECMA_IS_VALUE_ERROR (result)) + { + goto error; + } + + ecma_free_value (stack_top_p[-2]); + stack_top_p[-2] = stack_top_p[-1]; + stack_top_p[-1] = left_value; + continue; + } + case VM_OC_INITIALIZER_PUSH_NAME: + { + if (JERRY_UNLIKELY (!ecma_is_value_prop_name (left_value))) + { + ecma_string_t *property_key = ecma_op_to_property_key (left_value); + + if (property_key == NULL) + { + result = ECMA_VALUE_ERROR; + goto error; + } + + ecma_free_value (left_value); + left_value = ecma_make_string_value (property_key); + } + + ecma_object_t *array_obj_p = ecma_get_object_from_value (stack_top_p[-2]); + JERRY_ASSERT (ecma_get_object_type (array_obj_p) == ECMA_OBJECT_TYPE_ARRAY); + + ecma_extended_object_t *ext_array_obj_p = (ecma_extended_object_t *) array_obj_p; + ecma_fast_array_set_property (array_obj_p, ext_array_obj_p->u.array.length, left_value); + /* FALLTHRU */ + } case VM_OC_INITIALIZER_PUSH_PROP: { result = vm_op_get_value (stack_top_p[-1], left_value); diff --git a/jerry-core/vm/vm.h b/jerry-core/vm/vm.h index 80d530abb..4def5c07e 100644 --- a/jerry-core/vm/vm.h +++ b/jerry-core/vm/vm.h @@ -278,6 +278,9 @@ typedef enum VM_OC_GET_ITERATOR, /**< GetIterator abstract operation */ VM_OC_ITERATOR_STEP, /**< IteratorStep abstract operation */ VM_OC_ITERATOR_CLOSE, /**< IteratorClose abstract operation */ + VM_OC_INITIALIZER_PUSH_LIST, /**< push name list array */ + VM_OC_INITIALIZER_PUSH_REST, /**< push the object with the rest properties */ + VM_OC_INITIALIZER_PUSH_NAME, /**< append string to name list array and push the string */ VM_OC_DEFAULT_INITIALIZER, /**< default initializer inside a pattern */ VM_OC_REST_INITIALIZER, /**< create rest object inside an array pattern */ VM_OC_INITIALIZER_PUSH_PROP, /**< push property for object initializer */ @@ -363,6 +366,9 @@ typedef enum VM_OC_GET_ITERATOR = VM_OC_NONE, /**< GetIterator abstract operation */ VM_OC_ITERATOR_STEP = VM_OC_NONE, /**< IteratorStep abstract operation */ VM_OC_ITERATOR_CLOSE = VM_OC_NONE, /**< IteratorClose abstract operation */ + VM_OC_INITIALIZER_PUSH_LIST = VM_OC_NONE, /**< push name list array */ + VM_OC_INITIALIZER_PUSH_REST = VM_OC_NONE, /**< push the object with the rest properties */ + VM_OC_INITIALIZER_PUSH_NAME = VM_OC_NONE, /**< append string to name list array and push the string */ VM_OC_DEFAULT_INITIALIZER = VM_OC_NONE, /**< default initializer inside a pattern */ VM_OC_REST_INITIALIZER = VM_OC_NONE, /**< create rest object inside an array pattern */ VM_OC_INITIALIZER_PUSH_PROP = VM_OC_NONE, /**< push property for object initializer */ diff --git a/tests/jerry/es.next/object-copy-data.js b/tests/jerry/es.next/object-copy-data.js index 9e5db3e06..2bbf336c5 100644 --- a/tests/jerry/es.next/object-copy-data.js +++ b/tests/jerry/es.next/object-copy-data.js @@ -63,6 +63,6 @@ var sym = Symbol('Any') s = [ { [sym]:5, a:6 } ] o = { ...((s))[0] } -assert(o[sym] === undefined) +assert(o[sym] === 5) assert(o.a === 6) checkOwnProperties(o, ["a"]) diff --git a/tests/jerry/es.next/object-pattern.js b/tests/jerry/es.next/object-pattern.js index e4165ec88..d69c7e802 100644 --- a/tests/jerry/es.next/object-pattern.js +++ b/tests/jerry/es.next/object-pattern.js @@ -32,9 +32,6 @@ function mustThrow (str) { checkSyntax ("var {a}"); checkSyntax ("var {a, o.a}"); -checkSyntax ("var {a, ...b}"); -checkSyntax ("var {a, ...b} = 4"); -checkSyntax ("var {a, ...[b] = 4}"); checkSyntax ("var {a,,} = 4"); checkSyntax ("var {a :} = 4"); checkSyntax ("var {a : ,} = 4"); diff --git a/tests/jerry/es.next/object-pattern2.js b/tests/jerry/es.next/object-pattern2.js new file mode 100644 index 000000000..6a667c116 --- /dev/null +++ b/tests/jerry/es.next/object-pattern2.js @@ -0,0 +1,137 @@ +/* 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 checkSyntax (str) { + try { + eval (str); + assert (false); + } catch (e) { + assert (e instanceof SyntaxError); + } +} + +checkSyntax ("var {a, ...b, a} = {}") +checkSyntax ("var {a, ...b = 6} = {}") +checkSyntax ("var {a, ...[b]} = {}") +checkSyntax ("function f({a, ...a}) {}") +checkSyntax ("let {a, ...a} = {}") +checkSyntax ("let {a, ...(b)} = {}") +checkSyntax ("({a, ...{b}} = {})") +checkSyntax ("({a, ...([b])} = {})") +checkSyntax ("({a, ...b().a = 6} = {})") +checkSyntax ("try {} catch ({ ...a } = {}) {}") +checkSyntax ("for ({ ...a } = {} of []) {}") + +var sym1 = Symbol("sym1") +var sym2 = Symbol("sym2") + +function rest_compare(rest, values) +{ + var keys = Reflect.ownKeys(rest); + + assert(keys.length * 2 === values.length) + + for (var i = 0; i < keys.length; i++) { + key = keys[i] + assert(key === values[i * 2]) + assert(rest[key] === values[i * 2 + 1]) + } +} + +function f1() { + var { bb, ...rest } = { a:true, bb:6.25, [sym1]:"X" } + + assert(bb === 6.25) + rest_compare(rest, ["a", true, sym1, "X"]) +} +f1() + +function f2() { + var a, b, rest = {}; + + ({ a, "+": b, ...rest.c } = { "+": -3.75, [sym1]:6.25, [sym2]: sym2 }) + + assert(a === undefined) + assert(b === -3.75) + rest_compare(rest.c, [sym1, 6.25, sym2, sym2]) +} +f2() + +function f3() { + var a, rest1, rest2; + + ({ A:{ [sym2]: a, ...rest1 }, B:{ ...rest2 } = { X:null, 7:"A" } } = { A:{ [sym1]: 7.5, [sym2]: 3.5, S:-5.5 } }) + + assert(a === 3.5) + rest_compare(rest1, ["S", -5.5, sym1, 7.5]) + rest_compare(rest2, ["7", "A", "X", null]) +} +f3() + +function f4() { + try { + throw { A:5, [sym1]:6, [sym2]:7, b:8 } + assert(false) + } catch({ b, c, ...rest }) { + assert(b === 8) + assert(c === undefined) + rest_compare(rest, ["A", 5, sym1, 6, sym2, 7]) + } +} +f4() + +function f5() { + var a = {}, b = {}, c = {}, d = () => c + + for ({ A:a.x, B:b.y, ...d().z } of [ { B:"AA", C:6.25, [sym1]:-4.5 } ]) { + assert(a.x === undefined) + assert(typeof Object.getOwnPropertyDescriptor(a, "x") === "object") + assert(b.y === "AA") + rest_compare(c.z, ["C", 6.25, sym1, -4.5]) + } +} +f5() + +function f6({ [(() => "A")() + "A"]:a, ...b }, + { A:c, [sym1]:d, [sym2]:e, ...f } = { A:"X", [sym2]: 5.5 }) { + assert(a === 6) + rest_compare(b, ["B", 7, sym1, 8.25]) + assert(c === "X") + assert(d === undefined) + assert(e === 5.5) + rest_compare(f, []) +} +f6({ [sym1]:8.25, B:7, AA:6 }) + +function f7() { + var b, o = {}, rest + + ({ ["A" + "A"]:b, ...{o}.o.rest } = { [sym1]:5.5, A:"X", AA:-0.25 }) + + assert(b === -0.25) + rest_compare(o.rest, [ "A", "X", sym1, 5.5]) +} +f7() + +function f8() { + var a, b; + + ({ ...(b) } = { }) + rest_compare(b, []); + + [a,a,...{ ...b }] = ["A", "B", "C", "D"] + rest_compare(b, ["0", "C", "1", "D"]) +} +f8() diff --git a/tests/test262-esnext-excludelist.xml b/tests/test262-esnext-excludelist.xml index 33fb30f21..af5e89b0d 100644 --- a/tests/test262-esnext-excludelist.xml +++ b/tests/test262-esnext-excludelist.xml @@ -436,9 +436,6 @@ - - - @@ -461,10 +458,6 @@ - - - - @@ -783,9 +776,6 @@ - - - @@ -808,12 +798,8 @@ - - - - @@ -7434,60 +7420,6 @@ features: [object-rest, object-spread] https://github.com/tc39/proposal-object-rest-spread --> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -7500,30 +7432,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - @@ -7552,65 +7460,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -7623,30 +7472,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - @@ -7675,49 +7500,10 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -7730,70 +7516,15 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -