Initial implementation of class fields (#4191)

Missing features:
 - this binding in static fields are not supported
 - static field evaluation order is wrong
 - function names are not supported

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg
2020-09-17 15:22:55 +02:00
committed by GitHub
parent 7345c83af7
commit d9653823ca
30 changed files with 1666 additions and 581 deletions
+239 -95
View File
@@ -491,22 +491,6 @@ parser_parse_array_initializer (parser_context_t *context_p, parser_pattern_flag
static void
parser_parse_object_initializer (parser_context_t *context_p, parser_pattern_flags_t flags);
/**
* Description of "get" literal string.
*/
static const lexer_lit_location_t lexer_get_literal =
{
(const uint8_t *) "get", 3, LEXER_STRING_LITERAL, false
};
/**
* Description of "set" literal string.
*/
static const lexer_lit_location_t lexer_set_literal =
{
(const uint8_t *) "set", 3, LEXER_STRING_LITERAL, false
};
/**
* Class literal parsing options.
*/
@@ -517,6 +501,18 @@ typedef enum
PARSER_CLASS_LITERAL_HERTIAGE_PRESENT = (1 << 1), /**< class heritage is present */
} parser_class_literal_opts_t;
/**
* Checks whether the current string or identifier literal is constructor
*
* @return true, if constructor and false otherwise
*/
static inline bool JERRY_ATTR_ALWAYS_INLINE
parser_is_constructor_literal (parser_context_t *context_p) /**< context */
{
return (LEXER_IS_IDENT_OR_STRING (context_p->token.lit_location.type)
&& lexer_compare_literal_to_string (context_p, "constructor", 11));
} /* parser_is_constructor_literal */
/**
* Parse class literal.
*/
@@ -526,20 +522,11 @@ parser_parse_class_literal (parser_context_t *context_p, /**< context */
{
JERRY_ASSERT (context_p->token.type == LEXER_LEFT_BRACE);
uint32_t status_flags = PARSER_FUNCTION_CLOSURE | PARSER_ALLOW_SUPER;
lexer_literal_t *ctor_literal_p = NULL;
if (opts & PARSER_CLASS_LITERAL_CTOR_PRESENT)
{
if (context_p->literal_count >= PARSER_MAXIMUM_NUMBER_OF_LITERALS)
{
parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED);
}
ctor_literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool);
ctor_literal_p->type = LEXER_UNUSED_LITERAL;
ctor_literal_p->status_flags = 0;
ctor_literal_p = lexer_construct_unused_literal (context_p);
parser_emit_cbc_literal (context_p, CBC_PUSH_LITERAL, (uint16_t) (context_p->literal_count++));
}
else if (opts & PARSER_CLASS_LITERAL_HERTIAGE_PRESENT)
@@ -554,6 +541,7 @@ parser_parse_class_literal (parser_context_t *context_p, /**< context */
parser_emit_cbc_ext (context_p, CBC_EXT_INIT_CLASS);
bool is_static = false;
size_t fields_size = 0;
while (true)
{
@@ -562,17 +550,56 @@ parser_parse_class_literal (parser_context_t *context_p, /**< context */
lexer_skip_empty_statements (context_p);
}
lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_CLASS_METHOD);
lexer_expect_object_literal_id (context_p, (LEXER_OBJ_IDENT_CLASS_IDENTIFIER
| (is_static ? 0 : LEXER_OBJ_IDENT_CLASS_NO_STATIC)));
if (context_p->token.type == LEXER_RIGHT_BRACE)
{
if (JERRY_UNLIKELY (is_static))
{
parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED);
}
JERRY_ASSERT (!is_static);
break;
}
if (context_p->token.type == LEXER_KEYW_STATIC)
{
JERRY_ASSERT (!is_static);
is_static = true;
continue;
}
if (!is_static && context_p->token.type == LEXER_LITERAL && parser_is_constructor_literal (context_p))
{
JERRY_ASSERT (!is_static);
JERRY_ASSERT (opts & PARSER_CLASS_LITERAL_CTOR_PRESENT);
JERRY_ASSERT (ctor_literal_p != NULL);
if (ctor_literal_p->type == LEXER_FUNCTION_LITERAL)
{
/* 14.5.1 */
parser_raise_error (context_p, PARSER_ERR_MULTIPLE_CLASS_CONSTRUCTORS);
}
uint32_t constructor_status_flags = (PARSER_FUNCTION_CLOSURE
| PARSER_ALLOW_SUPER
| PARSER_CLASS_CONSTRUCTOR
| PARSER_LEXICAL_ENV_NEEDED);
if (opts & PARSER_CLASS_LITERAL_HERTIAGE_PRESENT)
{
constructor_status_flags |= PARSER_ALLOW_SUPER_CALL;
}
if (context_p->status_flags & PARSER_INSIDE_WITH)
{
constructor_status_flags |= PARSER_INSIDE_WITH;
}
parser_flush_cbc (context_p);
ecma_compiled_code_t *compiled_code_p = parser_parse_function (context_p, constructor_status_flags);
ctor_literal_p->u.bytecode_p = compiled_code_p;
ctor_literal_p->type = LEXER_FUNCTION_LITERAL;
continue;
}
bool is_computed = false;
if (context_p->token.type == LEXER_PROPERTY_GETTER || context_p->token.type == LEXER_PROPERTY_SETTER)
@@ -580,28 +607,17 @@ 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);
if (lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN))
{
lexer_construct_literal_object (context_p,
(is_getter ? (lexer_lit_location_t *) &lexer_get_literal
: (lexer_lit_location_t *) &lexer_set_literal),
LEXER_STRING_LITERAL);
goto parse_class_method;
}
uint32_t accessor_status_flags = status_flags;
uint32_t accessor_status_flags = PARSER_FUNCTION_CLOSURE | PARSER_ALLOW_SUPER;
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);
lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_ONLY_IDENTIFIERS);
literal_index = context_p->lit_object.index;
if (context_p->token.type == LEXER_RIGHT_SQUARE)
{
is_computed = true;
}
else if (!is_static
&& LEXER_IS_IDENT_OR_STRING (context_p->token.lit_location.type)
&& lexer_compare_literal_to_string (context_p, "constructor", 11))
else if (!is_static && parser_is_constructor_literal (context_p))
{
parser_raise_error (context_p, PARSER_ERR_CLASS_CONSTRUCTOR_AS_ACCESSOR);
}
@@ -659,45 +675,7 @@ parser_parse_class_literal (parser_context_t *context_p, /**< context */
continue;
}
if (!is_static)
{
if (context_p->token.type == LEXER_KEYW_STATIC)
{
is_static = true;
continue;
}
if (context_p->token.type == LEXER_CLASS_CONSTRUCTOR)
{
JERRY_ASSERT (opts & PARSER_CLASS_LITERAL_CTOR_PRESENT);
JERRY_ASSERT (ctor_literal_p != NULL);
if (ctor_literal_p->type == LEXER_FUNCTION_LITERAL)
{
/* 14.5.1 */
parser_raise_error (context_p, PARSER_ERR_MULTIPLE_CLASS_CONSTRUCTORS);
}
uint32_t constructor_status_flags = (status_flags
| PARSER_CLASS_CONSTRUCTOR
| PARSER_LEXICAL_ENV_NEEDED);
if (opts & PARSER_CLASS_LITERAL_HERTIAGE_PRESENT)
{
constructor_status_flags |= PARSER_ALLOW_SUPER_CALL;
}
parser_flush_cbc (context_p);
ecma_compiled_code_t *compiled_code_p = parser_parse_function (context_p, constructor_status_flags);
ctor_literal_p->u.bytecode_p = compiled_code_p;
ctor_literal_p->type = LEXER_FUNCTION_LITERAL;
continue;
}
}
status_flags &= (uint32_t) ~(PARSER_IS_GENERATOR_FUNCTION
| PARSER_IS_ASYNC_FUNCTION
| PARSER_DISALLOW_AWAIT_YIELD);
uint32_t status_flags = PARSER_FUNCTION_CLOSURE | PARSER_ALLOW_SUPER;
if (context_p->token.type == LEXER_KEYW_ASYNC)
{
@@ -728,15 +706,164 @@ parser_parse_class_literal (parser_context_t *context_p, /**< context */
parser_raise_error (context_p, PARSER_ERR_CLASS_STATIC_PROTOTYPE);
}
}
else if ((status_flags & PARSER_IS_GENERATOR_FUNCTION)
else if ((status_flags & (PARSER_IS_ASYNC_FUNCTION | PARSER_IS_GENERATOR_FUNCTION))
&& lexer_compare_literal_to_string (context_p, "constructor", 11))
{
parser_raise_error (context_p, PARSER_ERR_CLASS_CONSTRUCTOR_AS_GENERATOR);
parser_raise_error (context_p, PARSER_ERR_INVALID_CLASS_CONSTRUCTOR);
}
}
if (!(status_flags & (PARSER_IS_ASYNC_FUNCTION | PARSER_IS_GENERATOR_FUNCTION)))
{
if (!is_static && !lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN))
{
/* Class field. */
if (fields_size == 0)
{
parser_stack_push_uint8 (context_p, PARSER_CLASS_FIELD_END);
}
scanner_range_t range;
uint8_t class_field_type = 0;
if (!is_computed)
{
range.start_location.source_p = context_p->token.lit_location.char_p;
range.start_location.line = context_p->token.line;
range.start_location.column = context_p->token.column;
class_field_type = PARSER_CLASS_FIELD_NORMAL;
if (context_p->token.lit_location.type == LEXER_STRING_LITERAL)
{
range.start_location.source_p--;
}
}
else
{
parser_emit_cbc_ext (context_p, CBC_EXT_ADD_COMPUTED_FIELD);
}
if (lexer_consume_assign (context_p))
{
class_field_type |= PARSER_CLASS_FIELD_INITIALIZED;
if (context_p->next_scanner_info_p->source_p != context_p->source_p)
{
lexer_next_token (context_p);
parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA);
parser_raise_error (context_p, PARSER_ERR_SEMICOLON_EXPECTED);
}
if (is_computed)
{
scanner_get_location (&range.start_location, context_p);
}
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_CLASS_FIELD_INITIALIZER_END);
range.source_end_p = ((scanner_location_info_t *) context_p->next_scanner_info_p)->location.source_p;
scanner_set_location (context_p, &((scanner_location_info_t *) context_p->next_scanner_info_p)->location);
scanner_release_next (context_p, sizeof (scanner_location_info_t));
scanner_seek (context_p);
parser_stack_push (context_p, &range, sizeof (scanner_range_t));
fields_size += sizeof (scanner_range_t);
}
else
{
if (!(context_p->token.flags & LEXER_WAS_NEWLINE)
&& !lexer_check_next_characters (context_p, LIT_CHAR_SEMICOLON, LIT_CHAR_RIGHT_BRACE))
{
lexer_next_token (context_p);
parser_raise_error (context_p, PARSER_ERR_SEMICOLON_EXPECTED);
}
if (!is_computed)
{
parser_stack_push (context_p, &range.start_location, sizeof (scanner_location_t));
fields_size += sizeof (scanner_location_t);
}
}
parser_stack_push_uint8 (context_p, class_field_type);
fields_size++;
is_static = false;
continue;
}
if (!is_computed)
{
if (context_p->token.lit_location.type != LEXER_NUMBER_LITERAL)
{
JERRY_ASSERT (context_p->token.lit_location.type == LEXER_IDENT_LITERAL
|| context_p->token.lit_location.type == LEXER_STRING_LITERAL);
lexer_construct_literal_object (context_p,
&context_p->token.lit_location,
LEXER_STRING_LITERAL);
}
else
{
lexer_construct_number_object (context_p, false, false);
}
}
if (is_static && !lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN))
{
if (!is_computed && parser_is_constructor_literal (context_p))
{
parser_raise_error (context_p, PARSER_ERR_ARGUMENT_LIST_EXPECTED);
}
uint16_t literal_index = context_p->lit_object.index;
context_p->status_flags |= PARSER_INSIDE_CLASS_FIELD;
if (lexer_consume_assign (context_p))
{
if (context_p->next_scanner_info_p->source_p != context_p->source_p)
{
lexer_next_token (context_p);
parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA);
parser_raise_error (context_p, PARSER_ERR_SEMICOLON_EXPECTED);
}
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_CLASS_FIELD_INITIALIZER_END);
/* Changing the source_end_p prevents the lexer to process the name of the next class field
* as normal token which may cause issues if the name is also a keyword (e.g. var). */
const uint8_t *source_end_p = context_p->source_end_p;
context_p->source_end_p = ((scanner_location_info_t *) context_p->next_scanner_info_p)->location.source_p;
scanner_release_next (context_p, sizeof (scanner_location_info_t));
lexer_next_token (context_p);
parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA);
if (context_p->token.type != LEXER_EOS)
{
parser_raise_error (context_p, PARSER_ERR_SEMICOLON_EXPECTED);
}
context_p->source_end_p = source_end_p;
}
else
{
parser_emit_cbc (context_p, CBC_PUSH_UNDEFINED);
}
if (!is_computed)
{
parser_emit_cbc_ext_literal (context_p, CBC_EXT_SET_STATIC_PROPERTY, literal_index);
}
else
{
parser_emit_cbc_ext (context_p, CBC_EXT_SET_STATIC_COMPUTED_PROPERTY);
}
context_p->status_flags &= (uint32_t) ~PARSER_INSIDE_CLASS_FIELD;
is_static = false;
continue;
}
}
parse_class_method:
; /* 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 | PARSER_IS_METHOD);
@@ -769,6 +896,17 @@ parse_class_method:
context_p->last_cbc_opcode = CBC_SET_LITERAL_PROPERTY;
}
}
if (fields_size > 0)
{
parser_reverse_class_fields (context_p, fields_size);
/* Since PARSER_IS_ARROW_FUNCTION and PARSER_CLASS_CONSTRUCTOR bits cannot
* be set at the same time, this bit combination triggers class field parsing. */
uint16_t function_literal_index = lexer_construct_function_object (context_p, (PARSER_IS_ARROW_FUNCTION
| PARSER_CLASS_CONSTRUCTOR));
parser_emit_cbc_ext_literal (context_p, CBC_EXT_SET_CLASS_FIELD_INIT, function_literal_index);
}
} /* parser_parse_class_literal */
/**
@@ -1813,7 +1951,9 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */
{
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FUNCTION);
uint32_t arrow_status_flags = (PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION);
uint32_t arrow_status_flags = (PARSER_IS_FUNCTION
| PARSER_IS_ARROW_FUNCTION
| (context_p->status_flags & PARSER_INSIDE_CLASS_FIELD));
if (context_p->next_scanner_info_p->u8_arg & SCANNER_FUNCTION_ASYNC)
{
@@ -2073,7 +2213,10 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */
parser_check_assignment_expr (context_p);
parser_parse_function_expression (context_p, PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION);
uint32_t arrow_status_flags = (PARSER_IS_FUNCTION
| PARSER_IS_ARROW_FUNCTION
| (context_p->status_flags & PARSER_INSIDE_CLASS_FIELD));
parser_parse_function_expression (context_p, arrow_status_flags);
return parser_abort_parsing_after_assignment_expression (context_p);
}
case LEXER_KEYW_YIELD:
@@ -3442,11 +3585,6 @@ parser_parse_object_initializer (parser_context_t *context_p, /**< context */
}
parser_reparse_as_common_identifier (context_p, start_line, start_column);
lexer_next_token (context_p);
JERRY_ASSERT (context_p->token.type == LEXER_RIGHT_BRACE
|| context_p->token.type == LEXER_ASSIGN
|| context_p->token.type == LEXER_COMMA);
if (flags & PARSER_PATTERN_ARGUMENTS)
{
@@ -3462,6 +3600,12 @@ parser_parse_object_initializer (parser_context_t *context_p, /**< context */
#endif /* ENABLED (JERRY_MODULE_SYSTEM) */
parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL);
lexer_next_token (context_p);
JERRY_ASSERT (context_p->token.type == LEXER_RIGHT_BRACE
|| context_p->token.type == LEXER_ASSIGN
|| context_p->token.type == LEXER_COMMA);
parser_pattern_form_assignment (context_p, flags, push_prop_opcode, prop_index, start_line);
}