From 8956eff2bd36aeddf01b2a21d68230609fe319a6 Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Fri, 29 Nov 2019 12:28:51 +0100 Subject: [PATCH] Implement generator support for object initializers and classes. (#3372) Large part of the code is also reworked. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- jerry-core/parser/js/js-lexer.c | 225 ++++++++++---------- jerry-core/parser/js/js-lexer.h | 5 - jerry-core/parser/js/js-parser-expr.c | 128 ++++++----- jerry-core/parser/js/js-parser-internal.h | 6 + jerry-core/parser/js/js-parser-statm.c | 4 +- jerry-core/parser/js/js-scanner.c | 90 +++++++- tests/jerry/es2015/generator-initializer.js | 138 ++++++++++++ 7 files changed, 411 insertions(+), 185 deletions(-) create mode 100644 tests/jerry/es2015/generator-initializer.js diff --git a/jerry-core/parser/js/js-lexer.c b/jerry-core/parser/js/js-lexer.c index 37070ab2c..d57a9224f 100644 --- a/jerry-core/parser/js/js-lexer.c +++ b/jerry-core/parser/js/js-lexer.c @@ -323,7 +323,7 @@ lexer_skip_empty_statements (parser_context_t *context_p) /**< context */ while (context_p->source_p < context_p->source_end_p && *context_p->source_p == LIT_CHAR_SEMICOLON) { - context_p->source_p++; + lexer_consume_next_character (context_p); lexer_skip_spaces (context_p); } @@ -1472,7 +1472,7 @@ lexer_check_next_characters (parser_context_t *context_p, /**< context */ * * @return consumed character */ -uint8_t +inline uint8_t JERRY_ATTR_ALWAYS_INLINE lexer_consume_next_character (parser_context_t *context_p) { JERRY_ASSERT (context_p->source_p < context_p->source_end_p); @@ -2171,6 +2171,8 @@ lexer_construct_function_object (parser_context_t *context_p, /**< context */ parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED); } + parser_flush_cbc (context_p); + if (context_p->status_flags & (PARSER_RESOLVE_BASE_FOR_CALLS | PARSER_INSIDE_WITH)) { extra_status_flags |= PARSER_RESOLVE_BASE_FOR_CALLS; @@ -2490,6 +2492,11 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */ { lexer_skip_spaces (context_p); + if (context_p->source_p >= context_p->source_end_p) + { + parser_raise_error (context_p, PARSER_ERR_PROPERTY_IDENTIFIER_EXPECTED); + } + #if ENABLED (JERRY_ES2015) int is_class_method = ((ident_opts & LEXER_OBJ_IDENT_CLASS_METHOD) && !(ident_opts & LEXER_OBJ_IDENT_ONLY_IDENTIFIERS) @@ -2498,115 +2505,130 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */ context_p->token.line = context_p->line; context_p->token.column = context_p->column; + bool create_literal_object = false; - if (context_p->source_p < context_p->source_end_p) + if (lit_char_is_identifier_start (context_p->source_p) || context_p->source_p[0] == LIT_CHAR_BACKSLASH) { - bool create_literal_object = false; + lexer_parse_identifier (context_p, false); - if (lit_char_is_identifier_start (context_p->source_p) || context_p->source_p[0] == LIT_CHAR_BACKSLASH) + if (!(ident_opts & (LEXER_OBJ_IDENT_ONLY_IDENTIFIERS | LEXER_OBJ_IDENT_OBJECT_PATTERN)) + && context_p->token.lit_location.length == 3) { - lexer_parse_identifier (context_p, false); + lexer_skip_spaces (context_p); + context_p->token.flags = (uint8_t) (context_p->token.flags | LEXER_NO_SKIP_SPACES); - if (!(ident_opts & (LEXER_OBJ_IDENT_ONLY_IDENTIFIERS | LEXER_OBJ_IDENT_OBJECT_PATTERN)) - && context_p->token.lit_location.length == 3) - { - lexer_skip_spaces (context_p); - context_p->token.flags = (uint8_t) (context_p->token.flags | LEXER_NO_SKIP_SPACES); - - if (context_p->source_p < context_p->source_end_p + if (context_p->source_p < context_p->source_end_p #if ENABLED (JERRY_ES2015) - && context_p->source_p[0] != LIT_CHAR_COMMA - && context_p->source_p[0] != LIT_CHAR_RIGHT_BRACE - && context_p->source_p[0] != LIT_CHAR_LEFT_PAREN + && context_p->source_p[0] != LIT_CHAR_COMMA + && context_p->source_p[0] != LIT_CHAR_RIGHT_BRACE + && context_p->source_p[0] != LIT_CHAR_LEFT_PAREN #endif /* ENABLED (JERRY_ES2015) */ - && context_p->source_p[0] != LIT_CHAR_COLON) + && context_p->source_p[0] != LIT_CHAR_COLON) + { + if (lexer_compare_literal_to_string (context_p, "get", 3)) { - if (lexer_compare_literal_to_string (context_p, "get", 3)) - { - context_p->token.type = LEXER_PROPERTY_GETTER; - return; - } - else if (lexer_compare_literal_to_string (context_p, "set", 3)) - { - context_p->token.type = LEXER_PROPERTY_SETTER; - return; - } + context_p->token.type = LEXER_PROPERTY_GETTER; + return; + } + else if (lexer_compare_literal_to_string (context_p, "set", 3)) + { + context_p->token.type = LEXER_PROPERTY_SETTER; + return; } } + } #if ENABLED (JERRY_ES2015) - if (is_class_method && lexer_compare_literal_to_string (context_p, "static", 6)) - { - context_p->token.type = LEXER_KEYW_STATIC; - return; - } -#endif /* ENABLED (JERRY_ES2015) */ - - create_literal_object = true; - } - else if (context_p->source_p[0] == LIT_CHAR_DOUBLE_QUOTE - || context_p->source_p[0] == LIT_CHAR_SINGLE_QUOTE) + if (is_class_method && lexer_compare_literal_to_string (context_p, "static", 6)) { - lexer_parse_string (context_p); - create_literal_object = true; - } -#if ENABLED (JERRY_ES2015) - else if (context_p->source_p[0] == LIT_CHAR_LEFT_SQUARE) - { - context_p->source_p += 1; - context_p->column++; - - lexer_next_token (context_p); - parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA); - - if (context_p->token.type != LEXER_RIGHT_SQUARE) - { - parser_raise_error (context_p, PARSER_ERR_RIGHT_SQUARE_EXPECTED); - } + context_p->token.type = LEXER_KEYW_STATIC; return; } #endif /* ENABLED (JERRY_ES2015) */ - else if (!(ident_opts & LEXER_OBJ_IDENT_ONLY_IDENTIFIERS) && context_p->source_p[0] == LIT_CHAR_RIGHT_BRACE) - { - context_p->token.type = LEXER_RIGHT_BRACE; - context_p->source_p += 1; - context_p->column++; - return; - } - else - { - const uint8_t *char_p = context_p->source_p; - if (char_p[0] == LIT_CHAR_DOT) + create_literal_object = true; + } + else + { + switch (context_p->source_p[0]) + { + case LIT_CHAR_DOUBLE_QUOTE: + case LIT_CHAR_SINGLE_QUOTE: { - char_p++; + lexer_parse_string (context_p); + create_literal_object = true; + break; } - - if (char_p < context_p->source_end_p - && char_p[0] >= LIT_CHAR_0 - && char_p[0] <= LIT_CHAR_9) - { - lexer_parse_number (context_p); - lexer_construct_number_object (context_p, false, false); - return; - } - } - - if (create_literal_object) - { #if ENABLED (JERRY_ES2015) - if (is_class_method && lexer_compare_literal_to_string (context_p, "constructor", 11)) + case LIT_CHAR_LEFT_SQUARE: { - context_p->token.type = LEXER_CLASS_CONSTRUCTOR; + lexer_consume_next_character (context_p); + + lexer_next_token (context_p); + parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA); + + if (context_p->token.type != LEXER_RIGHT_SQUARE) + { + parser_raise_error (context_p, PARSER_ERR_RIGHT_SQUARE_EXPECTED); + } return; } + case LIT_CHAR_ASTERISK: +#endif /* ENABLED (JERRY_ES2015) */ + case LIT_CHAR_RIGHT_BRACE: + { + if (ident_opts & LEXER_OBJ_IDENT_ONLY_IDENTIFIERS) + { + break; + } + + context_p->token.type = LEXER_RIGHT_BRACE; +#if ENABLED (JERRY_ES2015) + if (context_p->source_p[0] == LIT_CHAR_ASTERISK) + { + context_p->token.type = LEXER_MULTIPLY; + } #endif /* ENABLED (JERRY_ES2015) */ - lexer_construct_literal_object (context_p, - &context_p->token.lit_location, - LEXER_STRING_LITERAL); + lexer_consume_next_character (context_p); + return; + } + default: + { + const uint8_t *char_p = context_p->source_p; + + if (char_p[0] == LIT_CHAR_DOT) + { + char_p++; + } + + if (char_p < context_p->source_end_p + && char_p[0] >= LIT_CHAR_0 + && char_p[0] <= LIT_CHAR_9) + { + lexer_parse_number (context_p); + lexer_construct_number_object (context_p, false, false); + return; + } + break; + } + } + } + + if (create_literal_object) + { +#if ENABLED (JERRY_ES2015) + if (is_class_method && lexer_compare_literal_to_string (context_p, "constructor", 11)) + { + context_p->token.type = LEXER_CLASS_CONSTRUCTOR; return; } +#endif /* ENABLED (JERRY_ES2015) */ + + lexer_construct_literal_object (context_p, + &context_p->token.lit_location, + LEXER_STRING_LITERAL); + return; } parser_raise_error (context_p, PARSER_ERR_PROPERTY_IDENTIFIER_EXPECTED); @@ -2629,7 +2651,6 @@ lexer_scan_identifier (parser_context_t *context_p, /**< context */ lexer_parse_identifier (context_p, false); if ((ident_opts & LEXER_SCAN_IDENT_PROPERTY) - && !(ident_opts & LEXER_SCAN_IDENT_NO_KEYW) && context_p->token.lit_location.length == 3) { lexer_skip_spaces (context_p); @@ -2653,41 +2674,11 @@ lexer_scan_identifier (parser_context_t *context_p, /**< context */ } } } + return; } - if (ident_opts & LEXER_SCAN_IDENT_PROPERTY) - { - lexer_next_token (context_p); - - if (context_p->token.type == LEXER_LITERAL -#if ENABLED (JERRY_ES2015) - || context_p->token.type == LEXER_LEFT_SQUARE -#endif /* ENABLED (JERRY_ES2015) */ - || context_p->token.type == LEXER_RIGHT_BRACE) - { - return; - } - } -#if ENABLED (JERRY_ES2015) - if (ident_opts & LEXER_SCAN_CLASS_PROPERTY) - { - lexer_next_token (context_p); - - if (context_p->token.type == LEXER_LITERAL -#if ENABLED (JERRY_ES2015) - || context_p->token.type == LEXER_LEFT_SQUARE -#endif /* ENABLED (JERRY_ES2015) */ - || context_p->token.type == LEXER_RIGHT_BRACE - || context_p->token.type == LEXER_SEMICOLON - || ((ident_opts & LEXER_SCAN_CLASS_LEFT_PAREN) && context_p->token.type == LEXER_LEFT_PAREN)) - { - return; - } - } -#endif /* ENABLED (JERRY_ES2015) */ - - parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED); + lexer_next_token (context_p); } /* lexer_scan_identifier */ /** diff --git a/jerry-core/parser/js/js-lexer.h b/jerry-core/parser/js/js-lexer.h index 267b6c511..64ca8f3be 100644 --- a/jerry-core/parser/js/js-lexer.h +++ b/jerry-core/parser/js/js-lexer.h @@ -249,11 +249,6 @@ typedef enum { LEXER_SCAN_IDENT_NO_OPTS = (1u << 0), /**< no options */ LEXER_SCAN_IDENT_PROPERTY = (1u << 1), /**< scan valid property names */ - LEXER_SCAN_IDENT_NO_KEYW = (1u << 2), /**< don't scan keywords (e.g. get/set) */ -#if ENABLED (JERRY_ES2015) - LEXER_SCAN_CLASS_PROPERTY = (1u << 3), /**< scan valid class property names */ - LEXER_SCAN_CLASS_LEFT_PAREN = (1u << 4), /**< also parse left parenthesis */ -#endif /* ENABLED (JERRY_ES2015) */ } lexer_scan_ident_opts_t; /** diff --git a/jerry-core/parser/js/js-parser-expr.c b/jerry-core/parser/js/js-parser-expr.c index 1b56ff1ba..72a1dbd22 100644 --- a/jerry-core/parser/js/js-parser-expr.c +++ b/jerry-core/parser/js/js-parser-expr.c @@ -414,7 +414,7 @@ parser_parse_class_literal (parser_context_t *context_p) /**< context */ JERRY_ASSERT (context_p->token.type == LEXER_LEFT_BRACE); bool super_called = false; - uint32_t status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE; + uint32_t status_flags = PARSER_FUNCTION_CLOSURE; status_flags |= context_p->status_flags & (PARSER_CLASS_HAS_SUPER | PARSER_CLASS_IMPLICIT_SUPER); while (true) @@ -438,8 +438,6 @@ parser_parse_class_literal (parser_context_t *context_p) /**< context */ uint16_t literal_index, function_literal_index; bool is_getter = (context_p->token.type == LEXER_PROPERTY_GETTER); - lexer_skip_empty_statements (context_p); - if (lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN)) { lexer_construct_literal_object (context_p, @@ -449,7 +447,7 @@ parser_parse_class_literal (parser_context_t *context_p) /**< context */ goto parse_class_method; } - uint32_t accessor_status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE; + uint32_t accessor_status_flags = PARSER_FUNCTION_CLOSURE; accessor_status_flags |= (is_getter ? PARSER_IS_PROPERTY_GETTER : PARSER_IS_PROPERTY_SETTER); lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_CLASS_METHOD | LEXER_OBJ_IDENT_ONLY_IDENTIFIERS); @@ -466,7 +464,6 @@ parser_parse_class_literal (parser_context_t *context_p) /**< context */ parser_raise_error (context_p, PARSER_ERR_CLASS_CONSTRUCTOR_AS_ACCESSOR); } - parser_flush_cbc (context_p); function_literal_index = lexer_construct_function_object (context_p, accessor_status_flags); parser_emit_cbc_literal (context_p, @@ -510,46 +507,55 @@ parser_parse_class_literal (parser_context_t *context_p) /**< context */ continue; } - if (!(status_flags & PARSER_CLASS_STATIC_FUNCTION) && context_p->token.type == LEXER_CLASS_CONSTRUCTOR) + if (!(status_flags & PARSER_CLASS_STATIC_FUNCTION)) { - if (super_called) + if (context_p->token.type == LEXER_KEYW_STATIC) { - /* 14.5.1 */ - parser_raise_error (context_p, PARSER_ERR_MULTIPLE_CLASS_CONSTRUCTORS); - } - else - { - super_called = true; + status_flags |= PARSER_CLASS_STATIC_FUNCTION; + continue; } - parser_flush_cbc (context_p); - uint32_t constructor_status_flags = status_flags | PARSER_CLASS_CONSTRUCTOR; - - if (context_p->status_flags & PARSER_CLASS_HAS_SUPER) + if (context_p->token.type == LEXER_CLASS_CONSTRUCTOR) { - constructor_status_flags |= PARSER_LEXICAL_ENV_NEEDED; - } + if (super_called) + { + /* 14.5.1 */ + parser_raise_error (context_p, PARSER_ERR_MULTIPLE_CLASS_CONSTRUCTORS); + } + else + { + super_called = true; + } - if (context_p->literal_count >= PARSER_MAXIMUM_NUMBER_OF_LITERALS) - { - parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED); - } + parser_flush_cbc (context_p); + uint32_t constructor_status_flags = status_flags | PARSER_CLASS_CONSTRUCTOR; - uint16_t result_index = context_p->literal_count; - lexer_literal_t *literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool); - literal_p->type = LEXER_UNUSED_LITERAL; - literal_p->status_flags = 0; - literal_p->u.bytecode_p = parser_parse_function (context_p, constructor_status_flags); - literal_p->type = LEXER_FUNCTION_LITERAL; - parser_emit_cbc_literal (context_p, PARSER_TO_EXT_OPCODE (CBC_EXT_SET_CLASS_LITERAL), result_index); - context_p->literal_count++; - continue; + if (context_p->status_flags & PARSER_CLASS_HAS_SUPER) + { + constructor_status_flags |= PARSER_LEXICAL_ENV_NEEDED; + } + + if (context_p->literal_count >= PARSER_MAXIMUM_NUMBER_OF_LITERALS) + { + parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED); + } + + uint16_t result_index = context_p->literal_count; + lexer_literal_t *literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool); + literal_p->type = LEXER_UNUSED_LITERAL; + literal_p->status_flags = 0; + literal_p->u.bytecode_p = parser_parse_function (context_p, constructor_status_flags); + literal_p->type = LEXER_FUNCTION_LITERAL; + parser_emit_cbc_literal (context_p, PARSER_TO_EXT_OPCODE (CBC_EXT_SET_CLASS_LITERAL), result_index); + context_p->literal_count++; + continue; + } } - if (!(status_flags & PARSER_CLASS_STATIC_FUNCTION) && context_p->token.type == LEXER_KEYW_STATIC) + if (context_p->token.type == LEXER_MULTIPLY) { - status_flags |= PARSER_CLASS_STATIC_FUNCTION; - continue; + lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_ONLY_IDENTIFIERS); + status_flags |= PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_YIELD; } if (context_p->token.type == LEXER_RIGHT_SQUARE) @@ -564,8 +570,7 @@ parser_parse_class_literal (parser_context_t *context_p) /**< context */ } parse_class_method: - parser_flush_cbc (context_p); - + ; /* Empty statement to make compiler happy. */ uint16_t literal_index = context_p->lit_object.index; uint16_t function_literal_index = lexer_construct_function_object (context_p, status_flags); @@ -720,12 +725,9 @@ parser_parse_class (parser_context_t *context_p, /**< context */ static void parser_parse_object_method (parser_context_t *context_p) /**< context */ { - parser_flush_cbc (context_p); - context_p->source_p--; context_p->column--; - uint16_t function_literal_index = lexer_construct_function_object (context_p, - PARSER_IS_FUNCTION | PARSER_IS_CLOSURE); + uint16_t function_literal_index = lexer_construct_function_object (context_p, PARSER_FUNCTION_CLOSURE); parser_emit_cbc_literal (context_p, CBC_PUSH_LITERAL, @@ -790,14 +792,13 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */ { uint32_t status_flags; cbc_ext_opcode_t opcode; - uint16_t literal_index, function_literal_index; #if !ENABLED (JERRY_ES2015) parser_object_literal_item_types_t item_type; #endif /* !ENABLED (JERRY_ES2015) */ if (context_p->token.type == LEXER_PROPERTY_GETTER) { - status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE | PARSER_IS_PROPERTY_GETTER; + status_flags = PARSER_FUNCTION_CLOSURE | PARSER_IS_PROPERTY_GETTER; opcode = CBC_EXT_SET_GETTER; #if !ENABLED (JERRY_ES2015) item_type = PARSER_OBJECT_PROPERTY_GETTER; @@ -805,7 +806,7 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */ } else { - status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE | PARSER_IS_PROPERTY_SETTER; + status_flags = PARSER_FUNCTION_CLOSURE | PARSER_IS_PROPERTY_SETTER; opcode = CBC_EXT_SET_SETTER; #if !ENABLED (JERRY_ES2015) item_type = PARSER_OBJECT_PROPERTY_SETTER; @@ -815,7 +816,7 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */ lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_ONLY_IDENTIFIERS); /* This assignment is a nop for computed getters/setters. */ - literal_index = context_p->lit_object.index; + uint16_t literal_index = context_p->lit_object.index; #if ENABLED (JERRY_ES2015) if (context_p->token.type == LEXER_RIGHT_SQUARE) @@ -827,8 +828,7 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */ parser_append_object_literal_item (context_p, literal_index, item_type); #endif /* ENABLED (JERRY_ES2015) */ - parser_flush_cbc (context_p); - function_literal_index = lexer_construct_function_object (context_p, status_flags); + uint16_t function_literal_index = lexer_construct_function_object (context_p, status_flags); #if ENABLED (JERRY_ES2015) if (opcode >= CBC_EXT_SET_COMPUTED_GETTER) @@ -880,6 +880,33 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */ } break; } + case LEXER_MULTIPLY: + { + lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_ONLY_IDENTIFIERS); + + uint16_t opcode = CBC_SET_LITERAL_PROPERTY; + /* This assignment is a nop for CBC_EXT_SET_COMPUTED_PROPERTY_LITERAL. */ + uint16_t literal_index = context_p->lit_object.index; + + if (context_p->token.type == LEXER_RIGHT_SQUARE) + { + opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_SET_COMPUTED_PROPERTY_LITERAL); + } + + uint32_t status_flags = PARSER_FUNCTION_CLOSURE | PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_YIELD; + uint16_t function_literal_index = lexer_construct_function_object (context_p, status_flags); + + parser_emit_cbc_literal (context_p, + CBC_PUSH_LITERAL, + function_literal_index); + + JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL); + context_p->last_cbc_opcode = opcode; + context_p->last_cbc.value = literal_index; + + lexer_next_token (context_p); + break; + } #endif /* ENABLED (JERRY_ES2015) */ default: { @@ -1054,10 +1081,6 @@ parser_parse_function_expression (parser_context_t *context_p, /**< context */ literal2 = context_p->last_cbc.value; context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE; } - else - { - parser_flush_cbc (context_p); - } function_literal_index = lexer_construct_function_object (context_p, status_flags); @@ -1383,8 +1406,7 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ } case LEXER_KEYW_FUNCTION: { - parser_parse_function_expression (context_p, - PARSER_IS_FUNCTION | PARSER_IS_FUNC_EXPRESSION | PARSER_IS_CLOSURE); + parser_parse_function_expression (context_p, PARSER_FUNCTION_CLOSURE | PARSER_IS_FUNC_EXPRESSION); break; } case LEXER_LEFT_BRACE: diff --git a/jerry-core/parser/js/js-parser-internal.h b/jerry-core/parser/js/js-parser-internal.h index 74c52edab..4aac02c04 100644 --- a/jerry-core/parser/js/js-parser-internal.h +++ b/jerry-core/parser/js/js-parser-internal.h @@ -121,6 +121,11 @@ typedef enum */ #define PARSER_STRICT_MODE_MASK 0x1 +/** + * Shorthand for function closure definition + */ +#define PARSER_FUNCTION_CLOSURE (PARSER_IS_FUNCTION | PARSER_IS_CLOSURE) + #if ENABLED (JERRY_ES2015) /** * Offset between PARSER_CLASS_CONSTRUCTOR and ECMA_PARSE_CLASS_CONSTRUCTOR @@ -183,6 +188,7 @@ typedef enum #define PARSER_CBC_STREAM_PAGE_SIZE \ ((uint32_t) (64 - sizeof (void *))) +/* Defines the size of the max page. */ #define PARSER_STACK_PAGE_SIZE \ ((uint32_t) (((sizeof (void *) > 4) ? 128 : 64) - sizeof (void *))) diff --git a/jerry-core/parser/js/js-parser-statm.c b/jerry-core/parser/js/js-parser-statm.c index 8d7972a25..0b47ae0fd 100644 --- a/jerry-core/parser/js/js-parser-statm.c +++ b/jerry-core/parser/js/js-parser-statm.c @@ -670,13 +670,15 @@ parser_parse_function_statement (parser_context_t *context_p) /**< context */ context_p->status_flags &= (uint32_t) ~(PARSER_MODULE_STORE_IDENT); #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ - uint32_t status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE; + uint32_t status_flags = PARSER_FUNCTION_CLOSURE; + if (context_p->lit_object.type != LEXER_LITERAL_OBJECT_ANY) { JERRY_ASSERT (context_p->lit_object.type == LEXER_LITERAL_OBJECT_EVAL || context_p->lit_object.type == LEXER_LITERAL_OBJECT_ARGUMENTS); status_flags |= PARSER_HAS_NON_STRICT_ARG; } + #if ENABLED (JERRY_ES2015) if (is_generator_function) { diff --git a/jerry-core/parser/js/js-scanner.c b/jerry-core/parser/js/js-scanner.c index 76e793f5e..ba7608a03 100644 --- a/jerry-core/parser/js/js-scanner.c +++ b/jerry-core/parser/js/js-scanner.c @@ -99,6 +99,7 @@ typedef enum SCAN_STACK_PROPERTY_ACCESSOR, /**< property accessor in squarey brackets */ #if ENABLED (JERRY_ES2015) SCAN_STACK_COMPUTED_PROPERTY, /**< computed property name */ + SCAN_STACK_COMPUTED_GENERATOR_FUNCTION, /**< computed property name */ SCAN_STACK_TEMPLATE_STRING, /**< template string */ SCAN_STACK_FOR_BLOCK_END, /**< end of "for" statement with let/const declaration */ SCAN_STACK_ARROW_ARGUMENTS, /**< might be arguments of an arrow function */ @@ -136,6 +137,13 @@ typedef enum #if ENABLED (JERRY_ES2015) +/** + * Returns the correct computed property mode based on the literal_pool_flags. + */ +#define GET_COMPUTED_PROPERTY_MODE(literal_pool_flags) \ + (((literal_pool_flags) & SCANNER_LITERAL_POOL_GENERATOR) ? SCAN_STACK_COMPUTED_GENERATOR_FUNCTION \ + : SCAN_STACK_COMPUTED_PROPERTY) + /** * Init scanning the body of an arrow function. */ @@ -673,6 +681,13 @@ scanner_scan_post_primary_expression (parser_context_t *context_p, /**< context case LEXER_DOT: { lexer_scan_identifier (context_p, LEXER_SCAN_IDENT_NO_OPTS); + + if (context_p->token.type != LEXER_LITERAL + || context_p->token.lit_location.type != LEXER_IDENT_LITERAL) + { + scanner_raise_error (context_p); + } + return true; } case LEXER_LEFT_PAREN: @@ -1291,6 +1306,27 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * } return SCAN_NEXT_TOKEN; } + case SCAN_STACK_COMPUTED_GENERATOR_FUNCTION: + { + if (type != LEXER_RIGHT_SQUARE) + { + break; + } + + lexer_next_token (context_p); + parser_stack_pop_uint8 (context_p); + + JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL + || context_p->stack_top_uint8 == SCAN_STACK_FUNCTION_PROPERTY); + + scanner_push_literal_pool (context_p, + scanner_context_p, + SCANNER_LITERAL_POOL_FUNCTION | SCANNER_LITERAL_POOL_GENERATOR); + context_p->status_flags |= PARSER_IS_GENERATOR_FUNCTION; + + scanner_context_p->mode = SCAN_MODE_FUNCTION_ARGUMENTS; + return SCAN_KEEP_TOKEN; + } case SCAN_STACK_TEMPLATE_STRING: { if (type != LEXER_RIGHT_BRACE) @@ -2531,7 +2567,7 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ JERRY_ASSERT (stack_top == SCAN_STACK_CLASS_STATEMENT || stack_top == SCAN_STACK_CLASS_EXPRESSION); lexer_skip_empty_statements (context_p); - lexer_scan_identifier (context_p, LEXER_SCAN_CLASS_PROPERTY); + lexer_scan_identifier (context_p, LEXER_SCAN_IDENT_NO_OPTS); if (context_p->token.type == LEXER_RIGHT_BRACE) { @@ -2549,16 +2585,18 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ if (lexer_compare_literal_to_identifier (context_p, "static", 6)) { - lexer_scan_identifier (context_p, LEXER_SCAN_CLASS_PROPERTY); + lexer_scan_identifier (context_p, LEXER_SCAN_IDENT_NO_OPTS); } parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PROPERTY); scanner_context.mode = SCAN_MODE_FUNCTION_ARGUMENTS; + uint16_t literal_pool_flags = SCANNER_LITERAL_POOL_FUNCTION; + if (lexer_compare_literal_to_identifier (context_p, "get", 3) || lexer_compare_literal_to_identifier (context_p, "set", 3)) { - lexer_scan_identifier (context_p, LEXER_SCAN_CLASS_PROPERTY | LEXER_SCAN_CLASS_LEFT_PAREN); + lexer_scan_identifier (context_p, LEXER_SCAN_IDENT_NO_OPTS); if (context_p->token.type == LEXER_LEFT_PAREN) { @@ -2566,15 +2604,30 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ continue; } } + else if (context_p->token.type == LEXER_MULTIPLY) + { + lexer_scan_identifier (context_p, LEXER_SCAN_IDENT_NO_OPTS); + literal_pool_flags |= SCANNER_LITERAL_POOL_GENERATOR; + } if (context_p->token.type == LEXER_LEFT_SQUARE) { - parser_stack_push_uint8 (context_p, SCAN_STACK_COMPUTED_PROPERTY); + parser_stack_push_uint8 (context_p, GET_COMPUTED_PROPERTY_MODE (literal_pool_flags)); scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION; break; } - scanner_push_literal_pool (context_p, &scanner_context, SCANNER_LITERAL_POOL_FUNCTION); + if (context_p->token.type != LEXER_LITERAL) + { + scanner_raise_error (context_p); + } + + if (literal_pool_flags & SCANNER_LITERAL_POOL_GENERATOR) + { + context_p->status_flags |= PARSER_IS_GENERATOR_FUNCTION; + } + + scanner_push_literal_pool (context_p, &scanner_context, literal_pool_flags); lexer_next_token (context_p); continue; } @@ -2920,19 +2973,35 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ } if (context_p->token.type == LEXER_PROPERTY_GETTER +#if ENABLED (JERRY_ES2015) + || context_p->token.type == LEXER_MULTIPLY +#endif /* ENABLED (JERRY_ES2015) */ || context_p->token.type == LEXER_PROPERTY_SETTER) { - lexer_scan_identifier (context_p, LEXER_SCAN_IDENT_PROPERTY | LEXER_SCAN_IDENT_NO_KEYW); + uint16_t literal_pool_flags = SCANNER_LITERAL_POOL_FUNCTION; + +#if ENABLED (JERRY_ES2015) + if (context_p->token.type == LEXER_MULTIPLY) + { + literal_pool_flags |= SCANNER_LITERAL_POOL_GENERATOR; + } +#endif /* ENABLED (JERRY_ES2015) */ parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PROPERTY); + lexer_scan_identifier (context_p, LEXER_SCAN_IDENT_NO_OPTS); #if ENABLED (JERRY_ES2015) if (context_p->token.type == LEXER_LEFT_SQUARE) { - parser_stack_push_uint8 (context_p, SCAN_STACK_COMPUTED_PROPERTY); + parser_stack_push_uint8 (context_p, GET_COMPUTED_PROPERTY_MODE (literal_pool_flags)); scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION; break; } + + if (literal_pool_flags & SCANNER_LITERAL_POOL_GENERATOR) + { + context_p->status_flags |= PARSER_IS_GENERATOR_FUNCTION; + } #endif /* ENABLED (JERRY_ES2015) */ if (context_p->token.type != LEXER_LITERAL) @@ -2940,12 +3009,15 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ scanner_raise_error (context_p); } - scanner_push_literal_pool (context_p, &scanner_context, SCANNER_LITERAL_POOL_FUNCTION); + scanner_push_literal_pool (context_p, &scanner_context, literal_pool_flags); scanner_context.mode = SCAN_MODE_FUNCTION_ARGUMENTS; break; } - JERRY_ASSERT (context_p->token.type == LEXER_LITERAL); + if (context_p->token.type != LEXER_LITERAL) + { + scanner_raise_error (context_p); + } #if ENABLED (JERRY_ES2015) parser_line_counter_t start_line = context_p->token.line; diff --git a/tests/jerry/es2015/generator-initializer.js b/tests/jerry/es2015/generator-initializer.js new file mode 100644 index 000000000..4493670de --- /dev/null +++ b/tests/jerry/es2015/generator-initializer.js @@ -0,0 +1,138 @@ +/* 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. + */ + +/* This file checks core generator operations. */ + +function check_syntax_error (code) +{ + try { + eval (code) + assert (false) + } catch (e) { + assert (e instanceof SyntaxError) + } +} + +check_syntax_error ("({ * })") +check_syntax_error ("({ *, b:4 })") +check_syntax_error ("({ *a:4 })") +check_syntax_error ("({ *['a']:4 })") +check_syntax_error ("({ *a(yield) {} })") +check_syntax_error ("({ get *a() {} })") +check_syntax_error ("({ set *b(v) {} })") + +check_syntax_error ("class C { * }") +check_syntax_error ("class C { static * }") +check_syntax_error ("class C { *() {} }") +check_syntax_error ("class C { static * () {} }") +check_syntax_error ("class C { *['a'] {} }") + +function check_result(result, value, done) +{ + assert(result.value === value) + assert(result.done === done) +} + +function postfix(a) { return a + "b" } + +var o = { + * a () { + yield 1 + return 2 + }, + *2(x) { + yield x + 1 + return x + 2 + }, + *[postfix("a")]() { + var o = { get yield() { return 3 + 2 } } + + yield o.yield + return 6 + }, + *yield() { + var o = { yield:7 } + + yield o.yield + return 8 + } +} + +var f = o.a() +check_result(f.next(), 1, false) +check_result(f.next(), 2, true) + +var f = o[2](2) +check_result(f.next(), 3, false) +check_result(f.next(), 4, true) + +var f = o.ab() +check_result(f.next(), 5, false) +check_result(f.next(), 6, true) + +var f = o.yield() +check_result(f.next(), 7, false) +check_result(f.next(), 8, true) + +class C { + * a () { + yield 1 + return 2 + } + + *3(x) { + yield x + 1 + return x + 2 + } + + *[postfix("a")]() { + var o = { get yield() { return 3 + 2 } } + + yield o.yield + return 6 + } + + static *yield() { + var o = { yield:7 } + + yield o.yield + return 8 + } + + static * [postfix("b") ] (v = 9) { + return v + } +} + +var c = new C + +var f = c.a() +check_result(f.next(), 1, false) +check_result(f.next(), 2, true) + +var f = c[3](2) +check_result(f.next(), 3, false) +check_result(f.next(), 4, true) + +var f = c.ab() +check_result(f.next(), 5, false) +check_result(f.next(), 6, true) + +var f = C.yield() +check_result(f.next(), 7, false) +check_result(f.next(), 8, true) + +var f = C.bb() +check_result(f.next(), 9, true)