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
+1 -1
View File
@@ -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 == 135,
JERRY_STATIC_ASSERT (CBC_EXT_END == 140,
number_of_cbc_ext_opcodes_changed);
#if ENABLED (JERRY_PARSER)
+10
View File
@@ -634,6 +634,8 @@
VM_OC_SET_GETTER | VM_OC_NON_STATIC_FLAG | VM_OC_GET_STACK_STACK) \
CBC_OPCODE (CBC_EXT_SET_COMPUTED_SETTER, CBC_NO_FLAG, -2, \
VM_OC_SET_SETTER | VM_OC_NON_STATIC_FLAG | VM_OC_GET_STACK_STACK) \
CBC_OPCODE (CBC_EXT_SET_STATIC_PROPERTY, CBC_HAS_LITERAL_ARG, -1, \
VM_OC_SET_PROPERTY | VM_OC_GET_STACK_LITERAL) \
CBC_OPCODE (CBC_EXT_SET_STATIC_PROPERTY_LITERAL, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
VM_OC_SET_PROPERTY | VM_OC_GET_LITERAL_LITERAL) \
CBC_OPCODE (CBC_EXT_SET_STATIC_COMPUTED_PROPERTY, CBC_NO_FLAG, -2, \
@@ -648,6 +650,8 @@
VM_OC_SET_SETTER | VM_OC_GET_STACK_STACK) \
CBC_OPCODE (CBC_EXT_SET__PROTO__, CBC_NO_FLAG, -1, \
VM_OC_SET__PROTO__ | VM_OC_GET_STACK) \
CBC_OPCODE (CBC_EXT_ADD_COMPUTED_FIELD, CBC_NO_FLAG, -1, \
VM_OC_ADD_COMPUTED_FIELD | VM_OC_GET_STACK) \
\
/* Class related opcodes. */ \
CBC_OPCODE (CBC_EXT_PUSH_NAMED_CLASS_ENV, CBC_HAS_LITERAL_ARG, 1, \
@@ -664,6 +668,12 @@
VM_OC_FINALIZE_CLASS | VM_OC_GET_LITERAL) \
CBC_OPCODE (CBC_EXT_FINALIZE_ANONYMOUS_CLASS, CBC_NO_FLAG, -2, \
VM_OC_FINALIZE_CLASS) \
CBC_OPCODE (CBC_EXT_SET_CLASS_FIELD_INIT, CBC_HAS_LITERAL_ARG, 0, \
VM_OC_SET_CLASS_FIELD_INIT | VM_OC_GET_LITERAL) \
CBC_OPCODE (CBC_EXT_RUN_CLASS_FIELD_INIT, CBC_NO_FLAG, 0, \
VM_OC_RUN_CLASS_FIELD_INIT) \
CBC_OPCODE (CBC_EXT_SET_NEXT_COMPUTED_FIELD, CBC_NO_FLAG, -1, \
VM_OC_SET_NEXT_COMPUTED_FIELD | VM_OC_PUT_REFERENCE) \
CBC_OPCODE (CBC_EXT_PUSH_SUPER, CBC_NO_FLAG, 1, \
VM_OC_NONE) \
CBC_OPCODE (CBC_EXT_PUSH_SUPER_CONSTRUCTOR, CBC_NO_FLAG, 1, \
+115 -44
View File
@@ -433,6 +433,7 @@ lexer_skip_spaces (parser_context_t *context_p) /**< context */
} /* lexer_skip_spaces */
#if ENABLED (JERRY_ESNEXT)
/**
* Skip all the continuous empty statements.
*/
@@ -450,6 +451,22 @@ lexer_skip_empty_statements (parser_context_t *context_p) /**< context */
context_p->token.flags = (uint8_t) (context_p->token.flags | LEXER_NO_SKIP_SPACES);
} /* lexer_skip_empty_statements */
#endif /* ENABLED (JERRY_ESNEXT) */
#if ENABLED (JERRY_ESNEXT)
/**
* Checks whether the keyword has escape sequences.
*/
#define LEXER_CHECK_INVALID_KEYWORD(ident_start_p, buffer_p) \
(JERRY_UNLIKELY ((ident_start_p) == (buffer_p)) \
&& !(context_p->global_status_flags & ECMA_PARSE_INTERNAL_PRE_SCANNING))
#else /* !ENABLED (JERRY_ESNEXT) */
/**
* Checks whether the keyword has escape sequences.
*/
#define LEXER_CHECK_INVALID_KEYWORD(ident_start_p, buffer_p) \
(JERRY_UNLIKELY ((ident_start_p) == (buffer_p)))
#endif /* ENABLED (JERRY_ESNEXT) */
/**
@@ -807,7 +824,6 @@ lexer_parse_identifier (parser_context_t *context_p, /**< context */
JERRY_ASSERT (length > 0);
context_p->token.type = LEXER_LITERAL;
context_p->token.keyword_type = LEXER_EOS;
context_p->token.lit_location.type = LEXER_IDENT_LITERAL;
context_p->token.lit_location.has_escape = has_escape;
@@ -865,7 +881,7 @@ lexer_parse_identifier (parser_context_t *context_p, /**< context */
if (context_p->status_flags & PARSER_DISALLOW_AWAIT_YIELD)
{
if (ident_start_p == buffer_p)
if (LEXER_CHECK_INVALID_KEYWORD (ident_start_p, buffer_p))
{
parser_raise_error (context_p, PARSER_ERR_INVALID_KEYWORD);
}
@@ -877,7 +893,7 @@ lexer_parse_identifier (parser_context_t *context_p, /**< context */
}
#endif /* ENABLED (JERRY_ESNEXT) */
if (ident_start_p == buffer_p)
if (LEXER_CHECK_INVALID_KEYWORD (ident_start_p, buffer_p))
{
/* Escape sequences are not allowed in a keyword. */
parser_raise_error (context_p, PARSER_ERR_INVALID_KEYWORD);
@@ -890,7 +906,7 @@ lexer_parse_identifier (parser_context_t *context_p, /**< context */
#if ENABLED (JERRY_ESNEXT)
if (keyword_p->type == LEXER_KEYW_LET && (context_p->status_flags & PARSER_IS_STRICT))
{
if (ident_start_p == buffer_p)
if (LEXER_CHECK_INVALID_KEYWORD (ident_start_p, buffer_p))
{
parser_raise_error (context_p, PARSER_ERR_INVALID_KEYWORD);
}
@@ -903,7 +919,7 @@ lexer_parse_identifier (parser_context_t *context_p, /**< context */
{
if (context_p->status_flags & PARSER_DISALLOW_AWAIT_YIELD)
{
if (ident_start_p == buffer_p)
if (LEXER_CHECK_INVALID_KEYWORD (ident_start_p, buffer_p))
{
parser_raise_error (context_p, PARSER_ERR_INVALID_KEYWORD);
}
@@ -913,6 +929,11 @@ lexer_parse_identifier (parser_context_t *context_p, /**< context */
context_p->token.type = (uint8_t) LEXER_KEYW_YIELD;
break;
}
if (keyword_p->type == LEXER_KEYW_ARGUMENTS && (context_p->status_flags & PARSER_INSIDE_CLASS_FIELD))
{
parser_raise_error (context_p, PARSER_ERR_ARGUMENTS_IN_CLASS_FIELD);
}
#endif /* ENABLED (JERRY_ESNEXT) */
if (keyword_p->type >= LEXER_FIRST_FUTURE_STRICT_RESERVED_WORD
@@ -944,6 +965,8 @@ lexer_parse_identifier (parser_context_t *context_p, /**< context */
return true;
} /* lexer_parse_identifier */
#undef LEXER_CHECK_INVALID_KEYWORD
/**
* Parse string.
*/
@@ -1118,9 +1141,6 @@ lexer_parse_string (parser_context_t *context_p, /**< context */
uint32_t escape_length = (*source_p == LIT_CHAR_LOWERCASE_X) ? 3 : 5;
lit_code_point_t code_point = UINT32_MAX;
context_p->token.line = line;
context_p->token.column = (parser_line_counter_t) (column - 1);
#if ENABLED (JERRY_ESNEXT)
if (source_p + 4 <= source_end_p
&& source_p[0] == LIT_CHAR_LOWERCASE_U
@@ -1142,6 +1162,8 @@ lexer_parse_string (parser_context_t *context_p, /**< context */
if (code_point == UINT32_MAX)
{
context_p->token.line = line;
context_p->token.column = (parser_line_counter_t) (column - 1);
parser_raise_error (context_p, PARSER_ERR_INVALID_UNICODE_ESCAPE_SEQUENCE);
}
@@ -1312,7 +1334,6 @@ lexer_parse_number (parser_context_t *context_p) /**< context */
size_t length;
context_p->token.type = LEXER_LITERAL;
context_p->token.keyword_type = LEXER_EOS;
context_p->token.extra_value = LEXER_NUMBER_DECIMAL;
context_p->token.lit_location.char_p = source_p;
context_p->token.lit_location.type = LEXER_NUMBER_LITERAL;
@@ -1571,6 +1592,7 @@ lexer_next_token (parser_context_t *context_p) /**< context */
lexer_skip_spaces (context_p);
context_p->token.keyword_type = LEXER_EOS;
context_p->token.line = context_p->line;
context_p->token.column = context_p->column;
@@ -2079,6 +2101,33 @@ lexer_consume_generator (parser_context_t *context_p) /**< context */
return true;
} /* lexer_consume_generator */
/**
* Checks whether the next token is an equal sign and consumes it.
*
* @return true if the next token is an equal sign
*/
bool
lexer_consume_assign (parser_context_t *context_p) /**< context */
{
if (!(context_p->token.flags & LEXER_NO_SKIP_SPACES))
{
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
|| context_p->source_p[0] != LIT_CHAR_EQUALS
|| (context_p->source_p + 1 < context_p->source_end_p
&& (context_p->source_p[1] == LIT_CHAR_EQUALS || context_p->source_p[1] == LIT_CHAR_GREATER_THAN)))
{
return false;
}
lexer_consume_next_character (context_p);
context_p->token.type = LEXER_ASSIGN;
return true;
} /* lexer_consume_assign */
/**
* Update await / yield keywords after an arrow function with expression.
*/
@@ -2409,6 +2458,27 @@ lexer_convert_literal_to_chars (parser_context_t *context_p, /**< context */
return destination_start_p;
} /* lexer_convert_literal_to_chars */
/**
* Construct an unused literal.
*
* @return a newly allocated literal
*/
lexer_literal_t *
lexer_construct_unused_literal (parser_context_t *context_p) /**< context */
{
lexer_literal_t *literal_p;
if (context_p->literal_count >= PARSER_MAXIMUM_NUMBER_OF_LITERALS)
{
parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED);
}
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;
return literal_p;
} /* lexer_construct_unused_literal */
/**
* Construct a literal object from an identifier.
*/
@@ -2755,34 +2825,32 @@ lexer_construct_function_object (parser_context_t *context_p, /**< context */
lexer_literal_t *literal_p;
uint16_t result_index;
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);
if (context_p->status_flags & PARSER_INSIDE_WITH)
{
extra_status_flags |= PARSER_INSIDE_WITH;
}
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 = lexer_construct_unused_literal (context_p);
result_index = context_p->literal_count;
context_p->literal_count++;
parser_flush_cbc (context_p);
#if ENABLED (JERRY_ESNEXT)
if (!(extra_status_flags & PARSER_IS_ARROW_FUNCTION))
if (JERRY_LIKELY (!(extra_status_flags & PARSER_IS_ARROW_FUNCTION)))
{
compiled_code_p = parser_parse_function (context_p, extra_status_flags);
}
else
else if (JERRY_LIKELY (!(extra_status_flags & PARSER_CLASS_CONSTRUCTOR)))
{
compiled_code_p = parser_parse_arrow_function (context_p, extra_status_flags);
}
else
{
/* Since PARSER_IS_ARROW_FUNCTION and PARSER_CLASS_CONSTRUCTOR bits cannot
* be set at the same time, this bit combination triggers class field parsing. */
compiled_code_p = parser_parse_class_fields (context_p);
}
#else /* !ENABLED (JERRY_ESNEXT) */
compiled_code_p = parser_parse_function (context_p, extra_status_flags);
#endif /* ENABLED (JERRY_ESNEXT) */
@@ -3031,14 +3099,12 @@ lexer_construct_regexp_object (parser_context_t *context_p, /**< context */
literal_p->type = literal_type;
literal_p->prop.length = (prop_length_t) length;
literal_p->status_flags = 0;
context_p->literal_count++;
context_p->token.type = LEXER_LITERAL;
context_p->token.keyword_type = LEXER_EOS;
context_p->token.lit_location.type = LEXER_REGEXP_LITERAL;
context_p->lit_object.literal_p = literal_p;
context_p->lit_object.index = (uint16_t) (context_p->literal_count - 1);
context_p->lit_object.index = context_p->literal_count++;
#else /* !ENABLED (JERRY_BUILTIN_REGEXP) */
JERRY_UNUSED (parse_only);
parser_raise_error (context_p, PARSER_ERR_UNSUPPORTED_REGEXP);
@@ -3057,6 +3123,7 @@ lexer_expect_identifier (parser_context_t *context_p, /**< context */
|| literal_type == LEXER_NEW_IDENT_LITERAL);
lexer_skip_spaces (context_p);
context_p->token.keyword_type = LEXER_EOS;
context_p->token.line = context_p->line;
context_p->token.column = context_p->column;
@@ -3093,7 +3160,6 @@ lexer_expect_identifier (parser_context_t *context_p, /**< context */
/* When parsing default exports for modules, it is not required by functions or classes to have identifiers.
* In this case we use a synthetic name for them. */
context_p->token.type = LEXER_LITERAL;
context_p->token.keyword_type = LEXER_EOS;
context_p->token.lit_location = lexer_default_literal;
lexer_construct_literal_object (context_p, &context_p->token.lit_location, literal_type);
context_p->status_flags &= (uint32_t) ~(PARSER_MODULE_DEFAULT_CLASS_OR_FUNC);
@@ -3128,16 +3194,14 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */
parser_raise_error (context_p, PARSER_ERR_PROPERTY_IDENTIFIER_EXPECTED);
}
#if ENABLED (JERRY_ESNEXT)
int is_class_method = ((ident_opts & LEXER_OBJ_IDENT_CLASS_METHOD)
&& !(ident_opts & LEXER_OBJ_IDENT_ONLY_IDENTIFIERS)
&& (context_p->token.type != LEXER_KEYW_STATIC));
#endif /* ENABLED (JERRY_ESNEXT) */
context_p->token.keyword_type = LEXER_EOS;
context_p->token.line = context_p->line;
context_p->token.column = context_p->column;
bool create_literal_object = false;
JERRY_ASSERT ((ident_opts & LEXER_OBJ_IDENT_CLASS_IDENTIFIER)
|| !(ident_opts & LEXER_OBJ_IDENT_CLASS_NO_STATIC));
if (lexer_parse_identifier (context_p, LEXER_PARSE_NO_OPTS))
{
if (!(ident_opts & (LEXER_OBJ_IDENT_ONLY_IDENTIFIERS | LEXER_OBJ_IDENT_OBJECT_PATTERN)))
@@ -3150,6 +3214,8 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */
&& 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_SEMICOLON
&& context_p->source_p[0] != LIT_CHAR_EQUALS
#endif /* ENABLED (JERRY_ESNEXT) */
&& context_p->source_p[0] != LIT_CHAR_COLON)
{
@@ -3171,18 +3237,19 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */
context_p->token.type = LEXER_KEYW_ASYNC;
return;
}
if (ident_opts & LEXER_OBJ_IDENT_CLASS_NO_STATIC)
{
if (lexer_compare_literal_to_string (context_p, "static", 6))
{
context_p->token.type = LEXER_KEYW_STATIC;
}
return;
}
#endif /* ENABLED (JERRY_ESNEXT) */
}
}
#if ENABLED (JERRY_ESNEXT)
if (is_class_method && lexer_compare_literal_to_string (context_p, "static", 6))
{
context_p->token.type = LEXER_KEYW_STATIC;
return;
}
#endif /* ENABLED (JERRY_ESNEXT) */
create_literal_object = true;
}
else
@@ -3263,7 +3330,11 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */
&& char_p[0] <= LIT_CHAR_9)
{
lexer_parse_number (context_p);
lexer_construct_number_object (context_p, false, false);
if (!(ident_opts & LEXER_OBJ_IDENT_CLASS_IDENTIFIER))
{
lexer_construct_number_object (context_p, false, false);
}
return;
}
break;
@@ -3274,10 +3345,8 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */
if (create_literal_object)
{
#if ENABLED (JERRY_ESNEXT)
if (is_class_method && lexer_compare_literal_to_string (context_p, "constructor", 11))
if (ident_opts & LEXER_OBJ_IDENT_CLASS_IDENTIFIER)
{
context_p->token.type = LEXER_CLASS_CONSTRUCTOR;
context_p->token.flags &= (uint8_t) ~LEXER_NO_SKIP_SPACES;
return;
}
#endif /* ENABLED (JERRY_ESNEXT) */
@@ -3300,6 +3369,7 @@ bool
lexer_scan_identifier (parser_context_t *context_p) /**< context */
{
lexer_skip_spaces (context_p);
context_p->token.keyword_type = LEXER_EOS;
context_p->token.line = context_p->line;
context_p->token.column = context_p->column;
@@ -3309,6 +3379,7 @@ lexer_scan_identifier (parser_context_t *context_p) /**< context */
return true;
}
context_p->token.flags |= LEXER_NO_SKIP_SPACES;
lexer_next_token (context_p);
return false;
} /* lexer_scan_identifier */
+3 -3
View File
@@ -198,7 +198,6 @@ typedef enum
#if ENABLED (JERRY_ESNEXT)
LEXER_ASSIGN_GROUP_EXPR, /**< indetifier for the assignment is located in a group expression */
LEXER_ASSIGN_CONST, /**< a const binding is reassigned */
LEXER_CLASS_CONSTRUCTOR, /**< special value for class constructor method */
LEXER_INVALID_PATTERN, /**< special value for invalid destructuring pattern */
#endif /* ENABLED (JERRY_ESNEXT) */
@@ -276,8 +275,9 @@ 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_METHOD = (1u << 2), /**< expect identifier inside a class body */
LEXER_OBJ_IDENT_OBJECT_PATTERN = (1u << 3), /**< parse "get"/"set" as string literal in object pattern */
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_opts_t;
/**
+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);
}
+28 -6
View File
@@ -69,16 +69,17 @@ typedef enum
PARSER_FUNCTION_HAS_REST_PARAM = (1u << 19), /**< function has rest parameter */
PARSER_CLASS_CONSTRUCTOR = (1u << 20), /**< a class constructor is parsed
* Note: PARSER_ALLOW_SUPER must be present */
/* These three status flags must be in this order. See PARSER_SAVED_FLAGS_OFFSET. */
/* These four status flags must be in this order. See PARSER_SAVED_FLAGS_OFFSET. */
PARSER_ALLOW_SUPER = (1u << 21), /**< allow super property access */
PARSER_ALLOW_SUPER_CALL = (1u << 22), /**< allow super constructor call
* Note: PARSER_CLASS_CONSTRUCTOR must be present */
PARSER_ALLOW_NEW_TARGET = (1u << 23), /**< allow new.target parsing in the current context */
PARSER_IS_METHOD = (1u << 24), /**< method is parsed */
PARSER_INSIDE_CLASS_FIELD = (1u << 23), /**< a class field is being parsed */
PARSER_ALLOW_NEW_TARGET = (1u << 24), /**< allow new.target parsing in the current context */
PARSER_IS_METHOD = (1u << 25), /**< method is parsed */
#endif /* ENABLED (JERRY_ESNEXT) */
#if ENABLED (JERRY_MODULE_SYSTEM)
PARSER_MODULE_DEFAULT_CLASS_OR_FUNC = (1u << 25), /**< parsing a function or class default export */
PARSER_MODULE_STORE_IDENT = (1u << 26), /**< store identifier of the current export statement */
PARSER_MODULE_DEFAULT_CLASS_OR_FUNC = (1u << 26), /**< parsing a function or class default export */
PARSER_MODULE_STORE_IDENT = (1u << 27), /**< store identifier of the current export statement */
#endif /* ENABLED (JERRY_MODULE_SYSTEM) */
PARSER_HAS_LATE_LIT_INIT = (1u << 30), /**< there are identifier or string literals which construction
* is postponed after the local parser data is freed */
@@ -129,6 +130,20 @@ typedef enum
#endif /* ENABLED (JERRY_ESNEXT) */
} parser_check_context_type_t;
#if ENABLED (JERRY_ESNEXT)
/**
* Class field bits.
*/
typedef enum
{
PARSER_CLASS_FIELD_END = (1u << 0), /**< last class field */
PARSER_CLASS_FIELD_NORMAL = (1u << 1), /**< normal (non-computed) class field */
PARSER_CLASS_FIELD_INITIALIZED = (1u << 2), /**< class field is initialized */
} parser_class_field_type_t;
#endif /* ENABLED (JERRY_ESNEXT) */
/**
* Mask for strict mode code
*/
@@ -704,6 +719,10 @@ void parser_set_continues_to_current_position (parser_context_t *context_p, pars
#define parser_emit_cbc_ext_backward_branch(context_p, opcode, offset) \
parser_emit_cbc_backward_branch ((context_p), PARSER_TO_EXT_OPCODE (opcode), (offset))
#if ENABLED (JERRY_ESNEXT)
void parser_reverse_class_fields (parser_context_t *context_p, size_t fields_size);
#endif /* ENABLED (JERRY_ESNEXT) */
/**
* @}
*
@@ -725,6 +744,7 @@ bool lexer_check_arrow (parser_context_t *context_p);
bool lexer_check_arrow_param (parser_context_t *context_p);
bool lexer_check_yield_no_arg (parser_context_t *context_p);
bool lexer_consume_generator (parser_context_t *context_p);
bool lexer_consume_assign (parser_context_t *context_p);
void lexer_update_await_yield (parser_context_t *context_p, uint32_t status_flags);
#endif /* ENABLED (JERRY_ESNEXT) */
void lexer_parse_string (parser_context_t *context_p, lexer_string_options_t opts);
@@ -736,7 +756,7 @@ void lexer_convert_ident_to_cesu8 (uint8_t *destination_p, const uint8_t *source
const uint8_t *lexer_convert_literal_to_chars (parser_context_t *context_p, const lexer_lit_location_t *literal_p,
uint8_t *local_byte_array_p, lexer_string_options_t opts);
void lexer_expect_object_literal_id (parser_context_t *context_p, uint32_t ident_opts);
uint16_t scanner_save_literal (parser_context_t *context_p, uint16_t ident_index);
lexer_literal_t *lexer_construct_unused_literal (parser_context_t *context_p);
void lexer_construct_literal_object (parser_context_t *context_p, const lexer_lit_location_t *lit_location_p,
uint8_t literal_type);
bool lexer_construct_number_object (parser_context_t *context_p, bool is_expr, bool is_negative_number);
@@ -804,6 +824,7 @@ void scanner_get_location (scanner_location_t *location_p, parser_context_t *con
void scanner_set_location (parser_context_t *context_p, scanner_location_t *location_p);
uint16_t scanner_decode_map_to (parser_scope_stack_t *stack_item_p);
#if ENABLED (JERRY_ESNEXT)
uint16_t scanner_save_literal (parser_context_t *context_p, uint16_t ident_index);
bool scanner_literal_is_const_reg (parser_context_t *context_p, uint16_t literal_index);
bool scanner_literal_is_created (parser_context_t *context_p, uint16_t literal_index);
#endif /* ENABLED (JERRY_ESNEXT) */
@@ -859,6 +880,7 @@ void parser_module_add_names_to_node (parser_context_t *context_p,
ecma_compiled_code_t *parser_parse_function (parser_context_t *context_p, uint32_t status_flags);
#if ENABLED (JERRY_ESNEXT)
ecma_compiled_code_t *parser_parse_arrow_function (parser_context_t *context_p, uint32_t status_flags);
ecma_compiled_code_t *parser_parse_class_fields (parser_context_t *context_p);
void parser_set_function_name (parser_context_t *context_p, uint16_t function_literal_index, uint16_t name_index,
uint32_t status_flags);
void parser_compiled_code_set_function_name (parser_context_t *context_p, ecma_compiled_code_t *bytecode_p,
+78 -2
View File
@@ -790,6 +790,78 @@ parser_set_continues_to_current_position (parser_context_t *context_p, /**< cont
}
} /* parser_set_continues_to_current_position */
#if ENABLED (JERRY_ESNEXT)
/**
* Reverse the field list of a class
*/
void
parser_reverse_class_fields (parser_context_t *context_p, /**< context */
size_t fields_size) /**< size of consumed memory */
{
uint8_t *data_p = (uint8_t *) parser_malloc (context_p, fields_size);
uint8_t *data_end_p = data_p + fields_size;
uint8_t *current_p = data_p;
parser_stack_iterator_t iterator;
parser_stack_iterator_init (context_p, &iterator);
do
{
uint8_t class_field_type = parser_stack_iterator_read_uint8 (&iterator);
parser_stack_iterator_skip (&iterator, 1);
if (class_field_type & PARSER_CLASS_FIELD_INITIALIZED)
{
parser_stack_iterator_read (&iterator, current_p, sizeof (scanner_range_t));
parser_stack_iterator_skip (&iterator, sizeof (scanner_range_t));
current_p += sizeof (scanner_range_t);
}
else if (class_field_type & PARSER_CLASS_FIELD_NORMAL)
{
parser_stack_iterator_read (&iterator, current_p, sizeof (scanner_location_t));
parser_stack_iterator_skip (&iterator, sizeof (scanner_location_t));
current_p += sizeof (scanner_location_t);
}
*current_p++ = class_field_type;
}
while (current_p < data_end_p);
parser_stack_iterator_init (context_p, &iterator);
current_p = data_end_p;
context_p->stack_top_uint8 = current_p[-1];
do
{
uint8_t class_field_type = current_p[-1];
if (class_field_type & PARSER_CLASS_FIELD_INITIALIZED)
{
current_p -= sizeof (scanner_range_t) + 1;
parser_stack_iterator_write (&iterator, current_p, sizeof (scanner_range_t) + 1);
parser_stack_iterator_skip (&iterator, sizeof (scanner_range_t) + 1);
}
else if (class_field_type & PARSER_CLASS_FIELD_NORMAL)
{
current_p -= sizeof (scanner_location_t) + 1;
parser_stack_iterator_write (&iterator, current_p, sizeof (scanner_location_t) + 1);
parser_stack_iterator_skip (&iterator, sizeof (scanner_location_t) + 1);
}
else
{
current_p--;
parser_stack_iterator_write (&iterator, current_p, 1);
parser_stack_iterator_skip (&iterator, 1);
}
}
while (current_p > data_p);
parser_free (data_p, fields_size);
} /* parser_reverse_class_fields */
#endif /* ENABLED (JERRY_ESNEXT) */
#if ENABLED (JERRY_ERROR_MESSAGES)
/**
* Returns with the string representation of the error
@@ -1170,9 +1242,9 @@ parser_error_to_string (parser_error_t error) /**< error code */
{
return "Class constructor may not be an accessor.";
}
case PARSER_ERR_CLASS_CONSTRUCTOR_AS_GENERATOR:
case PARSER_ERR_INVALID_CLASS_CONSTRUCTOR:
{
return "Class constructor may not be a generator.";
return "Class constructor may not be a generator or async function.";
}
case PARSER_ERR_CLASS_STATIC_PROTOTYPE:
{
@@ -1182,6 +1254,10 @@ parser_error_to_string (parser_error_t error) /**< error code */
{
return "Super is not allowed to be used here.";
}
case PARSER_ERR_ARGUMENTS_IN_CLASS_FIELD:
{
return "In class field declarations 'arguments' is not allowed.";
}
case PARSER_ERR_RIGHT_BRACE_EXPECTED:
{
return "Expected '}' token.";
+153
View File
@@ -2578,6 +2578,13 @@ parser_parse_function (parser_context_t *context_p, /**< context */
parser_raise_error (context_p, PARSER_ERR_ONE_ARGUMENT_EXPECTED);
}
#if ENABLED (JERRY_ESNEXT)
if ((context_p->status_flags & (PARSER_CLASS_CONSTRUCTOR | PARSER_ALLOW_SUPER_CALL)) == PARSER_CLASS_CONSTRUCTOR)
{
parser_emit_cbc_ext (context_p, CBC_EXT_RUN_CLASS_FIELD_INIT);
}
#endif /* ENABLED (JERRY_ESNEXT) */
#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE)
if (context_p->is_show_opcodes
&& (context_p->status_flags & PARSER_HAS_NON_STRICT_ARG))
@@ -2712,6 +2719,152 @@ parser_parse_arrow_function (parser_context_t *context_p, /**< context */
return compiled_code_p;
} /* parser_parse_arrow_function */
/**
* Parse class fields
*
* @return compiled code
*/
ecma_compiled_code_t *
parser_parse_class_fields (parser_context_t *context_p) /**< context */
{
parser_saved_context_t saved_context;
ecma_compiled_code_t *compiled_code_p;
JERRY_ASSERT (context_p->token.type == LEXER_RIGHT_BRACE);
parser_save_context (context_p, &saved_context);
context_p->status_flags |= (PARSER_IS_FUNCTION
| PARSER_ALLOW_SUPER
| PARSER_INSIDE_CLASS_FIELD
| PARSER_ALLOW_NEW_TARGET);
#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE)
if (context_p->is_show_opcodes)
{
JERRY_DEBUG_MSG ("\n--- Class fields parsing start ---\n\n");
}
#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */
#if ENABLED (JERRY_DEBUGGER)
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
{
jerry_debugger_send_parse_function (context_p->token.line, context_p->token.column);
}
#endif /* ENABLED (JERRY_DEBUGGER) */
const uint8_t *source_end_p = context_p->source_end_p;
bool first_computed_class_field = true;
scanner_location_t end_location;
scanner_get_location (&end_location, context_p);
do
{
uint8_t class_field_type = context_p->stack_top_uint8;
parser_stack_pop_uint8 (context_p);
scanner_range_t range;
if (class_field_type & PARSER_CLASS_FIELD_INITIALIZED)
{
parser_stack_pop (context_p, &range, sizeof (scanner_range_t));
}
else if (class_field_type & PARSER_CLASS_FIELD_NORMAL)
{
parser_stack_pop (context_p, &range.start_location, sizeof (scanner_location_t));
}
uint16_t literal_index = 0;
if (class_field_type & PARSER_CLASS_FIELD_NORMAL)
{
scanner_set_location (context_p, &range.start_location);
context_p->source_end_p = source_end_p;
scanner_seek (context_p);
lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_ONLY_IDENTIFIERS);
literal_index = context_p->lit_object.index;
if (class_field_type & PARSER_CLASS_FIELD_INITIALIZED)
{
lexer_next_token (context_p);
JERRY_ASSERT (context_p->token.type == LEXER_ASSIGN);
}
}
else if (first_computed_class_field)
{
parser_emit_cbc (context_p, CBC_PUSH_NUMBER_0);
first_computed_class_field = false;
}
if (class_field_type & PARSER_CLASS_FIELD_INITIALIZED)
{
if (!(class_field_type & PARSER_CLASS_FIELD_NORMAL))
{
scanner_set_location (context_p, &range.start_location);
scanner_seek (context_p);
}
context_p->source_end_p = range.source_end_p;
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);
}
}
else
{
parser_emit_cbc (context_p, CBC_PUSH_UNDEFINED);
}
if (class_field_type & PARSER_CLASS_FIELD_NORMAL)
{
parser_emit_cbc_literal (context_p, CBC_ASSIGN_PROP_THIS_LITERAL, literal_index);
}
else
{
parser_flush_cbc (context_p);
/* The next opcode pushes two more temporary values onto the stack */
if (context_p->stack_depth + 1 > context_p->stack_limit)
{
context_p->stack_limit = (uint16_t) (context_p->stack_depth + 1);
if (context_p->stack_limit > PARSER_MAXIMUM_STACK_LIMIT)
{
parser_raise_error (context_p, PARSER_ERR_STACK_LIMIT_REACHED);
}
}
parser_emit_cbc_ext (context_p, CBC_EXT_SET_NEXT_COMPUTED_FIELD);
}
}
while (context_p->stack_top_uint8 != PARSER_CLASS_FIELD_END);
if (!first_computed_class_field)
{
parser_emit_cbc (context_p, CBC_POP);
}
parser_stack_pop_uint8 (context_p);
parser_flush_cbc (context_p);
context_p->source_end_p = source_end_p;
scanner_set_location (context_p, &end_location);
compiled_code_p = parser_post_processing (context_p);
#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE)
if (context_p->is_show_opcodes)
{
JERRY_DEBUG_MSG ("\n--- Class fields parsing end ---\n\n");
}
#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */
parser_restore_context (context_p, &saved_context);
return compiled_code_p;
} /* parser_parse_class_fields */
/**
* Check whether the last emitted cbc opcode was an anonymous function declaration
*
+2 -1
View File
@@ -142,9 +142,10 @@ typedef enum
PARSER_ERR_MULTIPLE_CLASS_CONSTRUCTORS, /**< multiple class constructor */
PARSER_ERR_CLASS_CONSTRUCTOR_AS_ACCESSOR, /**< class constructor cannot be an accessor */
PARSER_ERR_CLASS_CONSTRUCTOR_AS_GENERATOR, /**< class constructor cannot be a generator */
PARSER_ERR_INVALID_CLASS_CONSTRUCTOR, /**< class constructor cannot be a generator or async function */
PARSER_ERR_CLASS_STATIC_PROTOTYPE, /**< static method name 'prototype' is not allowed */
PARSER_ERR_UNEXPECTED_SUPER_KEYWORD, /**< unexpected super keyword */
PARSER_ERR_ARGUMENTS_IN_CLASS_FIELD, /**< arguments is not allowed in class fields */
PARSER_ERR_RIGHT_BRACE_EXPECTED, /**< right brace expected */
PARSER_ERR_OF_EXPECTED, /**< of keyword expected */
+5 -2
View File
@@ -45,7 +45,8 @@ typedef enum
SCAN_MODE_CONTINUE_FUNCTION_ARGUMENTS, /**< continue scanning function arguments */
SCAN_MODE_BINDING, /**< array or object binding */
SCAN_MODE_CLASS_DECLARATION, /**< scanning class declaration */
SCAN_MODE_CLASS_METHOD, /**< scanning class method */
SCAN_MODE_CLASS_BODY, /**< scanning class body */
SCAN_MODE_CLASS_BODY_NO_SCAN, /**< scanning class body without calling lexer_scan_identifier */
#endif /* ENABLED (JERRY_ESNEXT) */
} scan_modes_t;
@@ -59,7 +60,7 @@ typedef enum
SCAN_STACK_BLOCK_STATEMENT, /**< block statement group */
SCAN_STACK_FUNCTION_STATEMENT, /**< function statement */
SCAN_STACK_FUNCTION_EXPRESSION, /**< function expression */
SCAN_STACK_FUNCTION_PROPERTY, /**< function expression in an object literal or class */
SCAN_STACK_FUNCTION_PROPERTY, /**< function expression in an object literal */
#if ENABLED (JERRY_ESNEXT)
SCAN_STACK_FUNCTION_ARROW, /**< arrow function expression */
#endif /* ENABLED (JERRY_ESNEXT) */
@@ -113,6 +114,7 @@ typedef enum
SCAN_STACK_CLASS_STATEMENT, /**< class statement */
SCAN_STACK_CLASS_EXPRESSION, /**< class expression */
SCAN_STACK_CLASS_EXTENDS, /**< class extends expression */
SCAN_STACK_CLASS_FIELD_INITIALIZER, /**< class field initializer */
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 */
@@ -387,6 +389,7 @@ void scanner_detect_eval_call (parser_context_t *context_p, scanner_context_t *s
#if ENABLED (JERRY_ESNEXT)
void scanner_push_class_declaration (parser_context_t *context_p, scanner_context_t *scanner_context_p,
uint8_t stack_mode);
void scanner_push_class_field_initializer (parser_context_t *context_p, scanner_context_t *scanner_context_p);
void scanner_push_destructuring_pattern (parser_context_t *context_p, scanner_context_t *scanner_context_p,
uint8_t binding_type, bool is_nested);
void scanner_pop_binding_list (scanner_context_t *scanner_context_p);
+16
View File
@@ -1494,6 +1494,21 @@ scanner_push_class_declaration (parser_context_t *context_p, /**< context */
lexer_next_token (context_p);
} /* scanner_push_class_declaration */
/**
* Push the start of a class field initializer.
*/
void
scanner_push_class_field_initializer (parser_context_t *context_p, /**< context */
scanner_context_t *scanner_context_p) /* scanner context */
{
scanner_source_start_t source_start;
source_start.source_p = context_p->source_p;
parser_stack_push (context_p, &source_start, sizeof (scanner_source_start_t));
parser_stack_push_uint8 (context_p, SCAN_STACK_CLASS_FIELD_INITIALIZER);
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
} /* scanner_push_class_field_initializer */
/**
* Push the values required for destructuring assignment or binding parsing.
*/
@@ -1658,6 +1673,7 @@ scanner_cleanup (parser_context_t *context_p) /**< context */
case SCANNER_TYPE_CASE:
#if ENABLED (JERRY_ESNEXT)
case SCANNER_TYPE_INITIALIZER:
case SCANNER_TYPE_CLASS_FIELD_INITIALIZER_END:
#endif /* ENABLED (JERRY_ESNEXT) */
{
size = sizeof (scanner_location_info_t);
+192 -27
View File
@@ -430,6 +430,11 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context *
{
break;
}
case SCAN_STACK_CLASS_FIELD_INITIALIZER:
{
scanner_raise_error (context_p);
break;
}
case SCAN_STACK_FUNCTION_PARAMETERS:
{
scanner_context_p->mode = SCAN_MODE_CONTINUE_FUNCTION_ARGUMENTS;
@@ -962,7 +967,7 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context *
break;
}
lexer_next_token (context_p);
lexer_scan_identifier (context_p);
parser_stack_pop_uint8 (context_p);
stack_top = (scan_stack_modes_t) context_p->stack_top_uint8;
@@ -970,11 +975,33 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context *
if (stack_top == SCAN_STACK_FUNCTION_PROPERTY)
{
scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_FUNCTION);
scanner_context_p->mode = SCAN_MODE_FUNCTION_ARGUMENTS;
return SCAN_KEEP_TOKEN;
}
if (stack_top == SCAN_STACK_EXPLICIT_CLASS_CONSTRUCTOR
|| stack_top == SCAN_STACK_IMPLICIT_CLASS_CONSTRUCTOR)
{
if (context_p->token.type == LEXER_LEFT_PAREN)
{
scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_FUNCTION);
parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PROPERTY);
scanner_context_p->mode = SCAN_MODE_FUNCTION_ARGUMENTS;
return SCAN_KEEP_TOKEN;
}
if (context_p->token.type == LEXER_ASSIGN)
{
scanner_push_class_field_initializer (context_p, scanner_context_p);
return SCAN_NEXT_TOKEN;
}
scanner_context_p->mode = (context_p->token.type != LEXER_SEMICOLON ? SCAN_MODE_CLASS_BODY_NO_SCAN
: SCAN_MODE_CLASS_BODY);
return SCAN_KEEP_TOKEN;
}
JERRY_ASSERT (stack_top == SCAN_STACK_OBJECT_LITERAL
|| stack_top == SCAN_STACK_OBJECT_LITERAL_WITH_SUPER);
@@ -1073,11 +1100,87 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context *
break;
}
scanner_context_p->mode = SCAN_MODE_CLASS_METHOD;
scanner_context_p->mode = SCAN_MODE_CLASS_BODY;
parser_stack_pop_uint8 (context_p);
return SCAN_KEEP_TOKEN;
}
case SCAN_STACK_CLASS_FIELD_INITIALIZER:
{
scanner_source_start_t source_start;
parser_stack_pop_uint8 (context_p);
parser_stack_pop (context_p, &source_start, sizeof (scanner_source_start_t));
const uint8_t *source_p = NULL;
scanner_context_p->mode = SCAN_MODE_CLASS_BODY_NO_SCAN;
switch (type)
{
case LEXER_SEMICOLON:
{
source_p = context_p->source_p - 1;
scanner_context_p->mode = SCAN_MODE_CLASS_BODY;
break;
}
case LEXER_RIGHT_BRACE:
{
source_p = context_p->source_p - 1;
break;
}
default:
{
if (!(context_p->token.flags & LEXER_WAS_NEWLINE))
{
break;
}
if (type == LEXER_LEFT_SQUARE)
{
source_p = context_p->source_p - 1;
break;
}
if (type == LEXER_LITERAL)
{
if (context_p->token.lit_location.type == LEXER_IDENT_LITERAL
|| context_p->token.lit_location.type == LEXER_NUMBER_LITERAL)
{
source_p = context_p->token.lit_location.char_p;
}
else if (context_p->token.lit_location.type == LEXER_STRING_LITERAL)
{
source_p = context_p->token.lit_location.char_p - 1;
}
break;
}
if (type == context_p->token.keyword_type && type != LEXER_EOS)
{
/* Convert keyword to literal. */
source_p = context_p->token.lit_location.char_p;
context_p->token.type = LEXER_LITERAL;
}
break;
}
}
if (JERRY_UNLIKELY (source_p == NULL))
{
scanner_raise_error (context_p);
}
scanner_location_info_t *location_info_p;
location_info_p = (scanner_location_info_t *) scanner_insert_info (context_p,
source_start.source_p,
sizeof (scanner_location_info_t));
location_info_p->info.type = SCANNER_TYPE_CLASS_FIELD_INITIALIZER_END;
location_info_p->location.source_p = source_p;
location_info_p->location.line = context_p->token.line;
location_info_p->location.column = context_p->token.column;
return SCAN_KEEP_TOKEN;
}
case SCAN_STACK_FUNCTION_PARAMETERS:
{
parser_stack_pop_uint8 (context_p);
@@ -2027,7 +2130,7 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */
if (context_p->stack_top_uint8 == SCAN_STACK_EXPLICIT_CLASS_CONSTRUCTOR
|| context_p->stack_top_uint8 == SCAN_STACK_IMPLICIT_CLASS_CONSTRUCTOR)
{
scanner_context_p->mode = SCAN_MODE_CLASS_METHOD;
scanner_context_p->mode = SCAN_MODE_CLASS_BODY;
return SCAN_KEEP_TOKEN;
}
@@ -2337,6 +2440,9 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
/* This assignment must be here because of Apple compilers. */
context_p->u.scanner_context_p = &scanner_context;
#if ENABLED (JERRY_ESNEXT)
context_p->global_status_flags |= ECMA_PARSE_INTERNAL_PRE_SCANNING;
#endif /* ENABLED (JERRY_ESNEXT) */
parser_stack_init (context_p);
@@ -2437,18 +2543,20 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
scanner_raise_error (context_p);
}
scanner_context.mode = SCAN_MODE_CLASS_METHOD;
scanner_context.mode = SCAN_MODE_CLASS_BODY;
/* FALLTHRU */
}
case SCAN_MODE_CLASS_METHOD:
case SCAN_MODE_CLASS_BODY:
{
lexer_skip_empty_statements (context_p);
lexer_scan_identifier (context_p);
/* FALLTHRU */
}
case SCAN_MODE_CLASS_BODY_NO_SCAN:
{
JERRY_ASSERT (stack_top == SCAN_STACK_IMPLICIT_CLASS_CONSTRUCTOR
|| stack_top == SCAN_STACK_EXPLICIT_CLASS_CONSTRUCTOR);
lexer_skip_empty_statements (context_p);
lexer_scan_identifier (context_p);
if (context_p->token.type == LEXER_RIGHT_BRACE)
{
scanner_source_start_t source_start;
@@ -2476,6 +2584,8 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
break;
}
bool identifier_found = false;
if (context_p->token.type == LEXER_LITERAL
&& LEXER_IS_IDENT_OR_STRING (context_p->token.lit_location.type)
&& lexer_compare_literal_to_string (context_p, "constructor", 11))
@@ -2491,13 +2601,12 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
parser_stack_push_uint8 (context_p, SCAN_STACK_EXPLICIT_CLASS_CONSTRUCTOR);
}
}
if (lexer_token_is_identifier (context_p, "static", 6))
else if (lexer_token_is_identifier (context_p, "static", 6))
{
lexer_scan_identifier (context_p);
identifier_found = true;
}
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;
@@ -2506,9 +2615,11 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
|| lexer_token_is_identifier (context_p, "set", 3))
{
lexer_scan_identifier (context_p);
identifier_found = true;
if (context_p->token.type == LEXER_LEFT_PAREN)
{
parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PROPERTY);
scanner_push_literal_pool (context_p, &scanner_context, SCANNER_LITERAL_POOL_FUNCTION);
continue;
}
@@ -2516,19 +2627,24 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
else if (lexer_token_is_identifier (context_p, "async", 5))
{
lexer_scan_identifier (context_p);
identifier_found = true;
if (context_p->token.type == LEXER_LEFT_PAREN)
if (!(context_p->token.flags & LEXER_WAS_NEWLINE))
{
scanner_push_literal_pool (context_p, &scanner_context, SCANNER_LITERAL_POOL_FUNCTION);
continue;
}
if (context_p->token.type == LEXER_LEFT_PAREN)
{
parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PROPERTY);
scanner_push_literal_pool (context_p, &scanner_context, SCANNER_LITERAL_POOL_FUNCTION);
continue;
}
literal_pool_flags |= SCANNER_LITERAL_POOL_ASYNC;
literal_pool_flags |= SCANNER_LITERAL_POOL_ASYNC;
if (context_p->token.type == LEXER_MULTIPLY)
{
lexer_scan_identifier (context_p);
literal_pool_flags |= SCANNER_LITERAL_POOL_GENERATOR;
if (context_p->token.type == LEXER_MULTIPLY)
{
lexer_scan_identifier (context_p);
literal_pool_flags |= SCANNER_LITERAL_POOL_GENERATOR;
}
}
}
else if (context_p->token.type == LEXER_MULTIPLY)
@@ -2539,23 +2655,63 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
if (context_p->token.type == LEXER_LEFT_SQUARE)
{
if (literal_pool_flags != SCANNER_LITERAL_POOL_FUNCTION)
{
parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PROPERTY);
}
parser_stack_push_uint8 (context_p, SCANNER_FROM_LITERAL_POOL_TO_COMPUTED (literal_pool_flags));
scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION;
break;
}
if (context_p->token.type != LEXER_LITERAL)
if (context_p->token.type == LEXER_LITERAL)
{
lexer_scan_identifier (context_p);
identifier_found = true;
}
if (!identifier_found)
{
scanner_raise_error (context_p);
}
if (literal_pool_flags & SCANNER_LITERAL_POOL_GENERATOR)
if (context_p->token.type == LEXER_LEFT_PAREN)
{
context_p->status_flags |= PARSER_IS_GENERATOR_FUNCTION;
if (literal_pool_flags & SCANNER_LITERAL_POOL_GENERATOR)
{
context_p->status_flags |= PARSER_IS_GENERATOR_FUNCTION;
}
parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PROPERTY);
scanner_push_literal_pool (context_p, &scanner_context, literal_pool_flags);
continue;
}
scanner_push_literal_pool (context_p, &scanner_context, literal_pool_flags);
lexer_next_token (context_p);
if (literal_pool_flags != SCANNER_LITERAL_POOL_FUNCTION)
{
scanner_raise_error (context_p);
}
if (context_p->token.type == LEXER_ASSIGN)
{
scanner_push_class_field_initializer (context_p, &scanner_context);
break;
}
if (context_p->token.type == LEXER_SEMICOLON)
{
scanner_context.mode = SCAN_MODE_CLASS_BODY;
continue;
}
if (context_p->token.type != LEXER_RIGHT_BRACE
&& !(context_p->token.flags & LEXER_WAS_NEWLINE))
{
scanner_raise_error (context_p);
}
scanner_context.mode = SCAN_MODE_CLASS_BODY_NO_SCAN;
continue;
}
#endif /* ENABLED (JERRY_ESNEXT) */
@@ -3299,6 +3455,9 @@ scan_completed:
PARSER_TRY_END
context_p->status_flags = scanner_context.context_status_flags;
#if ENABLED (JERRY_ESNEXT)
context_p->global_status_flags &= (uint32_t) ~ECMA_PARSE_INTERNAL_PRE_SCANNING;
#endif /* ENABLED (JERRY_ESNEXT) */
scanner_reverse_info_list (context_p);
#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE)
@@ -3549,6 +3708,12 @@ scan_completed:
print_location = false;
break;
}
case SCANNER_TYPE_CLASS_FIELD_INITIALIZER_END:
{
name_p = "SCANNER_TYPE_CLASS_FIELD_INITIALIZER_END";
print_location = true;
break;
}
case SCANNER_TYPE_LET_EXPRESSION:
{
JERRY_DEBUG_MSG (" LET_EXPRESSION: source:%d\n",
+10
View File
@@ -48,6 +48,7 @@ typedef enum
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_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 */
@@ -65,6 +66,15 @@ typedef struct
parser_line_counter_t column; /**< token start column */
} scanner_location_t;
/**
* Source code range with its start and end position.
*/
typedef struct
{
const uint8_t *source_end_p; /**< end position */
scanner_location_t start_location; /**< start location */
} scanner_range_t;
/**
* Scanner info blocks which provides information for the parser.
*/